如何使用Roslyn代码修复提供程序API从Document中删除SyntaxNode列表?

时间:2014-10-22 10:05:38

标签: c# visual-studio-2013 roslyn vsix

我正在使用SyntaxFactory.VariableDeclaration制作自定义生成的变量声明,并根据某些条件收集SyntaxNode列表。

我做了以下事情:

  1. 修改节点

    var newRoot = root.ReplaceNode(expression, newVariableDeclaration)
    

    使用newVariableDeclaration成功修改了节点。

  2. 在循环中删除与列表中的节点对应的节点

    foreach (var listObject in listObjects)
    {
        newRoot = newRoot.RemoveNode(listObject, SyntaxRemoveOptions.KeepNoTrivia);
    }
    

    这不会更改newRoot,并且需要更改的所有listObject保持不变。

  3. 如果我们使用root.RemoveNode(listObject, SyntaxRemoveOptions.KeepNoTrivia),它显然会继续替换以前的更改。

    所以newVariableDeclaration是整个文档中唯一被更改的节点,这是因为newRoot SyntaxNodesSyntaxNode root有所变化我从CSharpSyntaxRewriter获得的{1}}。

    如果我做错了,请纠正我。

    修改 我查看了{{1}}但看起来它每次访问节点时都在分析单个节点,并且一次只能修改一个节点。在我的场景中,我将不得不访问特定节点,对其进行更改,并删除与访问节点所做更改相关的其他节点。

1 个答案:

答案 0 :(得分:1)

您的方法存在的问题是,无论何时更改树(使用ReplaceNode()RemoveNode()),都意味着所有节点都会发生变化。这就是为什么在RemoveNode()之后拨打ReplaceNode()没有做任何事情的原因。

解决此问题的一种方法是使用TrackNodes(),以便您可以找到修改后的树中哪些节点与原始树中的节点相对应。

使用此方法,用单个节点替换节点序列的方法可能如下所示:

public static T ReplaceNodes<T>(
    this T root, IReadOnlyList<SyntaxNode> oldNodes, SyntaxNode newNode)
    where T : SyntaxNode
{
    if (oldNodes.Count == 0)
        throw new ArgumentException();

    var newRoot = root.TrackNodes(oldNodes);

    var first = newRoot.GetCurrentNode(oldNodes[0]);

    newRoot = newRoot.ReplaceNode(first, newNode);

    var toRemove = oldNodes.Skip(1).Select(newRoot.GetCurrentNode);

    newRoot = newRoot.RemoveNodes(toRemove, SyntaxRemoveOptions.KeepNoTrivia);

    return newRoot;
}