简体   繁体   English

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

[英]Replacing multiple nodes in Roslyn syntax tree

I'm trying to replace a couple of nodes in a syntax tree using roslyn. 我正在尝试使用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. 问题是,当我调用root.ReplaceNodes只有部分节点被替换。

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: 将多个更改应用于语法树有四种方法:

  1. Use the DocumentEditor - See: https://stackoverflow.com/a/30563669/300908 使用DocumentEditor - 请参阅: https//stackoverflow.com/a/30563669/300908
  2. Use Annotations (Lines 236 and 240) 使用Annotations (第236和240行)
  3. Use .TrackNodes() 使用.TrackNodes()
  4. Create a CSharpSyntaxRewriter that replaces nodes in a bottom-up approach. 创建一个CSharpSyntaxRewriter ,以自下而上的方式替换节点。 I've written about this on my blog . 我在博客上写过这篇文章

Of these options, I believe the DocumentEditor has the reputation for being the easiest to use. 在这些选项中,我相信DocumentEditor具有最容易使用的声誉。 It may very well be the idiomatic way to apply multiple changes going forward. 它很可能是未来应用多项更改的惯用方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM