2011-06-22 13 views
8

Quiero escribir una regla que fallará si se hace una asignación de objeto dentro de cualquier método llamado por un método marcado con un atributo particular.Determinar si un método llama a un método en otro ensamblado que contiene una nueva declaración y viceversa

Tengo esto funcionando hasta ahora, iterando todos los métodos que llaman a mi método para verificar usando CallGraph.CallersFor(), para ver si alguno de esos métodos padre tiene el atributo.

Esto funciona para verificar los métodos principales dentro del mismo ensamblaje que el método a verificar; sin embargo, leyendo en línea, parece que en un momento CallGraph.CallersFor() sí miró todos los ensamblajes, pero ahora no.

Pregunta: ¿Hay alguna manera de obtener una lista de métodos que invocan un método determinado, incluidos los que están en un ensamblaje diferente?

Respuesta alternativa: Si lo anterior no es posible, ¿cómo recorro todos los métodos invocados por un método determinado, incluidos los de un ensamblaje diferente?


Ejemplo:

-----In Assembly A 

public class ClassA 
{ 
    public MethodA() 
    { 
     MethodB(); 
    } 

    public MethodB() 
    { 
     object o = new object(); // Allocation i want to break the rule 
     // Currently my rule walks up the call tree, 
     // checking for a calling method with the NoAllocationsAllowed attribute. 
     // Problem is, because of the different assemblies, 
     // it can't go from ClassA.MethodA to ClassB.MethodB. 
    } 
} 


----In Assembly B 

public var ClassAInstance = new ClassA(); 

public class ClassB 
{ 
    [NoAllocationsAllowed] // Attribute that kicks off the rule-checking. 
    public MethodA() 
    { 
     MethodB(); 
    } 

    public MethodB() 
    { 
     ClassAInstance.MethodA(); 
    } 
} 

Realmente no importa donde la regla informa del error, en esta etapa consiguiendo el error es suficiente.

+0

no estoy seguro de que realmente entiendo lo que estás tratando de verificar. ¿Podrían presentar un ejemplo concreto de código que debe generar una infracción de regla? –

+0

@Nicole: Ed ited –

Respuesta

2

que tiene alrededor de este problema agregando todas las DLL que se hace referencia en mi proyecto FxCop, y utilizando el código de abajo, que construye un árbol de llamadas manualmente (se también añade llamadas para las clases derivadas para trabajar alrededor de otro problema que encontré, here.

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; 
    } 
} 
0

qué le dio una oportunidad de esta manera,

StackTrace stackTrace = new StackTrace(); 
    MethodBase methodBase = stackTrace.GetFrame(1).GetMethod(); 
    object [] items = methodBase.GetCustomAttributes(typeof (NoAllocationsAllowed)); 
    if(items.Length > 0) 
     //do whatever you want! 
+0

Gracias por la respuesta, pero no estoy tratando de hacer esto en tiempo de ejecución o con reflexión. Estoy tratando de hacer esto una regla con FxCop, que hace la comprobación estática, a diferencia de la verificación en tiempo de ejecución. –

Cuestiones relacionadas