【问题标题】:Roslyn: Analyzing the object invoking the methodRoslyn:分析调用方法的对象
【发布时间】:2016-06-29 18:20:52
【问题描述】:

例如:

SqlCommand command = new SqlCommand();
SqlDataReader datareader = command.ExecuteReader();

这里的调用节点是command.ExecuteReader()。如何使用 roslyn 从调用节点获取变量标识符 token/node command? 假设此调用节点之前可以有许多其他方法调用,例如classA.methodA().methodB().classB.methodC(command.ExecuteReader()) 因此通过node.DescendantNodes 获取标识符可能没有用。 我想到的解决方案是先获取ExecuteReader的SpanStart,然后通过调用SymbolFinder.FindSymbolAtPositionExecuteReader.SpanStart - 2的位置获取command的符号。但是我不确定这个解决方案是否可以处理每一种情况。我正在开发的应用程序是一个静态代码分析器。

【问题讨论】:

  • 最后这些只是链式调用/简单的成员访问。如果你得到最内在的调用(或SimpleMemberAccessExpression),你就会得到你想要的。查看直接父母而不是所有祖先。
  • 有没有比硬编码更好的方法呢?例如,获取方法调用的符号,然后从符号中,确定调用该方法的对象的实例。例如:ClassA varA = new ClassA(); varA.methodA() 获取 methodA() 的符号并发现 varA 调用了它。
  • “硬编码”是什么意思?如果您想要该调用,则必须编写获取该调用的代码。
  • 我的回答能解决你的问题吗?我可以为您做出任何澄清或扩展以让您接受吗?

标签: c# roslyn roslyn-code-analysis


【解决方案1】:

当你有一个调用节点时,你可以看到它的表达式是否是成员访问。如果调用是针对语句“DoThis()”,则没有成员访问权限,但如果调用是针对“x.DoThis()”,则 自“DoThis”以来有成员访问权限正在针对引用“x”调用。

一旦您确认成员访问,您就可以获得目标引用的表达式 - 这是其成员正在被访问的引用。这个表达式可能是一个简单的名称标识符(例如“command”)或者它可能是另一个成员访问(例如“x.command”)或者它可能是另一个调用(例如“GetCommand()”)或者它可能是这些的组合。

用代码来说明-

private static void AnalyseInvocation(SyntaxNodeAnalysisContext context)
{
    var invocation = (InvocationExpressionSyntax)context.Node;
    var memberAccess = invocation.Expression as MemberAccessExpressionSyntax;
    if ((memberAccess == null) || (memberAccess.Name.Identifier.ValueText != "ExecuteReader"))
        return;

    if (memberAccess.Expression is IdentifierNameSyntax)
    {
        // The target is a simple identifier, the code being analysed is of the form
        // "command.ExecuteReader()" and memberAccess.Expression is the "command"
        // node
    }
    else if (memberAccess.Expression is InvocationExpressionSyntax)
    {
        // The target is another invocation, the code being analysed is of the form
        // "GetCommand().ExecuteReader()" and memberAccess.Expression is the
        // "GetCommand()" node
    }
    else if (memberAccess.Expression is MemberAccessExpressionSyntax)
    {
        // The target is a member access, the code being analysed is of the form
        // "x.Command.ExecuteReader()" and memberAccess.Expression is the "x.Command"
        // node
    }
}

【讨论】:

  • hmm..但是如果它是一长串的调用表达式,它还能工作吗?例如,node.ChildNodes().OfType<MemberAccessExpressionSyntax>().Single().Name,来自 Visual Studio 中的语法可视化器,Single() 的 invocation.express 是 node.ChildNodes().OfType<MemberAccessExpressionSyntax>().Single,从语法可视化器来看,它是 MemberAccessExpressionSyntax,因此它不满足 "x.Command.ExecuteReader()" 的条件,如我错了请纠正我。谢谢!很抱歉很晚才回复。大声笑。
  • 对不起,我想我误解了你的代码,所以你实际上是在检查invocation.Expression.Expression 对吗?那么在这种情况下,我认为您的方法是正确的
  • @KimKangIn 是的,我实际上是在检查 invocation.Expression.Expression - 这将在“ExecuteReader”调用之前返回完整的链,无论该链多么简单或复杂。我稍微更改了代码示例,以忽略任何不用于“ExecuteReader”的调用,因此如果您让此代码在 IDE 中运行并在第一个“if (memberAccess.Expression is ..”行上放置一个断点,那么通过检查 memberAccess 引用,您会发现它总是 everything 在调用中的“ExecuteReader”之前。
猜你喜欢
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多