2012-04-12 18 views
4

私はRoslyn CTPを使用していますが、クラス内の変数の値に値があるかどうかを調べようとしています。私は誰かがBinaryExpressionSyntaxを使って文字列が何も ""と等しいかどうかを判断するときを検出しようとしていると言います。例えばRoslynを使用して変数の潜在的な価値を判断する方法はありますか?

private void StringLiteral(string a) 
     { 
      if (a == "") //flagged because we do not see a explicit set of 'a' 
      { 
       Console.WriteLine("Empty String"); 
      } 
      a="42"; 
      if (a == "") //not flagged because 'a' has been set 
      { 
       Console.WriteLine("Empty String"); 
      } 
} 

私はBinaryExpressionSyntaxを取得し、セマンティックと構文を使用して左右両側を調べるが、私は可能な値を追跡し、デバッガには何も表示されないことができます。私は、これは例えば大ざっぱ得ることができます知っている:

private void BooleanTest(string a, bool b) 
     { 

      if (b) 
      { 
       a=""; 
      } 
      if (!b) 
      { 
       a="42"; 
      } 
      if (a == "") // Maybe 'a' is set maybe it isn't so we will probably not flag this one 
      { 
       Console.WriteLine("What Do I Do?"); 
      } 
} 

は、潜在的な値が変数に設定されているかどうかを判断するためにRoslynのCTPを持つことが可能ですか?私はこれがStyleCOp/FxCopのルールでは大いに役立つと思います。

答えて

3

これにはSemanticModel.AnalyzeRegionDataFlow()を使用できます。あなたはそれにテキストスパンを与え、それはAlwaysAssignedプロパティでどの変数が割り当てられるのを含め、そのテキストの中のデータフローに関する情報を知らせます。

コード全体(あなたがコンパイル単位だけでなく、メソッドを持っていると仮定)は次のようになります。あなたの第一の方法について

var tree = SyntaxTree.ParseCompilationUnit(code); 

var compilation = Compilation.Create("foo") 
    .AddSyntaxTrees(tree); 

var semanticModel = compilation.GetSemanticModel(tree); 

var methods = tree.Root.DescendentNodes().OfType<MethodDeclarationSyntax>(); 

foreach (var method in methods) 
{ 
    Console.WriteLine(method.Identifier.ValueText); 

    var binaryExpressions = method.DescendentNodes() 
     .OfType<BinaryExpressionSyntax>() 
     .Where(e => e.Kind == SyntaxKind.EqualsExpression); 

    foreach (var binaryExpression in binaryExpressions) 
    { 
     Console.WriteLine(binaryExpression); 

     // get TextSpan that starts at the beginning of the method body 
     // and ends at the beginning of the binary expression 
     var textBefore = TextSpan.FromBounds(
      method.BodyOpt.Span.Start, binaryExpression.Span.Start); 

     //Console.WriteLine(tree.Root.GetFullTextAsIText().GetText(textBefore)); 

     var alwaysAssigned = semanticModel.AnalyzeRegionDataFlow(textBefore) 
      .AlwaysAssigned; 

     var isAAlwaysAssigned = alwaysAssigned.Any(s => s.Name == "a"); 

     Console.WriteLine(isAAlwaysAssigned); 
    } 

    Console.WriteLine(); 
} 

、それは正しくaが最初if前に割り当てられていないことを検出します第2のifの前に確実に割り当てられます。

2番目の方法では、Roslynはaを割り当てる必要はないと考えているようです。しかし、それはC#コンパイラの振る舞いに沿ったものです。

private void BooleanTest(bool b) 
{ 
    string a; 
    if (b) 
     a = ""; 
    if (!b) 
     a = "42"; 
    if (a == "") 
     Console.WriteLine("What Do I Do?"); 
} 

をしかし、あなたがelseで二ifを交換した場合、それがコンパイルされます。たとえば、次のような方法ではコンパイルされません。同様に、Roslynは変数が常に割り当てられていることを検出します。

+0

ありがとう、私は定数サンプルからこれを覚えていたはずです...欠けているものは、単にタイプミスです。 AnalyzeRegionDataFlowの変数に書き込まれた値を判断する方法はありますか?私はそれが常に割り当てられていることがわかります、私はまた "WrittenInside"でそれを見ることができます...シンタックスツリーに戻ってスワップし、それをナビゲートして潜在的な価値を見極める必要がありますか? – Jay

+0

@Jay、ええ、私はそれがあなたの唯一の選択だと思います。しかし、実際には可能な値を実際には決定できないので、それをすることはあまり意味がありません。 – svick

+0

svick、ありがとう。私は同意しますが、これは単なる楽しみのためです。とにかく試してみます:) – Jay

関連する問題