2017-05-19 8 views
15

私はRoslynの構文木の中のノードを置き換えようとしています。それはちょうどうまくいっていますが、気になる邪魔になります。ではありません。SyntaxNode.ReplaceNodeがSyntaxTreeオプションを変更するのはなぜですか?

構文ツリーはスクリプトから生成され、その結果もスクリプトベースの構文ツリーにしたいが、何らかの理由でツリー内のノードを置き換えると、変更されたオプションを持つ新しい構文ツリーが作成される:KindScriptの代わりにRegularになります。それはSyntaxTree.WithRootAndOptionsで修正可能ですが、私はそれを呼び出す必要がある場合、私は何か間違っているように感じています。

サンプルプログラム:

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

(。出力はコメントである)

は、この問題を回避するには、実際には正しいですか、私は、ツリーでノードを交換する必要があり、いくつかの異なる方法がありますか?

+0

言語バージョンも変更されます。 C#5構文ツリーを使用するかどうかを明示的に指定する必要があります。私は '.WithRootAndOptions()'も使いましたが、それには問題はありませんでした。 – Tamas

+0

私の腸はこれがバグだと言っています... –

+0

@JasonMalinowski:私はあなたがそれを言ってくれてうれしいです - 私は確かにしたくありません:)(しかし、はい、それは私にもそれのように感じます。 ) –

答えて

0

ツリー内のノードを置き換えると、ノードの新しいサブツリーが作成されます。基本的に、この新しいサブツリーはSyntaxTreeに含まれていません。ただし、ノード上のSyntaxTreeプロパティは、それを観察した場合に新しいものを作成します。これを行うとき、元のSyntaxTreeは長くなくなっているので、解析オプションを保持することはできません。たとえそれが可能であったとしても、パーサによってツリーが生成されていないため、オプションを保持することは意味がありません。

RoslynがこのSyntaxTreeを作成する理由は、すべてのサブツリーが技術的にSyntaxTreeインスタンス内に含まれるため、Roslynは診断に関連付けることができるからです。これは、SemanticModelの探索的APIを使用して、&をバインドしようとすると、現在コンパイルに含まれていないツリーの断片に対してセマンティック情報を取得する場合に便利です。診断では、エラーとその場所が表示されます。エラーとその場所は、その中にあるツリーインスタンスを示します。

+1

"可能であったとしても、パーサーによってツリーが作成されていないため、オプションを保持することは意味がありません。"それは実用的な理由よりはるかに理論的な感じです。確かに、「このツリーを他のノードと同じようにしたい、この1つのノードを変更したい」というのは珍しいシナリオではありません。もっと時間があるときは、残りの答えを慎重に読む必要がありますが、基本的には、APIの使い方に関しては、このことが少なくとも気になりません。それはそのようにする必要があるかもしれませんが、残念なIMOです:( –