c# - significado - roslyn new york
¿Por qué SyntaxNode.ReplaceNode cambia las opciones de SyntaxTree? (1)
Estoy tratando de reemplazar los nodos dentro de un árbol de sintaxis en Roslyn, y solo se trata de trabajar, pero con una molestia que siente que no debería ser un problema.
El árbol de sintaxis se genera a partir de un script, y quiero que el resultado sea también un árbol de sintaxis basado en scripts, pero por alguna razón, al reemplazar un nodo en el árbol se crea un nuevo árbol de sintaxis con opciones modificadas: la Kind
convierte en Regular
lugar de Script
Eso se puede SyntaxTree.WithRootAndOptions
con SyntaxTree.WithRootAndOptions
pero se siente como si estuviera haciendo algo mal si necesito llamar a eso.
Programa de muestra:
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
}
}
(La salida está en comentarios.)
¿Es esta solución realmente correcta, o hay alguna manera diferente de reemplazar el nodo en el árbol?
Cuando reemplaza nodos en un árbol, crea un nuevo subárbol de nodos. Esencialmente, este nuevo subárbol no está contenido dentro de un SyntaxTree. Sin embargo, la propiedad SyntaxTree en el nodo evoca una nueva si alguna vez la observa. En el momento en que hace esto, SyntaxTree original ya no existe, por lo que no es posible conservar las opciones de análisis. Incluso si fuera posible, conservar las opciones no tendría sentido porque ya no tiene un árbol producido por el analizador.
La razón por la que Roslyn crea este SyntaxTree es que todos los subárboles están técnicamente contenidos dentro de una instancia de SyntaxTree, para que Roslyn pueda asociar diagnósticos con él. Esto es útil si utiliza la API exploratoria de SemanticModel para intentar vincular y obtener información semántica para fragmentos de árboles que actualmente no forman parte de la compilación. El diagnóstico informa el error y su ubicación, lo que denota la instancia de árbol en la que se encuentra.