2011-06-21 4 views
5

Je souhaite créer une FxRule qui applique une méthode, uniquement si la méthode est appelée à partir d'une classe spécifique.Règle personnalisée dans FxCop à appliquer uniquement aux méthodes appelées par la méthode du type particulier

NOTE: Je ne veux pas simplement appliquer une règle à une méthode d'une classe particulière, je veux être capable de gérer des méthodes appelant d'autres méthodes appelant d'autres méthodes qui font la boxe.

J'aimerais que FxCop signale les problèmes associés à la méthode qui fait la boxe.

Ci-dessous est le code que j'ai jusqu'à présent:

using System; 
using System.Linq; 
using Microsoft.FxCop.Sdk; 
using System.Collections.Generic; 

class CheckUpdatableComponents : BaseIntrospectionRule 
{ 
    private string[] MethodsToCheck = new string[] { "BeginDraw", "BeginRun", "Draw", "EndRun", "EndDraw", "Update" }; 

    /// <summary>Gets the base class hooked up.</summary> 
    public CheckUpdatableComponents() 
     : base("CheckUpdatableComponents", "FxCopRules.Rules", typeof(CheckUpdatableComponents).Assembly) 
    { 
    } 

    public override ProblemCollection Check(string namespaceName, TypeNodeCollection types) 
    { 
     foreach (var type in types.Where(T => IsSubClassOf(T, "Microsoft.Xna.Framework.Game"))) 
     { 
      foreach (var MethodToCheck in MethodsToCheck) 
      { 
       Method RunMethod = type.GetMethod(Identifier.For(MethodToCheck)); 

       if (RunMethod != null) 
       { 
        Visit(RunMethod); 
       } 
      } 
     } 

     return Problems; 
    } 

    public override void VisitMethod(Method method) 
    { 
       Problems.Add(new Problem(GetResolution(), method, method.ToString())); // This problem only appears for each of the RunMethods, and doesn't seem to be recursing down the tree. 


     foreach (var Instruction in method.Instructions) 
     { 
      if (Instruction.NodeType == NodeType.Box || 
       Instruction.NodeType == NodeType.Unbox || 
       Instruction.NodeType == NodeType.UnboxAny || 
       Instruction.OpCode == OpCode.Box || 
       Instruction.OpCode == OpCode.Unbox || 
       Instruction.OpCode == OpCode.Unbox_Any) 
      { 
      } 
     } 

     base.VisitMethod(method); 
    } 

    private bool IsSubClassOf(TypeNode type, string typeName) 
    { 
     if (type.FullName == typeName) 
      return true; 
     if (type.BaseType == null) 
      return false; 
     else 
      return IsSubClassOf(type.BaseType, typeName); 
    } 
} 

Mon problème avec le code ci-dessus, est en premier lieu, qu'il ne semble pas être récursion. Deuxièmement, que FxCop signale les problèmes comme étant associés à l'espace de nom (probablement parce que je lance la visite en utilisant la partie Vérifier (espace de noms ....)

Mon problème est que je veux que FxCop rapporte une méthode qui a boxe comme un problème, mais seulement si elle est appelée par une méthode particulière, mais je n'ai aucun moyen de remonter l'arbre d'appel, je peux seulement visiter les nœuds inférieurs pour vérifier les problèmes avec mon emplacement de départ. ce genre de chose avant?

Comment puis-je savoir quelles méthodes appellent une méthode donnée?

Répondre

4

EDIT: Cela ne fonctionne pas dans le cas d'appels de méthode virtuelle où l'IL est callvirt. Voir ma question here.

J'ai réussi à mettre au point, en découvrant la méthode CallGraph.CallersFor(). Je cherche maintenant des méthodes déclarées avec un attribut donné, ou déclarées par une classe avec un attribut donné, mais le principal est le même.

using System; 
using System.Linq; 
using Microsoft.FxCop.Sdk; 
using System.Collections.Generic; 

class CheckUpdatableComponents : BaseIntrospectionRule 
{ 
    // private string[] MethodsToCheckNames = new string[] { "BeginDraw", "BeginRun", "Draw", "EndRun", "EndDraw", "Update" }; 

    /// <summary>Gets the base class hooked up.</summary> 
    public CheckUpdatableComponents() 
     : base("CheckUpdatableComponents", "FxCopRules.Rules", typeof(CheckUpdatableComponents).Assembly) 
    { 
    } 

    public override ProblemCollection Check(Member member) 
    { 

     Method method = member as Method; 

     if (method != null) 
     { 
      if (ShouldCheckMethod(method)) 
      { 
       foreach (var Instruction in method.Instructions) 
       { 
        if (Instruction.NodeType == NodeType.Box || 
         Instruction.NodeType == NodeType.Unbox || 
         Instruction.NodeType == NodeType.UnboxAny || 
         Instruction.OpCode == OpCode.Box || 
         Instruction.OpCode == OpCode.Unbox || 
         Instruction.OpCode == OpCode.Unbox_Any) 
        { 
         Problems.Add(new Problem(GetResolution(), Instruction, Instruction.SourceContext.StartLine.ToString())); 
        } 
       } 
      } 
     } 

     return Problems; 
    } 

    public bool ShouldCheckMethod(Method method) 
    { 
     Queue<Method> MethodsToCheck = new Queue<Method>(); 

     List<Method> MethodsChecked = new List<Method>(); 

     MethodsToCheck.Enqueue(method); 

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

      if (!MethodsChecked.Contains(MethodToCheck) && MethodToCheck != null) 
      { 
       /*if (IsSubClassOf(MethodToCheck.DeclaringType, "Microsoft.Xna.Framework.Game") && 
        MethodsToCheckNames.Contains(MethodToCheck.Name.Name)) 
       { 
        return true; 
       }*/ 

       foreach (var attribute in MethodToCheck.Attributes.Union(MethodToCheck.DeclaringType.Attributes)) 
       { 
        if (attribute.Type != null && 
         attribute.Type.FullName == "GridEngine.Components.Debugging.Attributes.FxCop.PerformanceCriticalAttribute") 
        { 
         return true; 
        } 
       } 

       // Add methods up the class tree 
       MethodsToCheck.Enqueue(MethodToCheck.OverriddenMethod); 
       MethodsToCheck.Enqueue(MethodToCheck.HiddenMethod); 



       // Add calling methods 
       foreach (var CallingMethod in CallGraph.CallersFor(MethodToCheck)) 
       { 
        MethodsToCheck.Enqueue(CallingMethod); 
       } 
      } 

      MethodsChecked.Add(MethodToCheck); 
     } 

     return false; 
    } 

    private bool IsSubClassOf(TypeNode type, string typeName) 
    { 
     if (type.FullName == typeName) 
      return true; 
     if (type.BaseType == null) 
      return false; 
     else 
      return IsSubClassOf(type.BaseType, typeName); 
    } 
} 
Questions connexes