2012-04-12 6 views
4

Ich verwende die Roslyn CTP und ich versuche festzustellen, ob der Wert einer Variablen in einer Klasse einen Wert hat. Sagen wir, ich versuche zu erkennen, wenn jemand eine BinaryExpressionSyntax verwendet, um festzustellen, ob eine Zeichenkette gleich null ist.Gibt es eine Möglichkeit, den potenziellen Wert einer Variablen mit Roslyn zu bestimmen?

Zum Beispiel:

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"); 
      } 
} 

Ich kann die BinaryExpressionSyntax bekommen und untersuchen sowohl die linke und rechte Seite Semantic und Syntax verwenden, aber ich habe nichts im Debugger sehen, die den möglichen Wert verfolgt. Ich weiß, das skizzenhaft beispiels bekommen konnte .:

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?"); 
      } 
} 

Ist es möglich, mit dem Roslyn CTP zu bestimmen, ob ein potentieller Wert auf eine Variable eingestellt? Ich würde denken, dass dies viel in den StyleCOp/FxCop-Regeln ins Spiel kommen würde.

Antwort

3

Sie könnten versuchen, SemanticModel.AnalyzeRegionDataFlow() dafür zu verwenden. Sie geben ihm einen Textbereich und er gibt Ihnen Informationen über den Datenfluss in diesem Textabschnitt, einschließlich der Variablen, die sicher in der Eigenschaft AlwaysAssigned zugewiesen werden.

Der gesamte Code (vorausgesetzt, Sie eine Übersetzungseinheit haben, nicht nur eine Methode) könnte wie folgt aussehen:

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(); 
} 

Für Ihre erste Methode, es erkennt richtig, dass a nicht vor dem ersten if zugewiesen wurde , ist aber sicherlich vor dem zweiten if zugewiesen.

Für Ihre zweite Methode scheint Roslyn zu denken, dass a nicht zugewiesen werden muss. Aber das entspricht der Funktionsweise des C# -Compilers. Zum Beispiel wird das folgende Verfahren nicht kompiliert:

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

Aber wenn Sie die zweite if mit else ersetzen, wird es kompilieren. Und ähnlich wird Roslyn feststellen, dass die Variable immer zugewiesen ist.

+0

danke, ich hätte mich daran erinnern müssen von der konstanten Probe ... Das fehlende andere war nur ein Tippfehler. Gibt es eine Möglichkeit zu bestimmen, welcher Wert in der AnalyzeRegionDataFlow in die Variable geschrieben wurde? Ich kann sehen, dass es immer zugewiesen ist, ich kann es auch in der "Insert-Datei" sehen ... Muss ich jetzt zurück zum Syntaxbaum wechseln und navigieren, um zu sehen, was der potenzielle Wert ist? – Jay

+0

@Jay, ja, ich denke das ist deine einzige Option. Aber es macht wahrscheinlich nicht viel Sinn, auch nur das zu tun, weil man die möglichen Werte eigentlich nur in den einfachsten Fällen bestimmen kann. – svick

+0

svick, danke nochmal. Ich stimme zu, aber das ist nur zum Spaß, also werde ich es trotzdem versuchen :) – Jay

Verwandte Themen