user4266661
user4266661

Reputation:

Generalized Method for Getting ISymbol Information in Roslyn

I am writing a documentation generator that uses Roslyn to extract information from C# source code. As part of that I need to get ISymbol information for various types of SyntaxNodes. However, there doesn't seem to be a generalized way of doing this.

Let's say I want to determine the accessibility of a certain type of node (e.g., private, protected, public). That information is readily available if the node contains the DeclaredAccessibility property. But there doesn't seem to be an interface that indicates a given node does. Consequently you have to either use reflection to see if has that property, which can be computationally expensive, or know exactly what kind of node you're dealing with so you can cast it to the correct type.

Here's an example based on a related situation involving determining the accessibility of a const:

public const string Dummy = "abc";

When I walk through the syntax tree, and use the corresponding semantic model to extract accessibility information, I end up doing this:

SyntaxNode nodeToTest = null;

switch( syntaxNode )
{
    case FieldDeclarationSyntax fieldDecNode:
        // all the fields expressed in a field declaration share the same
        // modifiers (e.g., public, static, const) and type; they're basically
        // all from the same statement/line of code
        nodeToTest = fieldDecNode.Declaration.Variables.FirstOrDefault();
        break;

    default:
        nodeToTest = syntaxNode;
        break;
}

var nodeInfo = syntaxTree.Model.GetDeclaredSymbol( nodeToTest );

This works, and if it's the least bad approach I'll live with it (and extend it when I run into other quirks). But it feels kludgy, and I'd like to use a better/more flexible approach.

Upvotes: 1

Views: 391

Answers (1)

MattB
MattB

Reputation: 149

Have you considered using CSharpSyntaxWalker?

Represents a CSharpSyntaxVisitor that descends an entire CSharpSyntaxNode graph visiting each CSharpSyntaxNode and its child SyntaxNodes and SyntaxTokens in depth-first order.

https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.csharp.csharpsyntaxwalker?view=roslyn-dotnet

You can create your own walker class which inherits from the CSharpSyntaxWalker class and override the visit function for each subtype of SyntaxNode that you are concerned with. This means that the type of the node will be known in the function. For your example, you would override the VisitFieldDeclaration method. The doc link shows the methods for each type of SyntaxNode visitor you can override.

internal class TestWalker : CSharpSyntaxWalker
{
    private readonly SemanticModel _model;

    public TestWalker(SemanticModel model)
    {
        _model = model;
    }

    public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
    {
        // do your const field accessibility analysis here
    }

    // override any other syntax visitors here
}

You can add any other implementation details you need to the class. When you need to do the analysis, instantiate your walker and call the Visit() method on the SyntaxNode you want to start walking from.

Upvotes: 0

Related Questions