.NET Compiler Platform (Roslyn) が簡単に利用できるようになり、 Analyzer などでよく見かけるようになりました。記事やブログのポストを覗いてみると、 Roslyn 関係の投稿は大抵 SyntaxTree を解説したもののような気がします。
この記事では、より詳しく分析できる Semantic Model というものについて紹介します。
Semantic Model について
Semantic Model は意味論モデルと訳されます。 Syntax Tree (構文木)がソースコードの構造のみから作られるのに対し、 Semantic Model は使用するライブラリの情報を含んで作られます。
構文の形のみによって判別できるものであれば Syntax Tree で十分ですが、メソッドの使い方のチェック(引数等)や複雑なコードに対しては、より詳しくできる方法が必要となります。
Semantic Model を使うことによる欠点もありますが、下手に Syntax Tree だけで組むよりは良いはずです。
使うための準備
まず、通常のプログラムで使う場合は以下のように書きます。
14 | var code = @"" |
0 | "";/* 解析対象のプログラムコード */ |
44 | var tree = CSharpSyntaxTree.ParseText(code); |
この場合、 Syntax Tree を生成し、コンパイル、 Semantic Model の生成という手順を踏みます。見ての通り Semantic Model を使うためにはコンパイルが必要で、リアルタイムで動かすプログラムではネックになる可能性があります。
Analyzer で使う場合は以下のように書きます。
RegisterSemanticModelAction
を使うと、内部で Semantic Model が生成されたタイミングで実行する処理を指定できます。
1 | public override void Initialize(AnalysisContext context) |
この場合は Semantic Model は IDE の動作の副産物として得られている雰囲気なので、あまりネックにはなりにくい感じはします。
Semantic Model でできること
Syntax Tree と Semantic Model が得られたところ、ようやくお楽しみの分析処理に入ります。 基本的な処理として、 Syntax Tree に対して探索により分析したい部分や候補を見つけ、そのノードを Semantic Model にある各種メソッドに渡すことで、必要な情報を取得するというのが手順となります。
Semantic Model を使ってよかったと思える処理は、識別名が被っているものに対して行う処理だと私は思っているので、 WriteLine()
メソッドを例に処理方法を見ていきます。例として、下のソースコードを解析するとします。
15 | namespace Hoge |
例として行う分析では、標準の WriteLine()
と自分で定義したもののどちらが呼ばれるかを調べます。
「 using
で何が呼ばれているか、クラスに同名のメソッドがあるかを調べればいい」と思われるかもしれませんが、 partial class
の存在や探索の深さを考慮すると、それだけでは問題が解決しない場面も考えられます。
まずは Syntax Tree を使って、 WriteLine()
メソッドが使われている部分をすべて列挙します。これは Roslyn の紹介などで出てくるサンプルと同じようなことをやっています。(もう少し短いコードで書けるとは思いますが、念のために長く。)
53 | // WriteLineメソッドのSyntax Nodeを取得 |
そして、いよいよ Semantic Model を利用します。ここでは GetSymbolInfo()
メソッドでシンボル情報、つまり簡単に言えばどのような定義されているかという情報を取得しています。
71 | foreach (var wl in writeLines) |
Semantic Model には GetSymbolInfo()
以外にも、 Get????()
というメソッドが多く用意されています。よく使うのは GetSymbolInfo()
と GetTypeInfo()
でしょうか。
実行結果は次の通りです。
1 | WriteLine("Hello Notebook!") |
いろいろな方法で WriteLine()
を呼び出していますが、どの WriteLine()
かがすぐにわかります。 Syntax Tree でこれを行うと、かなり複雑で面倒なコードになるでしょう。
まとめ
Roslyn の Semantic Model を紹介しました。難しい問題では、無理に Syntax Tree だけで解決せずに、 Semantic Model の利用を考えてみましょう。
また、 Semantic Model には、この記事では出ていない Flow Analysis という機能もあります。変数のスコープ関係や構文関係( if
や while
など)の分析に使えるもののようです。