This project is read-only.

GetCurrentNode() after replacing the node throws


When I start tracking some node, replace it with another node using ReplaceNode() and then try to find out which node corresponds to the old node now, GetCurrentNode() throws ArgumentNullException.

Even if I'm misunderstanding how tracking nodes works and this is not a supported operation, the thrown exception should explain the problem instead of being this cryptic.

Code to reproduce:
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace roslyn_tracknodes_bug
    static class Program
        static void Main()
            var code = @"class Foo
    public static void Bar()
        var l = new List<int>();
            var root = SyntaxFactory.ParseCompilationUnit(code);

            var oldNode = root.DescendantNodes().OfType<LocalDeclarationStatementSyntax>().Single();

            var newNode = SyntaxFactory.ParseStatement("        var l = new List<int> { 42 };\n");

            var newRoot = root.TrackNodes(oldNode);

            var currentNode1 = newRoot.GetCurrentNode(oldNode);

            newRoot = newRoot.ReplaceNode(currentNode1, newNode);

            var currentNode2 = newRoot.GetCurrentNode(oldNode);
Thrown exception:
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: source
   at System.Linq.Enumerable.OfType[TResult](IEnumerable source)
   at Microsoft.CodeAnalysis.SyntaxNodeExtensions.<GetCurrentNodes>d__8`1.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at Microsoft.CodeAnalysis.SyntaxNodeExtensions.GetCurrentNode[TNode](SyntaxNode root, TNode node)
   at roslyn_tracknodes_bug.Program.Main() in C:\code\roslyn tracknodes bug\Program.cs:line 31
I'm using the latest version of Roslyn from NuGet (0.7.4091001-beta from 29 September 2014 ).


svick wrote Oct 25, 2014 at 9:18 PM

After looking into this, I now believe that tracking (and annotations in general) don't work this way, so the final newRoot.GetCurrentNode(oldNode) in the code above should return null.

I have created a pull request that makes Roslyn do that: