きなこもち.net

.NET Framework × UiPath,Orchestrator × Azure × AWS × Angularなどの忘備録

C# × ErrorProne.NET × Roslynベースのコード解析ツールを使ってみた

この記事の目的

この記事では、
Roslynベースのコード解析ツール「ErrorProne.NET」を使ってみること
を目的としています。

本題

★ErrorProne.NETとは?

以下のGitHubで公開されているコード解析ツールです。
ツール・・・?
アナライザー・・・?
github.com


Roslynをベースに作られており、間違ったコードを実装すると警告で教えてくれます。
Googleのerror-proneと似ていますが、このツールでは、C#を対象としています。

解析してくれるコード誤りは、以下の項目です。
※各警告が出るサンプルコードはGitHubのReadMe.mdに詳しく乗っています。


ERP001:戻り値を利用していない警告
Pureアトリビュートで修飾されたインスタンスメソッドや、Object、IEnumerableなどのように、不変型*1として知られている型の戻り値を受け取っていない場合に警告します。


ERP002:生成されたExceptionが利用されていない警告
Exceptionクラス(派生クラス含む)のインスタンスを生成するだけして、throwも何もしていないコードに対して警告を出力します。


ERP003:生成されたインスタンスが利用されていない警告
生成したインスタンスが不変型、コレクション型、構造体のデフォルトコンストラクタ以外であり、副作用*2があることが知られている場合に警告します。


ERP011:フォーマット文字列に引数の数より多くのプレースホルダが指定されているエラー
ERP012:フォーマット文字列のプレースホルダに対し、過剰な引数が指定されている警告
ERP013:不正なフォーマット文字列が指定されている
言葉での説明がうまくできないので、サンプルコードを作ってみました。

    class Program
    {
        static void Main(string[] args)
        {
            var args01 = " ";
            var target = string.Format("{0},{1}", args01);// ERP011 Argument(s) 1 was not provided.
            target = string.Format("{0}", args01, args01);// ERP012 Argument'args01' wa not userd in the format string.
    target = String.Format("{}", args01);//ERP013 Formatargument is not a valid format string.
        }
    }

string.Formatを行う時の警告です。
実行してからでないと気が付かないこともありましたが、これを使えば一発で分かります!


ERP014:正規表現のパターンが間違っているエラー
不適切な正規表現を定義しているときにエラーとして警告してくれます。
このシナリオもstring.Formatの警告/エラーと同じように、実行してから気が付くことがあると思います。
実行する前に気づけて、修正ができるのが素敵です。


ERP021:誤った例外の伝播の方式で実装している場合の警告
Chatch句の中で、Exceptionをnewするような実装に対する警告です。
C#のアプリケーションを開発し始めのことにやりがちな実装パターンですよね。
実装してしまうと、諸先輩方のレビューを受けたときにドヤ顔でいろいろ言われますw
でも、このアナライザーからレビュー前に警告してもらえるので、すぐに気が付けます。


ERP022:Catch句で適切なExceptionを指定することを検討させるための警告
Catch句で「とりあえずExceptionを補足しておけばいいやろ」と考えて実装することへの警告です。
Exceptionの種類に応じてやるべき処理がある場合は、適切なExceptionの派生クラスを補足するように実装してくださいと警告してくれます。


ERP023:Chatch句でExceptionを指定して例外を補足したとき、
そのCatch句内でExtension.Messageプロパティからのみメッセージを取得していた場合の警告

例外を発生させる場所によっては、元となる例外を別の例外でラップしてくることがあります。
そんな時、ExceptionクラスのMessageプロパティから例外メッセージを取得すると例外の原因が特定できないことがあります。
そういうシナリオがないか検討する機会を与えてくれる警告です。
※自分は、過去のトラウマからGetBaseExceptionメソッドで一番元のエラーを取得するようにしています。



ERP031:Switch文でEnumを指定したとき、Enumで定義されたすべての値を使っていない警告
Switch文のdefault指定したステートメントで、InvalidOperationExceptionをスローする実装をするシナリオでの警告です。
InvalidOperationExceptionをスローするときは、名前の通り無効な操作が行われたことを示します。
その時、Switch文のほかの分岐で、条件として指定されているEnumの値がすべて利用されているかを検証します。
Enumで定義した以外の値が来たときに無効な操作として判定するという実装をしたつもりが、一部のEnumの値の場合だけ実装が漏れていたということに気が付くことができます。

★ErrorProne.NETの導入方法

Nugetで公開されています。
今回もNugetパッケージの管理からインストールしていこうと思います。
Nugetパッケージの管理画面で検索、インストールボタンを押下します(´・ω・`)

f:id:kinakomotitti:20180425003505p:plain

OKを押下します(´・ω・`)

f:id:kinakomotitti:20180425003521p:plain

とても簡単です!

インストールが完了すると、以下のように、「アナライザー」が追加されます。
※インストールした先のプロジェクトは「コンソールアプリ」です。
f:id:kinakomotitti:20180425003537p:plain
ERP001~ERP031の定義の存在が確認できます。


★実際に使ってみたところ

とりあえずERP023の警告を出してみたところです。
f:id:kinakomotitti:20180425003549p:plain

図のように、エラー一覧に警告として表示され、対象のコードは緑波線が引かれます。

ERP013のエラーを出してみたところは以下のようになります。
f:id:kinakomotitti:20180425004956p:plain

★ErrorProne.NETのこれから

今後のロードマップとしてすでに以下のものが予定されていました。
GitHubにも書かれていますが、ここにメモしておきます(´▽`)

  • Add Immutable attribute that will enforce type immutability
  • Add well known attribute like NoExceptionSwallowing that will enforce some rules related to exception handling
  • Add NoAdditionalHeapAllocations attribute that will warn on uncesseary boxing operations on different levels (method, class, assembly)
  • Warn on using ToString on collections
  • Warn on using Equals, GetHashCode on collections
  • Add a Record attribute that will enforce that all class/struct fields are used in ToString/GetHashCode and ToStringmethods
  • Make pure-method rule extensibile (external annotations? use attributes from Code Contracts repo?)

まとめ

  • Catch句でExtensionを指定する。
  • ExtensionのMessageを直接参照する。
  • 値を返すメソッドやコンストラクタを呼び出して変数に格納しない。

といった、C#アプリ開発を始めたころに教わったアンチパターン実装を警告してくれるところが便利だと感じました。
また、実際に警告の内容や解説を見ることで、”不変型(immutable)”や”副作用(side-effect)”などの(知らなかった)知識に触れることができて新鮮でしたw
引き続き動向に注目していこうと思います!