2016-06-14 60 views
2

例如对象:罗斯林:分析调用方法

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

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

+3

在那些只是链接调用/简单构件访问结束。如果你得到最内层的调用(或'SimpleMemberAccessExpression'),你有你想要的。看看直接的父母,而不是所有的祖先。 –

+0

是否有更好的方式,而不是硬编码呢?例如,获取方法调用的符号,然后从符号中确定调用该方法的对象的实例。例如:'ClassA varA = new ClassA(); varA.methodA()'得到'methodA()'的符号,并发现'varA'调用它。 –

+0

“硬编码”是什么意思?如果你想要这个调用,你必须编写获取调用的代码。 –

回答

4

当你有一个调用节点时,你可以看到它的表达式是否是成员访问。如果调用是针对语句“DoThis()”,那么没有成员访问,但如果调用是针对“x.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 
    } 
} 
+0

嗯..但如果它的调用表达式的长链它仍然工作?例如,在Visual Studio中的语法可视化器中,节点.ChildNodes()。OfType ()。Single()。Name',Single()的invocation.express是'node.ChildNodes()。OfType < MemberAccessExpressionSyntax>()。Single语法可视化器是'MemberAccessExpressionSyntax',因此它不符合'“x.Command.ExecuteReader()”的条件,如果我错了,就纠正我。谢谢!对于最近的回复感到抱歉。大声笑。 –

+0

对不起,我想我误解了你的代码,所以你实际上是在检查'invocation.Expression.Expression'吗?那么在那种情况下,我认为你是正确的方法 –

+0

@KimKangIn是的,我基本上检查invocation.Expression.Expression - 这将返回“ExecuteReader”调用之前的完整链,无论链是多么简单或复杂。我已经稍微更改了代码示例以忽略任何不适用于“ExecuteReader”的调用,以便如果您在IDE中运行此代码并在第一个“if(memberAccess.Expression is ..”行放置了一个断点,则您将通过检查memberAccess引用来看到它在调用中的“ExecuteReader”之前始终是* everything。 –