2017-05-26 41 views
0

众所周知,Roslyn语法树是不可变的,所以在进行更改后,您需要获取新节点。Roslyn在已更改文档中查找相同节点

我正在尝试使用文档编辑器更新文档,但我一直收到错误消息,指出在语法树中找不到该节点。

public static T FindEquivalentNode<T>(this Document newDocument, T node) 
    where T : CSharpSyntaxNode 
{ 
    var root = newDocument.GetSyntaxRootAsync().Result; 
    return root.DescendantNodes().OfType<T>() 
      .FirstOrDefault(newNode => SyntaxFactory.AreEquivalent(newNode, node)); 
} 

当我试图再次使用该文档编辑器:

var newFieldDeclaration = documentEditor.GetChangedDocument().FindEquivalentNode(syntaxNode); 
documentEditor.ReplaceNode(newFieldDeclaration, propertyDeclaration); 

我得到一个错误:

The node is not part of the tree

的新野宣言不为空它找到一个等效场还我仍然会出现此错误,我如何替换此节点?

+0

你修改的树,然后试图找到的东西,你所在(中)在原来的树?如果是这样,那么你可以将'new SyntaxAnnotation()'添加到一个节点,然后在修改后的树中找到同一个注释实例。看到一个例子在这里:https://github.com/SonarSource/sonar-csharp/blob/63c661bde321a96ffcf9daca1aabac79e0f37929/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/GenericReadonlyFieldPropertyAssignmentCodeFixProvider.cs#L130 – Tamas

+0

@Tamas他们在哪里抓住匹配节点脱离文档,我看到他们抓取注释列表,但如何找到特定的节点? –

+0

你是如何得到你想要找到的语法节点的?它不是你想要修改的树的一部分吗?如果是,那么上面的作品。如果没有,那么你可以使用['SyntaxFactory.AreEquivalent'](http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.CSharp/Syntax/SyntaxFactory.cs,84069a73c6b638c2)。但我会说后面的解决方案很少需要,因为您应该有一个需要修改的带有sytax树的文档。 – Tamas

回答

1

你得到的节点,因为在你的FindEquivalentNode方法,你正在做的:

SyntaxFactory.AreEquivalent(newNode, node) 

SyntaxFactory.AreEquivalent不是“真正的”同一节点返回true,但对于节点\令牌都似乎在它们的结构相同(考虑topLevel参数)。

回到你的问题,如果你想打电话给ReplaceNode您必须具有“真实”的旧节点,这样你就不会得到一个

The node is not part of the tree

为了更好地实现这一点,你有几种选择,一个其中@Tamas在评论中写道:使用SyntaxAnnotations

例子:

//Add annotation to node 
var annotation = new SyntaxAnnotation("your_annotation", "some_data"); 
node = node .WithAdditionalAnnotations(annotation); 

// Now you can change the tree as much you want 

// And when you want to get the node from the changed tree 
var annotatedNode = someNode.DescendantNodesAndSelf(). 
     FirstOrDefault(n => n.GetAnnotations("your_annotation").Any())