C# Language
.NETコンパイラプラットフォーム(Roslyn)
サーチ…
MSBuildプロジェクトからワークスペースを作成する
続行する前に、まずMicrosoft.CodeAnalysis.CSharp.Workspaces
ナゲットを入手してください。
var workspace = Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.Create();
var project = await workspace.OpenProjectAsync(projectFilePath);
var compilation = await project.GetCompilationAsync();
foreach (var diagnostic in compilation.GetDiagnostics()
.Where(d => d.Severity == Microsoft.CodeAnalysis.DiagnosticSeverity.Error))
{
Console.WriteLine(diagnostic);
}
既存のコードをワークスペースに読み込むには、エラーをコンパイルして報告します。その後、コードはメモリ内に配置されます。ここからは、構文的側面と意味論的側面の両方が利用できるようになります。
構文木
シンタックスツリーは、名前、コマンド、およびマークのツリーとしてプログラムを表す不変のデータ構造です(以前はエディタで設定されていました)。
たとえば、 compilation
という名前のMicrosoft.CodeAnalysis.Compilation
インスタンスが構成されているとします。ロードされたコードで宣言されたすべての変数の名前をリストする方法は複数あります。このように単純に行うには、すべてのドキュメント( DescendantNodes
メソッド)のすべての構文を取り、Linqを使用して変数宣言を記述するノードを選択します。
foreach (var syntaxTree in compilation.SyntaxTrees)
{
var root = await syntaxTree.GetRootAsync();
var declaredIdentifiers = root.DescendantNodes()
.Where(an => an is VariableDeclaratorSyntax)
.Cast<VariableDeclaratorSyntax>()
.Select(vd => vd.Identifier);
foreach (var di in declaredIdentifiers)
{
Console.WriteLine(di);
}
}
対応する型を持つすべての型のC#構文が構文ツリーに存在します。特定のタイプをすばやく見つけるには、Visual StudioのSyntax Visualizer
ウィンドウを使用します。これは現在開いている文書をRoslyn構文木として解釈します。
セマンティックモデル
セマンティックモデルは、構文ツリーと比較して、より深いレベルの解釈と洞察を提供します。構文木が変数の名前を知ることができるところでは、意味論的モデルも型とすべての参照を与える。構文ツリーはメソッド呼び出しを認識しますが、セマンティックモデルはメソッドが宣言された正確な場所を参照します(過負荷解決が適用された後)。
var workspace = Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.Create();
var sln = await workspace.OpenSolutionAsync(solutionFilePath);
var project = sln.Projects.First();
var compilation = await project.GetCompilationAsync();
foreach (var syntaxTree in compilation.SyntaxTrees)
{
var root = await syntaxTree.GetRootAsync();
var declaredIdentifiers = root.DescendantNodes()
.Where(an => an is VariableDeclaratorSyntax)
.Cast<VariableDeclaratorSyntax>();
foreach (var di in declaredIdentifiers)
{
Console.WriteLine(di.Identifier);
// => "root"
var variableSymbol = compilation
.GetSemanticModel(syntaxTree)
.GetDeclaredSymbol(di) as ILocalSymbol;
Console.WriteLine(variableSymbol.Type);
// => "Microsoft.CodeAnalysis.SyntaxNode"
var references = await SymbolFinder.FindReferencesAsync(variableSymbol, sln);
foreach (var reference in references)
{
foreach (var loc in reference.Locations)
{
Console.WriteLine(loc.Location.SourceSpan);
// => "[1375..1379)"
}
}
}
}
これは、構文木を使用してローカル変数のリストを出力します。次に、セマンティックモデルを参照して完全な型名を取得し、すべての変数のすべての参照を検索します。