5

我正在使用 Roslyn CTP,我正在尝试确定类中变量的值是否具有值。假设我正在尝试检测某人何时使用 BinaryExpressionSyntax 来确定字符串是否等于无“”。

例如:

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 规则中发挥很大作用。

4

1 回答 1

4

您可以尝试使用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在 first 之前未分配if,但肯定在 second 之前分配if

对于您的第二种方法,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?");
}

但是,如果您将第二个替换为ifelse它将编译。同样,Roslyn 会检测到变量总是被赋值。

于 2012-04-12T20:38:51.770 回答