Jerric Lyns John
Jerric Lyns John

Reputation: 936

How to remove a list of SyntaxNode from the Document using Roslyn code fix provider APIs?

I'm having a custom generated variable declaration using SyntaxFactory.VariableDeclaration and a list of SyntaxNode's collected according to some conditions.

I did the following:

  1. Modify the node

    var newRoot = root.ReplaceNode(expression, newVariableDeclaration)
    

    This successfully modified the node with the newVariableDeclaration.

  2. In a loop remove the nodes corresponding to the ones present in the list

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

    This doesn't change the newRoot and all the listObject required to be changed remains the same.

If we use root.RemoveNode(listObject, SyntaxRemoveOptions.KeepNoTrivia) instead it will, obviously, keep on replacing the previous changes.

So here the newVariableDeclaration is the only node that is changed in the whole document, is this because newRoot SyntaxNodes have changes from that of the SyntaxNode that I obtained from root.

Please correct me if I'm doing it wrong.

EDIT: I looked into CSharpSyntaxRewriter but it appears that it is analyzing a single node everytime it's visiting a node and can only modify a single node at a time. In my scenario, I'll have to visit a particular node, make changes to it, and remove other nodes with respect to the changes made to visited node.

Upvotes: 3

Views: 2410

Answers (1)

svick
svick

Reputation: 244848

The problem with your approach is that whenever you change the tree (using ReplaceNode() or RemoveNode()), it means all the nodes change as well. This is why your calls to RemoveNode() after ReplaceNode() don't do anything.

One way to fix this is to use TrackNodes(), so that you can find which nodes in the modified tree correspond to nodes in the original tree.

Uisng this, a method that replaces a sequence of nodes with a single node could look like this:

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

Upvotes: 7

Related Questions