c# - 如何使用 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 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 匹配的单个变量声明,找到它的用法,并确保 HasValueGetValue 之前调用.

简而言之,使用 Roslyn 分析器(源自 DiagnosticAnalyzer ),如何确保 HasValueGetValue 之前调用?

最佳答案

与其注册每个调用,不如注册整个方法声明。然后,您可以跟踪所有 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/

相关文章:

c# - 如何在 ASP.NET Core Web API 中传递一个 int 数组

java - 如何找到 Java 类中使用特定方法的所有执行路径?

c++ - 如何标记cpp源?

c# - UDPClient 流略有延迟。我可以加快速度吗?

c# - Sharepoint 2013 站点 - CSOM - 更新导航设置

c# - 使用正则表达式时过滤掉不匹配的字符

c# - SA1401 字段必须声明为私有(private)访问。使用属性公开字段

.net - VS 2015 : Profiling tools disabled in Performance Wizard

c++ - 即使关闭 CLR 选项后仍出现错误 D8045 "cannot compile C file <file> with/clr option"

algorithm - 关于快速排序 killer