google / dagger

A fast dependency injector for Android and Java.
https://dagger.dev
Apache License 2.0
17.42k stars 2.01k forks source link

Finding the paths to DAG roots for a given binding #287

Open pyricau opened 8 years ago

pyricau commented 8 years ago

This isn't a feature core to Dagger2, but a tool that we could build on top.

I want a tool that can answer the question: "who needs this binding", recursively, similar to the IDE shortcut "call hierarchy" (ctrl+option+H) on methods.

screen shot 2016-01-02 at 8 49 23 am

Today, I can find the answer to that question by doing "find usages", and then for each usage I can do it again, etc etc. Doable, but not practical.

What I want instead is a tool (maybe eventually an IDE plugin) that given a type A, will give me the chain MyComponent.someMethod() > Module.someBinding() > SomeManager > A where A is a binding used by SomeManager.

To do that, we just need a representation of the whole graph, starting from the roots. If Dagger could output the whole graph for a given component in some way, we could then build that.

Another option would be to build something independent that starts from component interfaces and rebuilds the whole graph. But I'm not super excited at the idea of redoing what Dagger2 does.

gk5885 commented 8 years ago

We have actually built the beginnings of similar features within Google built by users from various contributing projects. Nothing is even quite half-baked yet, but the ideas are promising. This will make a good tracking bug though and as soon as we have something worth sharing, we'll do it here.

ajaysaini-sgvu commented 7 years ago

@gk5885 This is most requested feature of Dagger. Are are planning to release some kinda tool soon ?

sleshJdev commented 7 years ago

@ajaysaini-sgvu , vote. When I started learning the dagger I was completely confused by how the object graph looks. From my point of view, it's really none obviously. All the properties like Module(includes, subcomponents), Component(models) bring more difficulties. But it's not the only difficulty. For example, I don't understand, why subcomponents are declared in the module? Where I should use Component(dependencies={...}), what the difference between if I will do Module(include=A) and Component(dependencies=A) or if I will add both and so on.?

ronshapiro commented 5 years ago

I've recently started thinking about this as a feature similar to bazel query. Here's some ideas I've sketched out (below). Users could add these snippets to their code and recompile - Dagger would scan the code, print a warning on the applicable elements with the results of the query.

Rough examples:

@dagger.query.Query(com.example.ComponentInterface.class)
interface WhyDoesThisComponentIncludeThisModule {
  @AllPaths
  void pathsTo(DeeplyIncludedModule m);
}

@dagger.query.Query(com.example.ModuleA.class)
interface WhyDoesModuleAIncludeModuleB {
  @AllPaths
  void pathsTo(ModuleB moduleB);
}

@dagger.query.Query(com.example.ComponentInterface.class)
interface WhatBindingsAreResolvedForTheDependenciesOfAParticularBinding {
  @ResolvedDependencies
  void resolvedDependencies(@SomeQualifier SomeKey key);
}

@dagger.query.Query(com.example.ComponentInterface.class)
interface WhoDependsOnThisBinding {
  @DependentsOf // or @ReverseDependencies to match bazel query :)
  void whoDependsOn(@SomeQualifier SomeKey key);
}

@dagger.query.Query(com.example.ComponentInterface.class)
interface DoesThisBindingTransitivelyDependOnAnotherBinding {
  @SomePath
  SourceKey somePathTo(@SomeQualifier TargetKey target);
}

@dagger.query.Query(com.example.ComponentInterface.class)
interface DoesAnyoneBindAQualifiedVersionOfFoo {
  @SomePath
  void qualifiedFoos(@dagger.query.AnyQualifier Foo qualifiedFoos);
}

@dagger.query.Query(com.example.ComponentInterface.class)
interface WhatTransitiveDependenciesOfFooAreScoped {
  @SomePath
  void scopedTransitiveDependencies(@dagger.query.AnyScope Foo qualifiedFoos);

  @SomePath
  void reusableTransitiveDependencies(@Reusable AnyScope Foo qualifiedFoos);
}