2017-05-26 40 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())