2011-06-23 15 views
7

私はまだFxCopルールを動作させようとしています。FxCop内のcallvirt IL命令によって実際に呼び出されたメソッドを取得する方法

これの一部として、私はメソッドが呼び出すメソッドを工夫する必要があります。以前は私はCallGraph.CallersFor()を使用していました(逆にこれをやっていますが、これは私の最終的な目的です)。しかし、私は以下で説明するのと同じ問題があるようです。

私はすべての方法を訪問しようとしたCallGraphクラスを使用する代わりに、このコードに基づいて、辞書を構築するために呼び出しなど:

public override void VisitMethodCall(MethodCall call) 
{ 
    Method CalledMethod = (call.Callee as MemberBinding).BoundMember as Method; 
    // .... 
} 

しかし、それが呼び出されるメソッドは、派生クラスである場合ことが判明それが基本クラスのメソッドをオーバーライドする場合、BoundMemberは、子クラスのメソッド(実際に呼び出されるメソッド)ではなく、基本クラスのメソッドです。

質問: FxCopのcallvirt IL命令の場合に、どのように呼び出されるメソッドを取得できますか?

答えて

2

私は実際にこれを正確には必要としないことがわかります(この場合は正確な答えがないために良いです)。

FxCopは静的チェッカーであるため、変数が指すオブジェクトのインスタンスの型を決して知ることはできません。これは基本型として宣言できます。だから私は私が求めていることは不可能だと信じています。

ここでの解決方法は、コールツリーを構築するときに、派生クラスを呼び出す基本クラスの追加参照を追加することです。このようにして、私が基本クラスのメソッドを呼び出すと、派生クラスのメソッドを呼び出すことができます。私はその方法で呼び出しツリーに従うことができます。

FxCopのルールクラスで使用される私のクラスについては、以下を参照してください:

public class CallGraphBuilder : BinaryReadOnlyVisitor 
{ 
    public Dictionary<TypeNode, List<TypeNode>> ChildTypes; 

    public Dictionary<Method, List<Method>> CallersOfMethod; 

    private Method _CurrentMethod; 

    public CallGraphBuilder() 
     : base() 
    { 
     CallersOfMethod = new Dictionary<Method, List<Method>>(); 
     ChildTypes = new Dictionary<TypeNode, List<TypeNode>>(); 
    } 

    public override void VisitMethod(Method method) 
    { 
     _CurrentMethod = method; 

     base.VisitMethod(method); 
    } 

    public void CreateTypesTree(AssemblyNode Assy) 
    { 
     foreach (var Type in Assy.Types) 
     { 
      if (Type.FullName != "System.Object") 
      { 
       TypeNode BaseType = Type.BaseType; 

       if (BaseType != null && BaseType.FullName != "System.Object") 
       { 
        if (!ChildTypes.ContainsKey(BaseType)) 
         ChildTypes.Add(BaseType, new List<TypeNode>()); 

        if (!ChildTypes[BaseType].Contains(Type)) 
         ChildTypes[BaseType].Add(Type); 
       } 
      } 
     } 
    } 

    public override void VisitMethodCall(MethodCall call) 
    { 
     Method CalledMethod = (call.Callee as MemberBinding).BoundMember as Method; 

     AddCallerOfMethod(CalledMethod, _CurrentMethod); 

     Queue<Method> MethodsToCheck = new Queue<Method>(); 

     MethodsToCheck.Enqueue(CalledMethod); 

     while (MethodsToCheck.Count != 0) 
     { 
      Method CurrentMethod = MethodsToCheck.Dequeue(); 

      if (ChildTypes.ContainsKey(CurrentMethod.DeclaringType)) 
      { 
       foreach (var DerivedType in ChildTypes[CurrentMethod.DeclaringType]) 
       { 
        var DerivedCalledMethod = DerivedType.Members.OfType<Method>().Where(M => MethodHidesMethod(M, CurrentMethod)).SingleOrDefault(); 

        if (DerivedCalledMethod != null) 
        { 
         AddCallerOfMethod(DerivedCalledMethod, CurrentMethod); 

         MethodsToCheck.Enqueue(DerivedCalledMethod); 
        } 
       } 
      } 
     } 

     base.VisitMethodCall(call); 
    } 

    private void AddCallerOfMethod(Method CalledMethod, Method CallingMethod) 
    { 
     if (!CallersOfMethod.ContainsKey(CalledMethod)) 
      CallersOfMethod.Add(CalledMethod, new List<Method>()); 

     if (!CallersOfMethod[CalledMethod].Contains(CallingMethod)) 
      CallersOfMethod[CalledMethod].Add(CallingMethod); 
    } 

    private bool MethodHidesMethod(Method ChildMethod, Method BaseMethod) 
    { 
     while (ChildMethod != null) 
     { 
      if (ChildMethod == BaseMethod) 
       return true; 

      ChildMethod = ChildMethod.OverriddenMethod ?? ChildMethod.HiddenMethod; 
     } 

     return false; 
    } 
} 
関連する問題