A while back I found a post written by jasonhaley. He provided a LINQ query to use to find all instantiations of an object with the reflector powercommands query editor. If you google "access analyze reflector" you'll find the post. The LINQ query provided on that post was the following:

(from a in AssemblyManager.Assemblies.Cast<IAssembly>()
from m in a.Modules.Cast<IModule>()
from t in m.Types.Cast<ITypeDeclaration>()
from mt in t.Methods.Cast<IMethodDeclaration>()
where ((ITypeReference)mt.DeclaringType).Namespace == "System.Net"
where mt.Body is IMethodBody
from i in ((IMethodBody)mt.Body).Instructions.Cast<IInstruction>()
where i != null && i.Value != null && i.Value is IMemberReference
&& ((IMemberReference)i.Value).Name == ".ctor"
&& ((IMemberReference)i.Value).DeclaringType is ITypeReference
&& ((ITypeReference)((IMemberReference)i.Value).DeclaringType).Name == "Stream"
&& ((ITypeReference)((IMemberReference)i.Value).DeclaringType).Namespace == "System.IO"
select mt).Distinct()

According to the post, this query returns everywhere a specified object is instantiated. I am trying to modify this to show me the exact same results returned by the "Used By" section of the Analyze function of reflector (i.e. anywhere a particular type is referenced or used). I modified the query as follows (see below), but its still not getting all references. Can anyone tell me why this is not working?

(from a in AssemblyManager.Assemblies.Cast<IAssembly>()
from m in a.Modules.Cast<IModule>()
from t in m.Types.Cast<ITypeDeclaration>()
from mt in t.Methods.Cast<IMethodDeclaration>()
where mt.Body is IMethodBody
from i in ((IMethodBody)mt.Body).Instructions.Cast<IInstruction>()
where i != null && i.Value != null && i.Value is IMemberReference
&& ((IMemberReference)i.Value).DeclaringType is ITypeReference
&& ((ITypeReference)((IMemberReference)i.Value).DeclaringType).Name=="Organization"
&& ((ITypeReference)((IMemberReference)i.Value).DeclaringType).Namespace=="MyProduct.Library"
select i.Value + ", " + t.Namespace + "." + t.Name + ", " + t.BaseType).Distinct().OrderBy(x=>x.ToString())

In the code above, I am trying to find anywhere the MyProduct.Library.Organization class is used. I know for a fact that I have a class that has a line of code in it like so:

Organization o = Utilities.CurrentOrganization;

And yet this class does not show up in my query. However, if I analyze that Organization class using the reflector analyze feature, the class that is missing in my query shows up. I am thinking that I am excluding certain types by restricting the instruction value to an IMemberReference (and then its DeclaringValue to an ITypeReference), but I'm not sure exactly what this code is doing.

Any help anyone can provide would be greatly appreciated. Thanks.
ardolino
0

Comments

3 comments

  • Clive Tong
    Unless CurrentOrganization is defined in the Organization class, I don't think you'd expect it to turn up. The query is finding places where a method defined in MyProduct.Library.Organization is being used.

    So, for example, in the following,
    namespace ConsoleApplication12
    &#123;
        public class A
        &#123;
            public virtual void Test&#40;&#41;
            &#123;   
            &#125;
        &#125;
    
        class Program
        &#123;
            static void Main&#40;&#41;
            &#123;
                A a = new A&#40;&#41;;
                a.Test&#40;&#41;;
            &#125;
        &#125;
    &#125;
    

    I can use the (slightly) modified query
                    from a in assemblyManager.Assemblies.Cast&lt;IAssembly&gt;&#40;&#41;
                    from m in a.Modules.Cast&lt;IModule&gt;&#40;&#41;
                    from t in m.Types.Cast&lt;ITypeDeclaration&gt;&#40;&#41;
                    from mt in t.Methods.Cast&lt;IMethodDeclaration&gt;&#40;&#41;
                    where mt.Body is IMethodBody
                    from i in &#40;&#40;IMethodBody&#41; mt.Body&#41;.Instructions.OfType&lt;IInstruction&gt;&#40;&#41;
                    where i.Value != null
                    let memberReference = i.Value as IMemberReference
                    where memberReference != null
                    let referencedType = memberReference.DeclaringType as ITypeReference
                    where referencedType != null
                          && referencedType.Name == "A"
                          && referencedType.Namespace == "ConsoleApplication12"
                    select "Method " + mt.Name + " in " + t.Name + " uses " + memberReference.Name;
    

    to get the results
    Method Main in Program uses .ctor
    Method Main in Program uses Test
    

    and that's because the IL has the form
    .method private hidebysig static void Main&#40;&#41; cil managed
    &#123;
        .entrypoint
        .maxstack 1
        .locals init &#40;
            &#91;0&#93; class ConsoleApplication12.A a&#41;
        L_0000: nop 
        L_0001: newobj instance void ConsoleApplication12.A::.ctor&#40;&#41;
        L_0006: stloc.0 
        L_0007: ldloc.0 
        L_0008: callvirt instance void ConsoleApplication12.A::Test&#40;&#41;
        L_000d: nop 
        L_000e: ret 
    &#125;
    

    The memberReference in the let part of the query is being bound to the two instance lines in the above.

    If you want to look at the return type of a method, you'd need to use IMethodReference (instead of IMemberReference), then convert that into a IMethodDeclaration (using Resolve()) to get the ReturnType.

    So, as a quick example, if I add the following method to my example
        class B
        &#123;
            public static A Test2&#40;&#41;
            &#123;
                return new A&#40;&#41;;
            &#125;
        &#125;
    

    and change the Main method to
        class Program
        &#123;
            static void Main&#40;&#41;
            &#123;
                A x = B.Test2&#40;&#41;;
            &#125;
        &#125;
    

    I can find things that call a method that returns an A using a query of the form
     from a in assemblyManager.Assemblies.Cast&lt;IAssembly&gt;&#40;&#41;
                    from m in a.Modules.Cast&lt;IModule&gt;&#40;&#41;
                    from t in m.Types.Cast&lt;ITypeDeclaration&gt;&#40;&#41;
                    from mt in t.Methods.Cast&lt;IMethodDeclaration&gt;&#40;&#41;
                    where mt.Body is IMethodBody
                    from i in &#40;&#40;IMethodBody&#41; mt.Body&#41;.Instructions.OfType&lt;IInstruction&gt;&#40;&#41;
                    where i.Value != null
                    let methodReference = i.Value as IMethodReference
                    where methodReference != null
                    let methodDeclaration = methodReference.Resolve&#40;&#41;
                    where methodDeclaration != null
                    let returnType = methodDeclaration.ReturnType.Type as ITypeReference
                    where returnType.Name == "A" && returnType.Namespace == "ConsoleApplication12"
                    select "Method " + mt.Name + " in " + t.Name + " uses " + methodReference.Name;
    

    which returns
    Method Main in Program uses Test2
    

    You'd need to do the same for IPropertyReference to trap properties in the same way.
    Clive Tong
    0
  • ardolino
    This is all great information and I thank you for the detailed examples.

    However, I am new at all of this. I need to create a LINQ query that would give me the same results as the Analyze function in reflector. You are much better at this than me and seem to have a very good understanding of all of this. What would be the query I would use to obtain this information? Thank you.
    ardolino
    0
  • ardolino
    I think found a solution. But not using reflector. Using an SDILReader I found on CodeProject and the native Reflection.Emit and Reflection libraries that come with .NET. I can navigate through the assemblies and the methods recursively to find what I need.

    If you still are able post the LINQ query, I think that would be helpful. I'd like to see which method is faster - the one I found, or reflector.
    ardolino
    0

Add comment

Please sign in to leave a comment.