Estoy tratando de reemplazar un par de nodos en un árbol de sintaxis usando roslyn. Pero su naturaleza inmutable parece interponerse en mi camino.
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(); }
El problema es que cuando llamo a root.ReplaceNodes
solo se reemplazan algunos de los nodos.
Supongo que el reemplazo cambia el árbol para que los otros nodos ya no coincidan con el árbol original y, por lo tanto, no puedan ser reemplazados.
Pero, ¿cuál es la mejor manera de lidiar con esto?
Repasar el proceso una y otra vez hasta que no se produzcan más cambios se siente tonto :)
Los cambios pueden ocurrir anidados, y creo que eso es lo que causa los problemas aquí. ¿Puedo ordenar el conjunto de cambios de alguna manera para evitar esto o hay una forma idiomática de hacer las cosas aquí?
Supongo que el reemplazo cambia el árbol para que los otros nodos ya no coincidan con el árbol original y, por lo tanto, no puedan ser reemplazados.
Tienes razón. Reemplazar nodos crea árboles de sintaxis completamente nuevos. Los nodos de árboles de sintaxis anteriores no se pueden comparar con estos nuevos árboles de sintaxis.
Hay cuatro formas de aplicar varios cambios a un árbol de sintaxis:
DocumentEditor
: consulte: https://stackoverflow.com/a/30563669/300908Annotations
(líneas 236 y 240).TrackNodes()
CSharpSyntaxRewriter
que reemplace los nodos con un enfoque ascendente. He escrito sobre esto en mi blog . De estas opciones, creo que DocumentEditor
tiene la reputación de ser la más fácil de usar. Es muy posible que sea la forma idiomática de aplicar múltiples cambios en el futuro.