Liviu
Liviu

Reputation: 605

Syntax rewriting

I need to transform all of the properties of a certain class using Roslyn.

What is the recommended way to apply more than one transformation to a syntax tree without invalidating references into it?


Here is what I've tried and where I'm stuck:

The problem with my attempt is: When I transform a property I add new fields to the class which causes the class to mutate. All the references in the list to the other properties become invalid in the new tree for the class.

It seems to be inefficient to revisit the whole class, and either way I cannot detect the property nodes already handled due to the reference difference.

Upvotes: 1

Views: 1529

Answers (1)

andyp
andyp

Reputation: 6279

I would not recommend to reference nodes from a SyntaxTree you want to modify. In your case just using a CSharpSyntaxRewriter in a single pass (without keeping references from a pre-processing pass) would be sufficient, because its VisitPropertyDeclaration method will only be called once per property, so there is no need to keep track of the nodes you've already modified.

The CSharpSyntaxRewriter also visits the nodes bottom-up, so the overrides should always be called with a node from the original tree. Most likely you have modified the node through the call to base.VisitPropertyDeclaration() before comparing its reference to the stored one. So you could still keep and compare references if you really wanted to.

public class PropertyRewriter : CSharpSyntaxRewriter
{
    public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
    {
        // 'node' should be still from the original syntax tree here

        node = (PropertyDeclarationSyntax)base.VisitPropertyDeclaration(node);

        // 'node' might be replaced here

        return node;
    }
}

Instead of keeping references to the nodes you want to modify, you could annotate them. Annotations to a node will survive modifications of the containing SyntraxTree as long as the node itself isn't replaced. You can add them like this:

node = node.WithAdditionalAnnotations(
        new SyntaxAnnotation("propertyToChange", "todo"));

To retrieve the annotation again either use node.GetAnnotations("propertyToChange") or use GetAnnotatedNodesOrTokens("propertyToChange") to retrieve all nodes or tokens with an annotation of the given kind ("propertyToChange").

Upvotes: 5

Related Questions