2011-06-22 1 views
8

Je souhaite écrire une règle qui échouera si une allocation d'objet est effectuée dans une méthode appelée par une méthode marquée avec un attribut particulier.Déterminer si une méthode appelle une méthode dans un autre assembly contenant une nouvelle instruction et vice-versa

Je l'ai fait jusqu'à présent, en itérant toutes les méthodes appelant ma méthode pour vérifier en utilisant CallGraph.CallersFor(), pour voir si l'une de ces méthodes parentes a l'attribut.

Cela fonctionne pour vérifier les méthodes parentes dans le même assemblage que la méthode à vérifier. Cependant, en lisant en ligne, il semble qu'à un moment, CallGraph.CallersFor() a examiné tous les assemblages, mais ce n'est plus le cas.

Question: Existe-t-il un moyen d'obtenir une liste de méthodes qui appellent une méthode donnée, y compris celles d'un assemblage différent?

Autre réponse: Si ce qui précède n'est pas possible, comment parcourir toutes les méthodes appelées par une méthode donnée, y compris celles d'un assemblage différent.


Exemple:

-----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(); 
    } 
} 

Cela ne me dérange pas vraiment où la règle signale l'erreur, à ce stade devient l'erreur est suffisant.

+0

Je ne suis pas sûr que je comprends vraiment ce que vous essayez de vérifier. Pourriez-vous s'il vous plaît donner un exemple concret de code qui devrait générer une violation de règle? –

+0

@Nicole: Ed ité. –

Répondre

2

Je contourné ce problème en ajoutant tous les dll référencés dans mon projet FxCop, et en utilisant le code ci-dessous, qui construit un arbre d'appel manuellement (il ajoute également des appels pour les classes dérivées à travailler autour de l'autre problème que je rencontrais, 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

Avez-vous l'essayer de cette manière,

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

Merci pour la réponse, mais je n'essaie pas de le faire à l'exécution, ou avec la réflexion. J'essaye de faire ceci une règle avec FxCop, qui fait la vérification statique, par opposition à la vérification d'exécution. –

Questions connexes