2011-06-23 14 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; 
    } 
} 
相關問題