Reputation: 605
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:
In the first pass a descendant of CSharpSyntaxWalker
is visiting all PropertyDeclarationSyntax
nodes, and storing them in a list.
In the second pass a CSharpSyntaxRewriter
is transforming the nodes while checking that each visited node equals one in the list before transforming it.
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
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