Reputation: 155055
I'd like to find out all of the upstream callers of a particular method, over multiple assemblies.
I don't need to resolve late-bound references or virtual method calls, simple straightforward CIL call
references are fine.
I've looked at several options:
CallGraph
class requires an FxCop context to run in.I guess my only solution is to work-backwards by iterating through every method in an assembly, looking for call
instructions to my source method, then recursively repeating the process for each caller method.
Assuming my proposed solution is the way to go, what is the best way of doing it? MethodInfo.GetMethodBody().GetILAsByteArray()
seems a bit hardcore. Are there any libraries that make it simple to work with CIL (like ASM for Java)?
Upvotes: 1
Views: 164
Reputation: 244757
You can use Mono Cecil. For this purpose, it's basically the same as reflection, except that it also parses the method body for you.
A sketch of code for doing this:
var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
var methods = from module in assembly.Modules
from type in module.Types
from method in type.Methods
from instruction in method.Body.Instructions
where instruction.OpCode == OpCodes.Call
|| instruction.OpCode == OpCodes.Callvirt
let calledMethod = (MethodReference)instruction.Operand
where calledMethod.DeclaringType.Name == givenMethodTypeName
&& calledMethod.Name == givenMethodName
select method;
Upvotes: 2
Reputation: 119
I would suggest using Roslyn. Previously linked from StackOverflow is svick's answer here on MSDN: http://social.msdn.microsoft.com/Forums/vstudio/en-US/85a816cb-e931-4b49-893a-abbbf38c7a38/can-i-get-function-callercallee-information-from-roslyn
Here is a copy svick's answer: var syntaxTree = SyntaxTree.ParseCompilationUnit(code);
var semanticModel = Compilation.Create("compilation")
.AddSyntaxTrees(syntaxTree)
.AddReferences(new AssemblyFileReference(typeof(object).Assembly.Location))
.GetSemanticModel(syntaxTree);
var baz = syntaxTree.Root
.DescendentNodes()
.OfType<ClassDeclarationSyntax>()
.Single(m => m.Identifier.ValueText == "C1")
.ChildNodes()
.OfType<MethodDeclarationSyntax>()
.Single(m => m.Identifier.ValueText == "Baz");
var bazSymbol = semanticModel.GetDeclaredSymbol(baz);
var invocations = syntaxTree.Root
.DescendentNodes()
.OfType<InvocationExpressionSyntax>();
var bazInvocations = invocations
.Where(i => semanticModel.GetSemanticInfo(i).Symbol == bazSymbol);
Upvotes: -1