Reputation: 349
For instance:
SqlCommand command = new SqlCommand();
SqlDataReader datareader = command.ExecuteReader();
The invocation node here is command.ExecuteReader()
. How can I, using roslyn, get the variable identifier token/node of command
from the invocation node?
Assuming that this invocation node can have many other method calls before it, e.g. classA.methodA().methodB().classB.methodC(command.ExecuteReader())
and hence getting identifiers through node.DescendantNodes
might not be useful.
The solution I thought of was to get the SpanStart of ExecuteReader
first, then follow by getting the symbol of command
by calling SymbolFinder.FindSymbolAtPosition
with the position of ExecuteReader.SpanStart - 2
. However I am unsure if this solution can handle every single situation. The application I am working on is a static code analyzer.
Upvotes: 4
Views: 2194
Reputation: 2329
When you have an invocation node, you can see whether its expression is a member access or not. If the invocation is for a statement "DoThis()" then there isn't a member access but if the invocation is for "x.DoThis()" then there is a member access since "DoThis" is being called against the reference "x".
Once you confirm that there is a member access, you may then get the expression of the target reference - this is the reference whose member is being accessed. This expression may be a simple name identifier (eg. "command") or it may be another member access (eg. "x.command") or it might be another invocation (eg. "GetCommand()") or it might be a combination of these.
To illustrate with code -
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
}
}
Upvotes: 7