Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Roslyn get MethodInfo from IMethodSymbol

how can I reliably get MethodInfo (reflection) from IMethodSymbol (Roslyn syntax tree). I can get the Type from the IMethodSymbol, and the type has many methods, of which one matches the IMethodSymbol instance.

e.g.

int i = 0;
i.Equals(5);

where the IMethodSymbol identifies 'Equals'

Note that there are 2 [Equals] methods on an [Int32] type, one taking and [Object], the other taking [Int32] parameter.

I'm parsing scripts, I don't have any workspace instances.

Any ideas? Stevo

like image 367
user1275154 Avatar asked May 29 '15 11:05

user1275154


1 Answers

It's not possible to reliably get a MethodInfo from an IMethodSymbol because you need to have the assembly loaded that contains the type that the method is on, which might be the case for the script that is being parsed but might not be the case for the code that is performing the analysis.

In other words, the script code you're running might have assembly X loaded which contains type T that has method M on it (and so the script code can have code that calls method M) but the analyser might not have assembly X loaded and so it can not load type T and so it can not get a MethodInfo instance for method M.

However, for an assembly like System, it's probably a fairly safe bet that you can access it from the analyser code.

So, all you'd need to do is get the namespace and type name of the type that has the method and get a TypeInfo instance for it. Then use GetMethod - passing it the name of the method and argument types to get a MethodInfo. Something like this:

var invocation = (InvocationExpressionSyntax)context.Node;
var methodSymbol = (IMethodSymbol)context.SemanticModel.GetSymbolInfo(invocation).Symbol;
var declaringTypeName = string.Format(
    "{0}.{1}",
    methodSymbol.ContainingType.ContainingAssembly.Name,
    methodSymbol.ContainingType.Name
);
var methodName = methodSymbol.Name;
var methodArgumentTypeNames = methodSymbol.Parameters.Select(
    p => p.Type.ContainingNamespace.Name + "." + p.Type.Name
);
var methodInfo = Type.GetType(declaringTypeName).GetMethod(
    methodName,
    methodArgumentTypeNames.Select(typeName => Type.GetType(typeName)).ToArray()
);

It's worth noting that analysers are often portable class libraries that don't have access to the full reflection API (meaning that the above code won't work) but if you're just using Roslyn in a project to analyse some scripts then you probably don't have to have that limitation.

like image 159
Dan Roberts Avatar answered Oct 17 '22 16:10

Dan Roberts