我正在编写一个 Rosyln 分析器/分析器。它进行检查以确保在访问类型上的另一个(可能危险的)方法之前调用该方法。为了说明我的意思,这里有一些我想要分析但失败的错误代码:
private void myMethod()
{
var myThing = new MyThing();
myThing.Value = null;
string value = myThing.GetValue(); // code blows up here as the internal value is null
}
这里的代码没问题,因为它调用了一个方法来判断它是否为 null:
private void myMethod()
{
var myThing = new MyThing();
myThing.Value = null;
if(!myThing.HasValue)
{
return ;
}
string value = myThing.GetValue();
}
因此,它应该检查所有对 GetValue
的调用先调用 HasValue
.
我刚刚开始使用 Roslyn,因此可能有一种比我最初(失败)尝试更优雅的方法:
1 - 声明我要检查调用表达式
context.RegisterSyntaxNodeAction(analyseMemberAccessNode, SyntaxKind.InvocationExpression);
2 - 在我的方法中,我得到方法名称 ( GetValue()
)
var expr = (InvocationExpressionSyntax)context.Node;
var memberAccess = expr.Expression as MemberAccessExpressionSyntax;
if (memberAccess?.Name.ToString() != "GetValue")
return;
3 - 然后我检查它是否是正确的“GetValue”
var memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol;
if (!memberSymbol?.OverriddenMethod.ToString().StartsWith("MyNamespace.MyThing.GetValue") ?? true)
return;
4 - 到目前为止,一切都很好。所以我得到了变量的名称
var e = memberAccess.Expression as IdentifierNameSyntax;
string variableName = e.Identifier.Text;
5 - 现在我陷入困境 - 我的理论是;获取包含方法,找到与 variableName
匹配的单个变量声明,找到它的用法,并确保 HasValue
在 GetValue
之前调用.
简而言之,使用 Roslyn 分析器(源自 DiagnosticAnalyzer
),如何确保 HasValue
在 GetValue
之前调用?
最佳答案
与其注册每个调用,不如注册整个方法声明。然后,您可以跟踪所有 MemberAccessExpressionSyntax
并确保对于给定变量,在 GetValue
之前调用 HasValue
。为此,我将从 MethodDeclaration
节点获取 MemberAccessExpressionSyntax
后代。
context.RegisterSyntaxNodeAction((analysisContext) =>
{
var invocations =
analysisContext.Node.DescendantNodes().OfType<MemberAccessExpressionSyntax>();
var hasValueCalls = new HashSet<string>();
foreach (var invocation in invocations)
{
var e = invocation.Expression as IdentifierNameSyntax;
if (e == null)
continue;
string variableName = e.Identifier.Text;
if (invocation.Name.ToString() == "HasValue")
{
hasValueCalls.Add(variableName);
}
if (invocation.Name.ToString() == "GetValue")
{
if (!hasValueCalls.Contains(variableName))
{
analysisContext.ReportDiagnostic(Diagnostic.Create(Rule, e.GetLocation()));
}
}
}
}, SyntaxKind.MethodDeclaration);
关于c# - 如何使用 Roslyn 查找变量以前的用法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32076495/