Get symbol info from new node

Viewed 104

I have a CSharpSyntaxRewriter that overrides VisitMemberAccessExpression, inside that method, I am calling MemberAccessExpressionSyntax.WithName(), but the node it returns has a different SyntaxTree compared to the original node, this is a problem since it means an error is thrown when calling SemanticModel.GetSymbolInfo(node).

Is there a way to change the Name of a MemberAccessExpressionSyntax but still have a SyntaxTree that works with SemanticModel.GetSymbolInfo(node)?

My code is:

public sealed override SyntaxNode VisitNode(SyntaxNode node)
{
    var nodeSyntax = (MemberAccessExpressionSyntax) node;
    if (nodeSyntax.Name.ToString() == OldModifier && !HasSymbol(nodeSyntax, out _))
    {
        if (ModifierType == ModifierType.Damage)
            nodeSyntax = nodeSyntax.WithName(IdentifierName($"GetDamage({NewModifier})"));
        else
            nodeSyntax = nodeSyntax.WithName(IdentifierName($"GetCritChance({NewModifier})"));

        nodeSyntax = nodeSyntax.WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia());
    }

    return nodeSyntax;
}

(VisitNode is called from VisitMemberAccessExpression)

And here are images showing the difference in the SyntaxTree: original: original node After calling WithName: modified node

1 Answers

There's a few ways to approach something like this:

Change Your Visit Method

Can you restructure your code to call VisitNode before you've done any changes to VisitMemberAccessExpression? For example can you go from:

var memberAccess = memberAccess.With...();
memberAccess = VisitNode(memberAccess);
return memberAccess;

to

var memberAccess = VisitNode(memberAccess);
memberAccess = memberAccess.With...();
return memberAccess;

Then it might mean that you are then visiting with the original node before you've done rewriting. Note this can still be tricky though if you are doing recursive stuff.

Use ReplaceNodes

There's a helper method you can use instead of a rewriter. This will call the function you pass to do rewriting at each step, but that function is handed both the original node in the original tree and the node after child nodes have been rewritten; you can use the original one to ask binding questions (since that's from the original tree) and consume the one that's been rewritten for recursive rewriting.

Break Your Problem into Two Steps

Do two walks: first get a list of all the places will need to update, add those SyntaxNodes to a HashSet or like, and then do the rewrite second where you are updating those places.

Related