替换 Roslyn 语法树中的多个节点 [英] Replacing multiple nodes in Roslyn syntax tree

查看:54
本文介绍了替换 Roslyn 语法树中的多个节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 roslyn 替换语法树中的几个节点.但它的不变性似乎妨碍了我.

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

问题是当我调用 root.ReplaceNodes 时,只有部分节点被替换.

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:

  1. 使用 DocumentEditor - 请参阅:https://stackoverflow.com/a/30563669/300908
  2. 使用注释(第 236 和 240 行)
  3. 使用 .TrackNodes()
  4. 创建一个 CSharpSyntaxRewriter 以自下而上的方式替换节点.我已经在我的博客.

在这些选项中,我相信 DocumentEditor 以最容易使用而著称.这很可能是应用多个更改的惯用方式.

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.

这篇关于替换 Roslyn 语法树中的多个节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆