Syntax Tree
Introduction#
One of the major parts of the Roslyn compiler is the Syntax API. It exposes the syntax trees the compilers use to understand Visual Basic and C# programs.
Remarks#
- The Syntax Tree is a Parse Tree in the context of the Roslyn compiler.
Getting the Syntax Tree Root from a Document.
If you already have access to your Document
class from your workspace (Using Workspaces) it is easy to access the root of your Syntax tree.
Document document = ... // Get document from workspace or other source
var syntaxRoot = await document.GetSyntaxRootAsync();
Traversing the Syntax Tree Using LINQ
You can easily navigate the a Syntax Tree using LINQ. For example it is easy to get all the ClassDeclarationSyntax
nodes (declared classes), that have a name starting with the letter A
:
var allClassesWithNameStartingWithA = syntaxRoot.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(x => x.Identifier.ToString().StartsWith("A"));
Or getting all the classes that have attributes:
var allClassesWithAttriutes = syntaxRoot.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(x => x.AttributeLists.Any(y => y.Attributes.Any()));
Traversing the Syntax Tree using a CSharpSyntaxWalker
The CSharpSyntaxWalker
class is out of the box implementation of the Visitor pattern, that we can use to traverse our Syntax Tree. Here is a simple example of a Syntax Walker that collects all the struct
-s that have a name, starting with the letter A
:
public class StructCollector : CSharpSyntaxWalker
{
public StructCollector()
{
this.Structs = new List<StructDeclarationSyntax>();
}
public IList<StructDeclarationSyntax> Structs { get; }
public override void VisitStructDeclaration(StructDeclarationSyntax node)
{
if (node.Identifier.ToString().StartsWith("A"))
{
this.Structs.Add(node);
}
}
}
We can use our SyntaxWalker in the following way:
var structCollector = new StructCollector();
structCollector.Visit(syntaxRoot); // Or any other syntax node
Console.WriteLine($"The number of structs that have a name starting with the letter 'A' is {structCollector.Structs.Count}");