.NET コンパイラ プラットフォーム (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)"
            }
        }
    }
}

これは、構文ツリーを使用してローカル変数のリストを出力します。次に、セマンティック モデルを調べて完全な型名を取得し、すべての変数のすべての参照を見つけます。

# 構文ツリー

構文ツリー 名前、コマンド、およびマークのツリーとしてプログラムを表す不変のデータ構造です (エディターで以前に構成されたとおりです)。

たとえば、Microsoft.CodeAnalysis.Compilation を想定します。 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# コンストラクトが構文ツリーに存在します。特定のタイプをすばやく見つけるには、Syntax Visualizer を使用します Visual Studio のウィンドウ。これにより、現在開いているドキュメントが 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);
}

既存のコードをワークスペースに読み込むには、コンパイルしてエラーを報告します。その後、コードはメモリに配置されます。ここから、構文面と意味面の両方を使用できるようになります。