Geo*_*ett 8 .net c# fxcop call-graph
我想编写一个规则,如果在由特定属性标记的方法调用的任何方法中进行对象分配,则该规则将失败.
到目前为止,我已经完成了这项工作,通过迭代调用我的方法来检查使用的所有方法CallGraph.CallersFor(),看看这些父方法中是否有任何属性.
这适用于检查与要检查的方法相同的程序集中的父方法,但是在线阅读时,似乎一次CallGraph.CallersFor()确实查看了所有程序集,但现在却没有.
问题:有没有办法获取调用给定方法的方法列表,包括那些在不同程序集中的方法?
替代答案:如果无法实现上述目标,我如何遍历给定方法调用的每个方法,包括不同程序集中的方法.
例:
-----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();
}
}
Run Code Online (Sandbox Code Playgroud)
我真的不介意规则报告错误的位置,在此阶段获取错误就足够了.
我通过在 FxCop 项目中添加所有引用的 dll 并使用下面的代码解决了这个问题,该代码手动构建了一个调用树(它还添加了对派生类的调用来解决我遇到的另一个问题,这里。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
415 次 |
| 最近记录: |