Question

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:

  • Reflector: the Analyzer portion of the tool is not exposed as an extension point.
  • FxCop: the CallGraph class requires an FxCop context to run in.
  • Roslyn: I've no idea where to begin, but anyway I'm not interested in starting from source, I want to give it an assembly and work with the bytecode and metadata instead.
  • VS Add-in: As with Reflector, the Call Hierarchy tool is not exposed to add-ins.

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)?

Was it helpful?

Solution

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;

OTHER TIPS

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top