2017-05-19 36 views
15

Roslyn'de bir sözdizimi ağacındaki düğümleri değiştirmeye çalışıyorum ve bu sadece çalışmakla ilgili ama 'un bir sorun olması gerektiğini hisseden bir sıkıntıyla.SyntaxNode.ReplaceNode, SyntaxTree seçeneklerini neden değiştiriyor?

Sözdizimi ağacı bir komut dosyasından oluşturulur ve sonucun senaryona dayalı bir sözdizimi ağacı olmasını istiyorum - ama bir sebepten dolayı, ağaçtaki bir düğümü değiştirmek, değiştirilen seçeneklerle yeni bir sözdizimi ağacı oluşturur: KindScript yerine Regular olur. Bu, SyntaxTree.WithRootAndOptions ile düzeltilebilir, ancak buna ihtiyaç duyarsam yanlış bir şey yapıyorum gibi geliyor.

Örnek 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 
    } 
} 

(. Çıktı yorumların olan)

bu geçici çözüm aslında doğru mu, yoksa ağacında düğümü yerine gereken bazı farklı yol var?

+0

Dil sürümü de değişir. Bir C# 5 sözdizim ağacının olup olmadığını açıkça belirtmelisiniz. Ayrıca .WithRootAndOptions() işlevini kullandım ve bununla ilgili hiçbir sorun yaşamadım. – Tamas

+0

Benim bağırsak bunun bir hata olduğunu söylüyor ... –

+0

@JasonMalinowski: Bunu söyleyen kişi olduğunuza sevindim - Kesinlikle istemedim :) (Ama evet, bana da öyle geliyor. –

cevap

0

Ağaçtaki düğümleri değiştirdiğinizde, yeni bir alt ağaç ağacı oluşturursunuz. Esasen, bu yeni alt ağaç bir SyntaxTree içinde yer almamaktadır. Bununla birlikte, gözlemlediğinizde düğümdeki SyntaxTree özelliği yeni bir tanesini uydurur. Bu zamanda, orijinal SyntaxTree uzun gitmiştir, bu yüzden ayrıştırma seçeneklerini korumak mümkün değildir. Mümkün olsa bile, seçeneklerin korunması anlamsız olurdu çünkü artık ayrıştırıcı tarafından üretilen bir ağacınız yok.

Roslyn bu SyntaxTree'yi oluşturmasının nedeni, tüm alt ağaçların bir SyntaxTree örneği içinde teknik olarak yer almasıdır, böylece Roslyn bu tanılamayı ilişkilendirebilir. Bu, SemanticModel'in keşifsel API'sini &'u derlemenin parçası olmayan ağaç parçaları için anlamsal bilgi almak için kullanırsanız kullanışlıdır. Tanılama, içinde bulunduğu ağaç örneğini belirten hatayı ve konumunu bildirir.

+1

"Mümkün olsa bile, seçeneklerin korunması anlamsız olurdu çünkü artık ayrıştırıcı tarafından üretilen bir ağacınız yok." Bu pratik bir sebepten ziyade teorik olarak daha çok hissediyor.Elbette, "Bu ağacın tıpkı diğeri gibi olmasını istiyorum, bu bir düğüm değişti." Demek sıra dışı bir senaryo değil. Daha fazla zamanım olduğunda cevabınızın geri kalanını dikkatlice okumam gerekiyor, ama temelde bu en azından API kullanımı açısından * garip * hissediyor. Bu şekilde olması gerekebilir, ama talihsiz IMO :( –