我正在使用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规则中发挥很大作用。
答案 0 :(得分: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
未在第一个if
之前分配,但肯定会在第二个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?");
}
但是如果你用if
替换第二个else
,它将会编译。同样,Roslyn将检测到变量总是被分配。