2017-02-28 5 views
4

私はRoslynを初めて使っています。私は、変数が意味モデルのある位置でスコープ内にあるかどうかを判断する方法があるかどうか疑問に思っています。私がやっていることについて少しの背景を述べるために、foreachブロックを変換して、Selectの結果を反復しようとしています。Roslynのある構文ノードで変数がスコープ内にあるかどうかを確認するにはどうすればよいですか?

foreach (int item in new int[0]) 
{ 
    string str = item.ToString(); 
} 

foreach (string str in new int[0].Select(i => i.ToString())) 
{ 
} 

形式でここに私のコードの修正プロバイダの関連部分があります。現在、私はハードコーディング反復変数がitemする午前:

var ident = SyntaxFactory.Identifier("item"); 

その後、私は、セレクタのSimpleLambdaExpressionSyntaxBodyを取得していますし、(上記の場合には)item.ToString()を取得するためにitemとパラメータiに置き換えてください。

var paramTokens = from token in selectorBody.DescendantTokens() 
        where token.Text == selectorParam.Identifier.Text 
        select token; 
selectorBody = selectorBody.ReplaceTokens(paramTokens, (_, __) => ident); 

は、私は私のコードの修正プロバイダが遺伝子をしないように、itemという名前の変数がforeachブロックの場所でスコープ内にすでにあるかどうかを伝える方法があるかどうかを知りたいです競合する変数宣言を評価します。 SemanticModel/Symbol/etcを使って何らかの形で達成することは可能でしょうか? API?

ありがとうございました。

答えて

1

私はそれを行うには2つの方法が考えられます。私は異なる宣言をテストすることができ、このテストコードを使用

(フィールド、プロパティ、変数、クラス名)

const string code = @" 
    public class AClass{ 
     private int MyFld = 5; 
     protected double MyProp{get;set;} 
     public void AMethod(){ 
      string myVar = null; 
      for (int myIterator=0; myIterator<10;myIterator++) 
       foreach (string str in new int[0].Select(i => i.ToString())){ } 
     } 
     public void AnotherMethod() 
     { 
      string anotherVar = null; 
     } 
    }"; 

-

void Main() 
{ 
    var tree = CSharpSyntaxTree.ParseText(code); 
    var root = tree.GetRoot(); 

    var startNode = root 
     .DescendantNodes() 
     .OfType<SimpleLambdaExpressionSyntax>() // start at the Select() lambda 
     .FirstOrDefault(); 

    FindSymbolDeclarationsInAncestors(startNode, "myVar").Dump(); // True 
    FindSymbolDeclarationsInAncestors(startNode, "anotherVar").Dump(); // False 

    CompilationLookUpSymbols(tree, startNode, "myVar").Dump(); // True 
    CompilationLookUpSymbols(tree, startNode, "anotherVar").Dump(); // False 
} 

// You could manually traverse the ancestor nodes, and find the different DeclarationSyntax-es. 
// I may have missed some, like CatchDeclarationSyntax.. 
// Error-prone but more fun. 
public bool FindSymbolDeclarationsInAncestors(CSharpSyntaxNode currentNode, string symbolToFind) 
{ 
    return currentNode 
     .Ancestors().SelectMany(a => a.ChildNodes()) // get direct siblings 
     .SelectMany(node => // find different declarations 
      (node as VariableDeclarationSyntax)?.Variables.Select(v => v.Identifier.ValueText) 
      ?? (node as FieldDeclarationSyntax)?.Declaration?.Variables.Select(v => v.Identifier.ValueText) 
      ?? (node as LocalDeclarationStatementSyntax)?.Declaration?.Variables.Select(v => v.Identifier.ValueText) 
      ?? new[] { 
       (node as PropertyDeclarationSyntax)?.Identifier.ValueText, 
       (node as MethodDeclarationSyntax)?.Identifier.ValueText, 
       (node as ClassDeclarationSyntax)?.Identifier.ValueText, 
       }) 
     .Any(member => string.Equals(member, symbolToFind)); 
} 

// Or use the SemanticModel from the CSharpCompilation. 
// Possibly slower? Also, not as much fun as manually traversing trees. 
public bool CompilationLookUpSymbols(SyntaxTree tree, CSharpSyntaxNode currentNode, string symbolToFind) 
{ 
    var compilation = CSharpCompilation.Create("dummy", new[] { tree }); 
    var model = compilation.GetSemanticModel(tree); 
    return model.LookupSymbols(currentNode.SpanStart, name: symbolToFind).Any(); 
} 
関連する問題