Question

Hi I'm unsing NDepend for some analysis on my code. I wanted to get all methods from my codebase that are calling certain method and I observed that it doesn't work as I expected.

Here are my observations:

In my code I have:

1.) An interface IMyInterface with method Method1

public interface IMyInterface {
    void Method1();
}

2.) A class that implements the above interface

public class MyClass : IMyInterface {
    public void Method1() {
        // Implementation
    }
}

3.) Somewhere in the code of my program I have a method that does the following

public void MethodCaller() {
    IMyInterface instance = new MyClass();
    instance.Method1();
}

Now, using NDepend, I observe the following:

I get an IMethod instance for the MyClass.Method1 method, e.g. method1Info and its MethodsCallingMe property returns 0 result.

method1Info.MethodsCallingMe count is 0.

If I get IMethod instance for the IMyInterace.Method1 method MethodsCallingMe property returns 1 item which is MethodCaller.

I'm looking for a way to find all methods that are calling certain method implementation no matter through which type it is called. I can not achieve that with MethodsCallingMe. How can I achieve that?

Était-ce utile?

La solution

Indeed in your context:

from m in Methods where m.IsUsing ("MyNamespace.IMyInterface.Method1()") select m

...returns MyNamespace.CallerClass.MethodCaller() and ...

from m in Methods where m.IsUsing ("MyNamespace.MyClass.Method1()") select m

...returns nothing. The reason is simple: NDepend does static analysis and doesn't try to do dynamic analysis. Hence it doesn't try to look who implements an abstract method, even if in the MethodCaller() context type class of the variable instance can be inferred without any ambiguity.

However since NDepend code query language is pretty flexible, the following code query can detect your case and provide the result you wish. Notice that false positive can be matched, but it would be a pretty tweaked case.

// Gather the abstract method
let mAbstract = Application.Methods.WithFullName("MyNamespace.IMyInterface.Method1()").Single()

from m in Methods where m.IsUsing(mAbstract)

// Get ctors called by MethodCaller()
let ctorsCalled = m.MethodsCalled.Where(mc => mc.IsConstructor)

// Get classes that implement IMyInterface instantiated by MethodCaller()
let classesInstantiated = ctorsCalled.ParentTypes().Where(t => t.Implement("MyNamespace.IMyInterface"))

// Get override of Method1() 'probably' called.
let overridesCalled = classesInstantiated.ChildMethods().Where(m1 => m1.OverriddensBase.Contains(mAbstract))

select new { m, overridesCalled }

Concretely this look like:

enter image description here


As a side note, being able to infer without ambiguity the class of an object referenced through an interface is more the exception than the rule, since often fields and methods parameters are referenced through an interface and doesn't hold any information about how they are instantiated.


The code I used:

namespace MyNamespace {
    public interface IMyInterface {
        void Method1();
    }
    public class MyClass : IMyInterface {
        public void Method1() {
            // Implementation
        }
    }
    public class CallerClass {
        public void MethodCaller() {
            IMyInterface instance = new MyClass();
            instance.Method1();
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top