.NET Compiler-Plattform (Roslyn)

 C Programming >> C-Programmierung >  >> Tags >> .NET
.NET Compiler-Plattform (Roslyn)

# Semantisches Modell

Ein semantisches Modell bietet im Vergleich zu einem Syntaxbaum eine tiefere Ebene der Interpretation und Einsicht in den Code. Wo Syntaxbäume die Namen von Variablen angeben können, geben semantische Modelle auch den Typ und alle Referenzen an. Syntaxbäume bemerken Methodenaufrufe, aber semantische Modelle geben Verweise auf den genauen Ort, an dem die Methode deklariert ist (nachdem die Überladungsauflösung angewendet wurde.)

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)"
            }
        }
    }
}

Dies gibt eine Liste lokaler Variablen unter Verwendung eines Syntaxbaums aus. Dann konsultiert es das semantische Modell, um den vollständigen Typnamen zu erhalten und alle Referenzen jeder Variablen zu finden.

# Syntaxbaum

Ein Syntaxbaum ist eine unveränderliche Datenstruktur, die das Programm als Baum aus Namen, Befehlen und Markierungen darstellt (wie zuvor im Editor konfiguriert).

Nehmen Sie beispielsweise Microsoft.CodeAnalysis.Compilation an Instanz namens compilation konfiguriert wurde. Es gibt mehrere Möglichkeiten, die Namen aller im geladenen Code deklarierten Variablen aufzulisten. Um dies naiv zu tun, nehmen Sie alle Teile der Syntax in jedem Dokument (die DescendantNodes -Methode) und verwenden Sie Linq, um Knoten auszuwählen, die die Variablendeklaration beschreiben:

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);
    }
}

Jeder Typ von C#-Konstrukt mit einem entsprechenden Typ ist in der Syntaxstruktur vorhanden. Um bestimmte Typen schnell zu finden, verwenden Sie die Syntax Visualizer Fenster aus Visual Studio. Dadurch wird das aktuell geöffnete Dokument als Roslyn-Syntaxbaum interpretiert.

# Arbeitsbereich aus MSBuild-Projekt erstellen

Besorgen Sie sich zuerst den Microsoft.CodeAnalysis.CSharp.Workspaces nuget, bevor Sie fortfahren.

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);
}

Um vorhandenen Code in den Arbeitsbereich zu laden, kompilieren und Fehler melden. Danach befindet sich der Code im Speicher. Von hier aus stehen sowohl die syntaktische als auch die semantische Seite zum Arbeiten zur Verfügung.