Callers and Callees

FxCop has the ability to determine which methods call a given method (the callers) and which methods a given method calls (the callees). The ability to determine the callers is built-in to the API. The ability to determine the callees is easily accomplished with some custom code.

To determine the callees for a method, use the following static method of the CallGraph class. This method searches all assemblies that are in your FxCop project. If there are no callers, the returned MethodCollection contains zero Method objects.

public static MethodCollection CallersFor(Method callee)

To determine the callees of a method, visit every MethodCall expression in that method. The following shows a possible implementation of a utility, Callees.CalleesFor, to obtain the callees.

using System;
using System.Collections.Generic;
using Microsoft.FxCop.Sdk;

namespace TutorialRules
{
  public sealed class Callees
  {
    public static IList<Method> CalleesFor(Method caller)
    {    
      if (caller == null)
        throw new ArgumentNullException("caller");

      CalleeVisitor cv = new CalleeVisitor();
      cv.VisitStatements(caller.Body.Statements);

      return cv.Callees;
    }

    private class CalleeVisitor : BinaryReadOnlyVisitor
    {
      private List<Method> m_Callees = new List<Method>();
      private Dictionary<int, int> m_CalleeIds = new Dictionary<int, int>();

      public IList<Method> Callees
      {
        get
        {
          return m_Callees;
        }
      }

      public override void VisitMethodCall(MethodCall call)
      {
        base.VisitMethodCall(call);

        MemberBinding mb = call.Callee as MemberBinding;
        if (mb == null)
          return;

        Method methd = mb.BoundMember as Method;
        if (methd == null)
          return;

        int key = methd.UniqueKey;

        if (!m_CalleeIds.ContainsKey(key))
        {
          m_Callees.Add(methd);
          m_CalleeIds.Add(key, key);
        }
      }
    }

    // Prevent instantiation of this class; all members are static.
    private Callees()
    {
    }
  }
}