Why does SyntaxNode.ReplaceNode change the SyntaxTree options?

Viewed 2116

I'm trying to replace nodes within a syntax tree in Roslyn, and it's just about working, but with an annoyance which feels it shouldn't be a problem.

The syntax tree is generated from a script, and I want the result to be a script-based syntax tree too - but for some reason, replacing a node in the tree creates a new syntax tree with changed options: the Kind becomes Regular instead of Script. That's fixable with SyntaxTree.WithRootAndOptions but it feels like I'm doing something wrong if I need to call that.

Sample program:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Scripting;
using System;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        Script script = CSharpScript.Create("Console.WriteLine(\"Before\")",
            ScriptOptions.Default.AddImports("System"));

        var compilation = script.GetCompilation();
        var tree = compilation.SyntaxTrees.Single();

        var after = SyntaxFactory.LiteralExpression(
            SyntaxKind.StringLiteralExpression,
            SyntaxFactory.Literal("After"));

        var root = tree.GetRoot();
        var before = root.DescendantNodes().OfType<LiteralExpressionSyntax>().Single();
        var newRoot = root.ReplaceNode(before, after);
        var fixedTree = newRoot.SyntaxTree.WithRootAndOptions(newRoot, tree.Options);

        Console.WriteLine(newRoot);                         // Console.WriteLine("After")
        Console.WriteLine(tree.Options.Kind);               // Script
        Console.WriteLine(newRoot.SyntaxTree.Options.Kind); // Regular
        Console.WriteLine(fixedTree.Options.Kind);          // Script
    }
}

(Output is in comments.)

Is this workaround actually correct, or is there some different way I should be replacing the node in the tree?

1 Answers
Related