title: How can I use Cecil to find the type passed to a generic method?
body: <p>I'm trying to use Cecil to find instances of calls to a generic method using an interface for a convention test. I'm having trouble identifying the generic type from the <code>MethodReference</code>.</p>
  
  <p>I've set up a basic test:</p>
  
  <pre><code>private interface IAnimal
  {
  }
  
  private class Duck : IAnimal
  {
  }
  
  private class Farm
  {
      private readonly ICollection&lt;string&gt; _animals = new List&lt;string&gt;();
  
      public void Add&lt;T&gt;()
      {
          _animals.Add(typeof(T).Name);
      }
  
      public override string ToString()
      {
          return string.Join(", ", _animals);
      }
  }
  
  static Farm FarmFactory()
  {
      var farm = new Farm();
      farm.Add&lt;Duck&gt;();
      farm.Add&lt;Duck&gt;();
      farm.Add&lt;IAnimal&gt;();    // whoops
      farm.Add&lt;Duck&gt;();
      return farm;
  }
  
  private static void Main(string[] args)
  {
      var farm = FarmFactory();
      Console.WriteLine("Farm:");
      Console.WriteLine(farm);
  
      // Use Cecil to find the call to farm.Add&lt;IAnimal&gt;():
      Console.WriteLine("Errors:");
      FindErrors();
      Console.Read();
  }
  </code></pre>
  
  <p>So I want to find the call to <code>farm.Add&lt;IAnimal&gt;()</code>, which won't give a compile time error or even a run-time error, until the farm conceivable tried to create an instance of the type through reflection. My actual use case is a convention test for a DI container.</p>
  
  <p>Cecil comes in to it in the <code>FindErrors()</code> method:</p>
  
  <pre><code>private static void FindErrors()
  {
      var methods = AssemblyDefinition.ReadAssembly(typeof (Farm).Assembly.Location)
                                      .Modules
                                      .SelectMany(module =&gt; module.Types)
                                      .SelectMany(type =&gt; type.Methods)
                                      .Where(method =&gt; method.HasBody)
                                      .ToArray()
          ;
      var callsToFarmDotAdd = methods
          .Select(method =&gt; new
              {
                  Name = method.Name,
                  MethodReferences = GetCallsToFarmDotAdd(method)
              })
          .Where(x =&gt; x.MethodReferences.Any())
          .ToArray()
          ;
      var testCases = callsToFarmDotAdd
          .SelectMany(x =&gt; x.MethodReferences)
          ;
      var callsInError = testCases
          .Where(test =&gt; !test.GenericParameters[0].Resolve().IsClass)
          ;
  
      foreach (var error in callsInError)
      {
          Console.WriteLine(error.FullName);
      }
  }
  
  private static IEnumerable&lt;MethodReference&gt; GetCallsToFarmDotAdd(MethodDefinition method)
  {
      return method.Body.Instructions
                   .Where(instruction =&gt; instruction.OpCode == OpCodes.Callvirt)
                   .Select(instruction =&gt; (MethodReference) instruction.Operand)
                   .Where(methodReference =&gt; methodReference.FullName.Contains("Farm::Add"))
          ;
  }
  </code></pre>
  
  <p>The <code>callsInError</code> part is where I am failing to identify the generic type used when calling <code>Farm::Add</code>. Specifically, the <code>GenericParameters</code> property of the <code>MethodReference</code> is empty, so <code>GenericParameters[0]</code> gives an <code>ArgumentOutOfRangeException</code>. I've explored the <code>MethodReference</code>, and I'm definitely getting the calls to <code>Farm::Add</code>, but I can't see anywhere that relates to the generic type being used except for the <code>FullName</code> property, which isn't useful.</p>
  
  <p>How can I get Cecil to identify the generic type used in the call?</p>