Hi everyone!
I am developing a plugin for ReSharper I wanted to do for a long while, called Agent Mulder. The idea is to analyze DI container registrations in your project, and help ReSharper fill the missing information about type usages.
I'm currently adding support to Castle Windsor, but eventually will add support to all major DI containers, pluggable via MEF.
For the most part, analyzing container registration is straightforward - I only have to detect enough information to know which concrete types are affected.
For example, Component.For<IFoo>().ImplementedBy<Foo>() is obvious, so is AllTypes.FromThisAssembly().BasedOn<IFoo>() - giving me just enough information to guestimate the concrete types that will be affected by this line.
The plugin utilizes ReSharper's Structural Search (SSR), to look for patterns in code, such as $component$.For<$type$>(), without having to manually reparse the files.
So while direct registrations are statically analyzable, some more complex things are not. Consider for example this registration:
container.Register(Classes
.FromAssemblyInDirectory(new AssemblyFilter(".").FilterByName(an => an.Name.StartsWith("Ploeh.Samples.Booking")))
.Where(t => !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dispatcher<>)))
.WithServiceAllInterfaces());
Here the information depends on a predicate that will only be evaluated at runtime.
And now I need some help.
I have two ideas on how to try and analyze this registration, both are insane and difficult, and I hope you will have some other things I hadn't considered.
- Since all I have during my static analysis is ReSharper's AST of the source code (called PSI in ReSharper), I can try to to somehow parse the lambda expression AST into a LINQ expression tree which I can later compile to an actual delegate, then load the target assembly (determined by the FromAssembly*) manually, and apply the delegate to all the types in that assembly, getting the concrete type names OR
- Go nuts, and RUN the actual piece of code by compiling a small snippet, with references to the container assemblies with Mono, Roslyn, CodeDOM or whatever, then getting the actual registered components from the container.
Both options are have lots of cons to their pros - I really would like to stick to static analysis where possible. But if there is no other choice - I'd really like to choose the lesser of the two evils. I think the 2nd approach is easier to implement, but it might be both dangerous (executing user's code) and very performance-heavy.
Or I might not do this feature at all, I don't know :)
Anyway, sorry about the long writeup, I really need a brainstorming on this, and since I'm currently not in Israel, I can't really bug you about it in person during one of the ALT.NETs :)
Thanks in advance for your ideas!
-Igal