Roslyn语法树中替换多个节点

15

我正在尝试使用Roslyn替换语法树中的一些节点,但它的不可变性似乎妨碍了我。

    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();
    }

问题在于当我调用 root.ReplaceNodes 时,只有一些节点被替换了。

我猜想这个替换改变了树的结构,因此其他节点不再匹配原来的树,不能被替换。

但是,处理这个问题的最佳方法是什么呢?

反复循环该过程直到不再发生更改感觉很糟糕 :)

更改可能会嵌套发生,我认为这就是导致问题的原因。 我能否以某种方式对更改集进行排序以避免这种情况,或者在这里进行事情的惯用方式是什么?

1个回答

23
我想替换节点会更改语法树,使得其他节点不再与原始语法树匹配,因此无法替换。你是正确的。替换节点会创建全新的语法树。之前的语法树节点不能与这些新的语法树进行比较。有四种方法可以对语法树应用多个更改:
  1. 使用 DocumentEditor - 参见:https://dev59.com/OF0a5IYBdhLWcg3wPGiQ#30563669
  2. 使用 Annotations (Lines 236 and 240)
  3. 使用 .TrackNodes()
  4. 创建一个 CSharpSyntaxRewriter,从下往上替换节点。我在我的博客中写过这方面的内容。
在这些选项中,我认为 DocumentEditor 以易于使用闻名。未来在应用多个更改时,它很可能是惯用方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接