Comments
3 comments
-
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 { public class A { public virtual void Test() { } } class Program { static void Main() { A a = new A(); a.Test(); } } }
I can use the (slightly) modified queryfrom 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.OfType<IInstruction>() 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 resultsMethod 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() cil managed { .entrypoint .maxstack 1 .locals init ( [0] class ConsoleApplication12.A a) L_0000: nop L_0001: newobj instance void ConsoleApplication12.A::.ctor() L_0006: stloc.0 L_0007: ldloc.0 L_0008: callvirt instance void ConsoleApplication12.A::Test() L_000d: nop L_000e: ret }
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 exampleclass B { public static A Test2() { return new A(); } }
and change the Main method toclass Program { static void Main() { A x = B.Test2(); } }
I can find things that call a method that returns an A using a query of the formfrom 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.OfType<IInstruction>() where i.Value != null let methodReference = i.Value as IMethodReference where methodReference != null let methodDeclaration = methodReference.Resolve() 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 returnsMethod Main in Program uses Test2
You'd need to do the same for IPropertyReference to trap properties in the same way. -
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. -
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.
Add comment
Please sign in to leave a comment.
(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.