如何获取FxCop中callvirt IL指令实际调用的方法

我仍然试图让我的FxCop规则正常工作。

作为其中的一部分,我需要弄清楚方法调用的方法。 以前我使用的是CallGraph.CallersFor() (反过来做,这是我最后的目标),但它似乎有我在下面描述的相同问题。

作为使用CallGraph类的替代方法,我尝试访问所有方法调用以构建字典,基于以下代码:

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

但是,事实certificate,如果被调用的方法在派生类上覆盖基类的方法,那么BoundMember是基类’方法,而不是子类’方法(实际上将被调用的方法) 。

问题:如何获得在FxCop中使用callvirt IL指令时将调用的方法?

事实certificate,我实际上并不需要这个(这很好,因为在这种情况下我没有确切的答案)。

因为FxCop是一个静态检查器,它永远不会知道变量指向的对象实例的类型,可以将其声明为基类型。 所以我相信我所要求的是不可能的。

我的解决方案是,在构建调用树时,我为基类“调用”任何派生类添加额外的引用。 这样,如果我在基类上调用一个方法,并且可以调用派生类的方法,我就可以按照这种方式跟随调用树。

请参阅下面的FxCop规则类使用的类:

 public class CallGraphBuilder : BinaryReadOnlyVisitor { public Dictionary> ChildTypes; public Dictionary> CallersOfMethod; private Method _CurrentMethod; public CallGraphBuilder() : base() { CallersOfMethod = new Dictionary>(); ChildTypes = new Dictionary>(); } 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()); 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 MethodsToCheck = new Queue(); 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().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()); 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; } }