こんにちは、サイオステクノロジーの佐藤 陽です。
今回はVisualStudioの、コードアナライザー機能をより使いこなすための方法をご紹介します。
はじめに
前回のブログで、CodeAnalyzerを導入し、コード品質を向上する方法を紹介しました。
ただデフォルト設定だけだと実際のプロジェクト方針に沿っていない場合もありますよね。
そこで、今回はVisualStudioAnalyzerのカスタマイズ方法をご紹介します。
ポイントは大きく分けて2点です。
- 警告カテゴリ別に検出レベルを変更する
- 警告を抑制する
それでは見ていきましょう!
検出レベルのカスタマイズ
Code Analyzerで検出されるWarningにはカテゴリが存在しています。
前回のブログでも取り上げたCA1309は、Globalizationのカテゴリです。
このカテゴリ一覧はMSのドキュメントにも一覧が存在し、それぞれのカテゴリに対する説明が記述されています。
参考:ルール カテゴリ
これに基づいて
- セキュリティの規則は少し厳しめに見ておきたいなぁ
- 名前付け規則や、スタイルの規則はまぁ最低限でいいか
といった方針がある場合に、カテゴリごとに検出レベルを変更することができます。
例えば、今回
基本的にはRecommendedのレベルで検出しておきたいけど、セキュリティの規則とパフォーマンスのルールは全て検出したい!
といったチームの方針になったとします。
この場合は、以下のように設定することで実現できます。
<AnalysisLevel>6.0-recommended</AnalysisLevel>
<AnalysisLevelPerformance>6.0-All</AnalysisLevelPerformance>
<AnalysisLevelSecurity>6.0-All</AnalysisLevelSecurity>
警告の抑制
カテゴリごとの検出レベルを変更することで、プロジェクトの方針に沿った設定が行えました。
ただ、これだけではまだ足りません。
基本的にはRecommendedのレベルで検出しておきたいけど、この関数においてだけは検出しないようにしたい!
といった要求もあるかと思います。
理由は様々だと思いますが、例えば
- BindされるだけのModelクラスだけは警告を抑制する
- 今回の実装には影響ない部分なので警告を抑制する
といったものでしょうか?
こういった場合、コード単位、関数単位など、様々なスコープで警告を抑制することができます。
※決してむやみやたらに抑制するのはおすすめできないので、しっかりとチームで合意をとった上で行いましょう。
また、以下に示す方法は一例です。
他にも様々な方法があるので、ぜひ調べてみてください。
準備
では検証用にプロジェクトを準備します。
前回のプロジェクト同様、Azure Functionsのプロジェクトを新規作成し
Analyzerの設定を以下のように設定します。
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<RootNamespace>Function</RootNamespace>
<AnalysisLevel>6.0-recommended</AnalysisLevel>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
また、以下のような関数を作っておきます。
private static bool Equal(string a, string b)
{
return a.Equals(b);
}
warning CA1309: 序数の文字列比較を使用してください
のWarningが発生していたら準備OKです!
コード単位での抑制
プラグマのプリプロセッサを利用して、コード単位で警告を抑制することができます。
細かい単位で抑制したい場合には、この方法がおすすめです。
ただ、あまりに頻発するようであればコードの可読性がガクっと落ちますね。
private static bool Equal(string a, string b)
{
#pragma warning disable CA1309 // 序数の文字列比較を使用してください
return a.Equals(b);
#pragma warning restore CA1309 // 序数の文字列比較を使用してください
}
関数単位での抑制
関数レベルで抑制する場合は、SuppressMessageAttributeを利用します。
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1309:序数の文字列比較を使用してください", Justification = "<保留中>")]
private static bool Equal(string a, string b)
{
return a.Equals(b);
}
フォルダ単位での抑制
フォルダ単位での抑制は、EditConfigファイル(.editorconfig)を利用します。
この.editorconfigの追加方法はいろいろとありますが
1.プロジェクト右クリック→追加→新しい項目から.editorconfigファイル(新規)を追加
2.警告文からSuggestion経由でファイル追加
です。
2.の方が自動で追加してくれて楽ですが、
SolutionItemとして追加されたりして、フォルダ構成が複雑になるため、今回は1.の方法を採用します。
.editorconfigファイル(既定)のテンプレートでファイルを作成し、以下の項目を追加します。
(VisualStudioでファイル開くとGUIで表示されてしまうので、別途テキストエディタなどで編集してください。)
# cs file
[*.cs]
dotnet_diagnostic.CA1309.severity = none
この.editorconfigファイルが置かれているディレクトリおよび、その以下のサブディレクトリに対して反映されます。
namespace単位での抑制
namespace単位での抑制は、AssemblyInfo.csファイルを利用します。
こちらもプロジェクト右クリック→追加→新しい項目からAssemblyInfo.csファイルを新規追加します。
作成したファイルに以下のように記述します
[assembly: SuppressMessage(
"Globalization", "CA1309:序数の文字列比較を使用してください", Justification = "<保留中>", Scope = "namespaceanddescendants", Target = "~N:CodeAnalyzerTest")]
これで、CodeAnalyzerTestのnamespaceおよび、そのサブnamespaceに対して影響が反映されます。
namespace先頭の「~」に関しては何故ついてるか不明なのですが、VSのSuggestionで自動でついてきたのでそのままにしています。
(Microsoft様に従っておくのが安パイですね。)
あと、AssemblyInfoファイルの設定時にもう一点注意する点があります。
最近の.NETの環境ではAssemblyInfoがビルド時に自動生成されます。
そのため、手動でAssemblyInfo.csを追加した場合はビルド時に競合してしまいます。
そのため自動生成を抑制しておきましょう。
プロジェクト単位での抑制
最後にプロジェクト単位での抑制です。
こちらはグローバル AnalyzerConfigファイルを活用します。
こちらはプロジェクトからテンプレートで新規追加できなかったようなので、直接.globalconfigファイルを作成します。
そして、ドキュメントに従って以下のように記述します。
# Top level entry required to mark this as a global AnalyzerConfig file
is_global = true
# NOTE: No section headers for configuration entries
#### Diagnostic configuration ####
# CA1309: 序数の文字列比較を使用してください
dotnet_diagnostic.CA1309.severity = none
これで警告が抑制できてますね。
また、このGlobal Analyzer ConfigとEditor Configは併用できるのですが、競合する場合があります。
競合した場合の振る舞いに関してはドキュメントにまとまっているので参考にしてみてください。
参考:優先順位
おわりに
今回は、Visual StudioのCode Analyzerをより使いこなすために
- 警告カテゴリ別に検出レベルを変更する
- 警告を抑制する
について解説しました。
特に警告の抑制方法はスコープ毎に設定方法が異なるので、覚えておくと便利ですね。
基本的にスコープを狭める方に寄せた方がいいかとは思いますが、可読性とのトレードオフもあるかと思うので
そのあたりはチーム内でしっかり話し合って決めていくといいかと思います。
是非、Visual StudioのCode Analyzerを活用して、より良いコードを書いていきましょう!
余談
Code AnalyzerをAzure Pipelinesに組み込むことも出来そうです。
CI/CD好きとしては、こちらも気になるところなので、機会があれば試して紹介したいと思います。
ではまた!