2011-06-21 7 views
5

Chcę utworzyć FxRule, która stosuje metodę, tylko jeśli metoda zostanie wywołana z konkretnej klasy.Niestandardowa reguła w FxCop, aby zastosować tylko do metod wywoływanych przez metodę określonego typu

UWAGA: Nie chcę po prostu stosować reguły do ​​metody określonej klasy, chcę móc obsługiwać metody wywołujące inne metody wywołujące inne metody, które wykonują boks.

Chciałbym, aby FxCop zgłosił problemy związane z metodą, która wykonuje boks.

Poniżej znajduje się kod mam tak daleko:

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

Mój problem z powyższym kodem, to po pierwsze, że nie wydaje się być recursing. Po drugie, że FxCop zgłasza problemy jako powiązane z przestrzenią nazw (prawdopodobnie dlatego, że zaczynam wizytę przy użyciu części Check (namespace ....)

Mój problem polega na tym, że chcę, aby FxCop raportował metodę, która ma boks jako problem, ale tylko wtedy, gdy zostanie wywołany przez konkretną metodę, ale nie mam możliwości podchodzenia do drzewa wywołań, mogę odwiedzać tylko niższe węzły, aby sprawdzić problemy z moją lokalizacją początkową.

Czy ktoś zrobił coś takiego wcześniej?

Jak mogę dowiedzieć się, jakie metody nazwać daną metodę?

Odpowiedz

4

EDYCJA: Nie działa to w przypadku wywołań metod wirtualnych, gdzie IL to callvirt. Zobacz moje pytanie here.

Udało mi się go rozwiązać, odkrywając metodę CallGraph.CallersFor(). Teraz szukam metod zadeklarowanych przy danym atrybucie lub zadeklarowanych przez klasę z danym atrybutem, ale główny jest taki sam.

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); 
    } 
} 
Powiązane problemy