I'm trying to replace a couple of nodes in a syntax tree using roslyn. But the immutable nature of it seems to get in my way.
public static string Rewrite(string content)
{
var tree = CSharpSyntaxTree.ParseText(content);
var root = tree.GetRoot();
var methods =root
.DescendantNodes(node=>true)
.OfType<MethodDeclarationSyntax>()
.ToList();
foreach(var method in methods)
{
var returnActions = method
.DescendantNodes(node => true)
.OfType<BinaryExpressionSyntax>()
//Ok this is cheating
.Where(node => node.OperatorToken.ValueText == "==")
.Where(node => node.Right.ToString() == "\"#exit#\"" || node.Right.ToString() == "\"#break#\"")
.Select(node => node.Parent as IfStatementSyntax)
.ToList();
var lookup = new Dictionary<StatementSyntax,StatementSyntax>();
if (returnActions.Count > 0)
{
foreach(var ifStatement in returnActions)
{
var mainCall = ifStatement.GetPrevious() as ExpressionStatementSyntax;
var newIfStatement = ifStatement.WithCondition(mainCall.Expression.WithoutTrivia());
lookup[mainCall] = null;
lookup[ifStatement] = newIfStatement;
}
//this only replace some of the nodes
root = root.ReplaceNodes(lookup.Keys, (s, d) => lookup[s]);
}
}
return root.ToFullString();
}
The problem is that when I call root.ReplaceNodes
only some of the nodes gets replaced.
I guess that the replacement changes the tree so that the other nodes no longer match the original tree and thus cant be replaced.
But what is the best way to deal with this?
Looping over the process over and over untill no more change occurs feels lame :)
The changes can occur nested, and I think that is what causes the problems here. Can I sort the changeset somehow to get around this or is there an idiomatic way to go about things here?
I guess that the replacement changes the tree so that the other nodes no longer match the original tree and thus cant be replaced.
You're right. Replacing nodes creates entirely new syntax trees. Nodes from previous syntax trees cannot be compared against these new syntax trees.
There are four ways to apply multiple changes to a syntax tree:
DocumentEditor
- See: https://stackoverflow.com/a/30563669/300908
Annotations
(Lines 236 and 240).TrackNodes()
CSharpSyntaxRewriter
that replaces nodes in a bottom-up approach. I've written about this on my blog. Of these options, I believe the DocumentEditor
has the reputation for being the easiest to use. It may very well be the idiomatic way to apply multiple changes going forward.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With