C# 如何使用Roslyn查找变量的以前用法?
我在写Rosyln分析仪。它检查以确保在访问类型上的另一个(潜在危险的)方法之前调用了一个方法。为了说明我的意思,这里有一些我想分析并失败的错误代码:C# 如何使用Roslyn查找变量的以前用法?,c#,visual-studio-2015,code-analysis,roslyn,C#,Visual Studio 2015,Code Analysis,Roslyn,我在写Rosyln分析仪。它检查以确保在访问类型上的另一个(潜在危险的)方法之前调用了一个方法。为了说明我的意思,这里有一些我想分析并失败的错误代码: private void myMethod() { var myThing = new MyThing(); myThing.Value = null; string value = myThing.GetValue(); // code blows up here as the internal value is nu
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()
)
3-然后检查它是否为正确的“GetValue”
var memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol;
if (!memberSymbol?.OverriddenMethod.ToString().StartsWith("MyNamespace.MyThing.GetValue") ?? true)
return;
到目前为止,一切都很好。所以我得到了变量的名称
5-现在我陷入困境-我的理论是:;获取包含方法,找到与variableName
匹配的单变量声明,找到该声明的用法,并确保在GetValue
之前调用HasValue
简而言之,使用Roslyn分析器(源自
DiagnosticanAnalyzer
),如何确保在GetValue
之前调用HasValue
?而不是为每次调用注册,最好注册整个方法声明。然后,您可以跟踪所有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);
context.RegisterSyntaxNodeAction((analysisContext)=>
{
变量调用=
analysisContext.Node.DegenantNodes()。of type();
var hasValueCalls=newhashset();
foreach(调用中的var调用)
{
var e=invocation.Expression作为IdentifierNameSyntax;
如果(e==null)
继续;
字符串variableName=e.Identifier.Text;
if(invocation.Name.ToString()=“HasValue”)
{
hasValueCalls.Add(variableName);
}
if(invocation.Name.ToString()=“GetValue”)
{
如果(!hasValueCalls.Contains(variableName))
{
analysisContext.ReportDiagnostic(Diagnostic.Create(Rule,e.GetLocation());
}
}
}
},SyntaxKind.MethodDeclaration);
您正在查找数据流
。
var e = memberAccess.Expression as IdentifierNameSyntax;
string variableName = e.Identifier.Text;
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);