【问题标题】:How can I find previous usages of a variable using Roslyn?如何使用 Roslyn 查找变量的先前用法?
【发布时间】:2015-11-11 15:08:52
【问题描述】:

我正在编写一个 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
}

这里的代码没问题,因为它调用了一个判断它是否为空的方法:

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 的单个变量声明,找到它的用法,并确保在 GetValue 之前调用 HasValue

简而言之,使用 Roslyn 分析器(源自 DiagnosticAnalyzer),我如何确保在 GetValue 之前调用 HasValue

【问题讨论】:

标签: c# visual-studio-2015 code-analysis roslyn


【解决方案1】:

您最好注册整个方法声明,而不是注册每个调用。然后您可以跟踪所有MemberAccessExpressionSyntax 并确保对于给定变量HasValueGetValue 之前被调用。为此,我将从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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多