替换Roslyn语法树中的多个节点

本文关键字:节点 Roslyn 语法树 替换 | 更新日期: 2023-09-27 18:02:02

我正在尝试使用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时,只有一些节点被替换。

我猜替换改变了树,使其他节点不再匹配原始树,因此不能被替换。

但是处理这个问题的最好方法是什么?

一遍又一遍地循环过程,直到没有更多的变化发生,感觉很蹩脚:)

更改可以嵌套发生,我认为这就是这里的问题所在。我是否可以对更改集进行排序以绕过这个问题,或者是否有一种惯用的方法来处理这里的事情?

替换Roslyn语法树中的多个节点

我猜替换改变了树,使其他节点不再匹配原始树,因此不能被替换。

你是对的。替换节点会创建全新的语法树。以前语法树中的节点不能与这些新的语法树进行比较。

有四种方法可以将多个更改应用于语法树:

  1. 使用DocumentEditor -参见:https://stackoverflow.com/a/30563669/300908
  2. 使用Annotations(第236和240行)
  3. 使用.TrackNodes()
  4. 创建一个CSharpSyntaxRewriter,以自底向上的方式替换节点。我已经在我的博客上写过了。

在这些选项中,我相信DocumentEditor以最容易使用而闻名。