• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.model;
18 
19 import static com.google.common.collect.Sets.intersection;
20 import static com.google.common.graph.Graphs.inducedSubgraph;
21 import static com.google.common.graph.Graphs.reachableNodes;
22 import static com.google.common.graph.Graphs.transpose;
23 import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
24 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
25 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
26 
27 import com.google.common.collect.ImmutableSet;
28 import com.google.common.collect.ImmutableSetMultimap;
29 import com.google.common.graph.EndpointPair;
30 import com.google.common.graph.ImmutableNetwork;
31 import com.google.common.graph.MutableNetwork;
32 import com.google.common.graph.Network;
33 import com.google.common.graph.NetworkBuilder;
34 import dagger.Module;
35 import java.util.Optional;
36 import java.util.stream.Stream;
37 import javax.lang.model.element.ExecutableElement;
38 import javax.lang.model.element.TypeElement;
39 
40 /**
41  * A graph of bindings, dependency requests, and components.
42  *
43  * <p>A {@link BindingGraph} represents one of the following:
44  *
45  * <ul>
46  *   <li>an entire component hierarchy rooted at a {@code Component} or {@code ProductionComponent}
47  *   <li>a partial component hierarchy rooted at a {@code Subcomponent} or
48  *       {@code ProductionSubcomponent} (only when the value of
49  *       {@code -Adagger.fullBindingGraphValidation} is not {@code NONE})
50  *   <li>the bindings installed by a {@code Module} or {@code ProducerModule},
51  *       including all subcomponents generated by {@code Module#subcomponents()} and
52  *       {@code ProducerModule#subcomponents()}
53  * </ul>
54  *
55  * In the case of a {@link BindingGraph} representing a module, the root {@link ComponentNode} will
56  * actually represent the module type. The graph will also be a {@linkplain #isFullBindingGraph()
57  * full binding graph}, which means it will contain all bindings in all modules, as well as nodes
58  * for their dependencies. Otherwise it will contain only bindings that are reachable from at least
59  * one {@linkplain #entryPointEdges() entry point}.
60  *
61  * <h3>Nodes</h3>
62  *
63  * <p>There is a <b>{@link Binding}</b> for each owned binding in the graph. If a binding is owned
64  * by more than one component, there is one binding object for that binding for every owning
65  * component.
66  *
67  * <p>There is a <b>{@linkplain ComponentNode component node}</b> (without a binding) for each
68  * component in the graph.
69  *
70  * <h3>Edges</h3>
71  *
72  * <p>There is a <b>{@linkplain DependencyEdge dependency edge}</b> for each dependency request in
73  * the graph. Its target node is the binding for the binding that satisfies the request. For entry
74  * point dependency requests, the source node is the component node for the component for which it
75  * is an entry point. For other dependency requests, the source node is the binding for the binding
76  * that contains the request.
77  *
78  * <p>There is a <b>subcomponent edge</b> for each parent-child component relationship in the graph.
79  * The target node is the component node for the child component. For subcomponents defined by a
80  * {@linkplain SubcomponentCreatorBindingEdge subcomponent creator binding} (either a method on the
81  * component or a set of {@code @Module.subcomponents} annotation values), the source node is the
82  * binding for the {@code @Subcomponent.Builder} type. For subcomponents defined by {@linkplain
83  * ChildFactoryMethodEdge subcomponent factory methods}, the source node is the component node for
84  * the parent.
85  *
86  * <p><b>Note that this API is experimental and will change.</b>
87  */
88 public abstract class BindingGraph {
89   /** Returns the graph in its {@link Network} representation. */
network()90   public abstract ImmutableNetwork<Node, Edge> network();
91 
92   @Override
toString()93   public String toString() {
94     return network().toString();
95   }
96 
97   /**
98    * Returns {@code true} if this graph was constructed from a module for full binding graph
99    * validation.
100    *
101    * @deprecated use {@link #isFullBindingGraph()} to tell if this is a full binding graph, or
102    *     {@link ComponentNode#isRealComponent() rootComponentNode().isRealComponent()} to tell if
103    *     the root component node is really a component or derived from a module. Dagger can generate
104    *     full binding graphs for components and subcomponents as well as modules.
105    */
106   @Deprecated
isModuleBindingGraph()107   public boolean isModuleBindingGraph() {
108     return !rootComponentNode().isRealComponent();
109   }
110 
111   /**
112    * Returns {@code true} if this is a full binding graph, which contains all bindings installed in
113    * the component, or {@code false} if it is a reachable binding graph, which contains only
114    * bindings that are reachable from at least one {@linkplain #entryPointEdges() entry point}.
115    *
116    * @see <a href="https://dagger.dev/compiler-options#full-binding-graph-validation">Full binding
117    *     graph validation</a>
118    */
isFullBindingGraph()119   public abstract boolean isFullBindingGraph();
120 
121   /**
122    * Returns {@code true} if the {@link #rootComponentNode()} is a subcomponent. This occurs in
123    * when {@code -Adagger.fullBindingGraphValidation} is used in a compilation with a subcomponent.
124    *
125    * @deprecated use {@link ComponentNode#isSubcomponent() rootComponentNode().isSubcomponent()}
126    *     instead
127    */
128   @Deprecated
isPartialBindingGraph()129   public boolean isPartialBindingGraph() {
130     return rootComponentNode().isSubcomponent();
131   }
132 
133   /** Returns the bindings. */
bindings()134   public ImmutableSet<Binding> bindings() {
135     return nodes(Binding.class);
136   }
137 
138   /** Returns the bindings for a key. */
bindings(Key key)139   public ImmutableSet<Binding> bindings(Key key) {
140     return nodes(Binding.class).stream()
141         .filter(binding -> binding.key().equals(key))
142         .collect(toImmutableSet());
143   }
144 
145   /** Returns the nodes that represent missing bindings. */
missingBindings()146   public ImmutableSet<MissingBinding> missingBindings() {
147     return nodes(MissingBinding.class);
148   }
149 
150   /** Returns the component nodes. */
componentNodes()151   public ImmutableSet<ComponentNode> componentNodes() {
152     return nodes(ComponentNode.class);
153   }
154 
155   /** Returns the component node for a component. */
componentNode(ComponentPath component)156   public Optional<ComponentNode> componentNode(ComponentPath component) {
157     return componentNodes().stream()
158         .filter(node -> node.componentPath().equals(component))
159         .findFirst();
160   }
161 
162   /** Returns the component nodes for a component. */
componentNodes(TypeElement component)163   public ImmutableSet<ComponentNode> componentNodes(TypeElement component) {
164     return componentNodes().stream()
165         .filter(node -> node.componentPath().currentComponent().equals(component))
166         .collect(toImmutableSet());
167   }
168 
169   /** Returns the component node for the root component. */
rootComponentNode()170   public ComponentNode rootComponentNode() {
171     return componentNodes().stream()
172         .filter(node -> node.componentPath().atRoot())
173         .findFirst()
174         .get();
175   }
176 
177   /** Returns the dependency edges. */
dependencyEdges()178   public ImmutableSet<DependencyEdge> dependencyEdges() {
179     return dependencyEdgeStream().collect(toImmutableSet());
180   }
181 
182   /**
183    * Returns the dependency edges for the dependencies of a binding. For valid graphs, each {@link
184    * DependencyRequest} will map to a single {@link DependencyEdge}. When conflicting bindings exist
185    * for a key, the multimap will have several edges for that {@link DependencyRequest}. Graphs that
186    * have no binding for a key will have an edge whose {@linkplain EndpointPair#target() target
187    * node} is a {@link MissingBinding}.
188    */
dependencyEdges( Binding binding)189   public ImmutableSetMultimap<DependencyRequest, DependencyEdge> dependencyEdges(
190       Binding binding) {
191     return dependencyEdgeStream(binding)
192         .collect(toImmutableSetMultimap(DependencyEdge::dependencyRequest, edge -> edge));
193   }
194 
195   /** Returns the dependency edges for a dependency request. */
dependencyEdges(DependencyRequest dependencyRequest)196   public ImmutableSet<DependencyEdge> dependencyEdges(DependencyRequest dependencyRequest) {
197     return dependencyEdgeStream()
198         .filter(edge -> edge.dependencyRequest().equals(dependencyRequest))
199         .collect(toImmutableSet());
200   }
201 
202   /**
203    * Returns the dependency edges for the entry points of a given {@code component}. Each edge's
204    * source node is that component's component node.
205    */
entryPointEdges(ComponentPath component)206   public ImmutableSet<DependencyEdge> entryPointEdges(ComponentPath component) {
207     return dependencyEdgeStream(componentNode(component).get()).collect(toImmutableSet());
208   }
209 
dependencyEdgeStream(Node node)210   private Stream<DependencyEdge> dependencyEdgeStream(Node node) {
211     return network().outEdges(node).stream().flatMap(instancesOf(DependencyEdge.class));
212   }
213 
214   /**
215    * Returns the dependency edges for all entry points for all components and subcomponents. Each
216    * edge's source node is a component node.
217    */
entryPointEdges()218   public ImmutableSet<DependencyEdge> entryPointEdges() {
219     return entryPointEdgeStream().collect(toImmutableSet());
220   }
221 
222   /** Returns the binding or missing binding nodes that directly satisfy entry points. */
entryPointBindings()223   public ImmutableSet<MaybeBinding> entryPointBindings() {
224     return entryPointEdgeStream()
225         .map(edge -> (MaybeBinding) network().incidentNodes(edge).target())
226         .collect(toImmutableSet());
227   }
228 
229   /**
230    * Returns the edges for entry points that transitively depend on a binding or missing binding for
231    * a key.
232    */
entryPointEdgesDependingOnBinding( MaybeBinding binding)233   public ImmutableSet<DependencyEdge> entryPointEdgesDependingOnBinding(
234       MaybeBinding binding) {
235     ImmutableNetwork<Node, DependencyEdge> dependencyGraph = dependencyGraph();
236     Network<Node, DependencyEdge> subgraphDependingOnBinding =
237         inducedSubgraph(
238             dependencyGraph, reachableNodes(transpose(dependencyGraph).asGraph(), binding));
239     return intersection(entryPointEdges(), subgraphDependingOnBinding.edges()).immutableCopy();
240   }
241 
242   /** Returns the bindings that directly request a given binding as a dependency. */
requestingBindings(MaybeBinding binding)243   public ImmutableSet<Binding> requestingBindings(MaybeBinding binding) {
244     return network().predecessors(binding).stream()
245         .flatMap(instancesOf(Binding.class))
246         .collect(toImmutableSet());
247   }
248 
249   /**
250    * Returns the bindings that a given binding directly requests as a dependency. Does not include
251    * any {@link MissingBinding}s.
252    *
253    * @see #requestedMaybeMissingBindings(Binding)
254    */
requestedBindings(Binding binding)255   public ImmutableSet<Binding> requestedBindings(Binding binding) {
256     return network().successors(binding).stream()
257         .flatMap(instancesOf(Binding.class))
258         .collect(toImmutableSet());
259   }
260 
261   /**
262    * Returns the bindings or missing bindings that a given binding directly requests as a
263    * dependency.
264    *
265    * @see #requestedBindings(Binding)
266    */
requestedMaybeMissingBindings(Binding binding)267   public ImmutableSet<MaybeBinding> requestedMaybeMissingBindings(Binding binding) {
268     return network().successors(binding).stream()
269         .flatMap(instancesOf(MaybeBinding.class))
270         .collect(toImmutableSet());
271   }
272 
273   /** Returns a subnetwork that contains all nodes but only {@link DependencyEdge}s. */
274   // TODO(dpb): Make public. Cache.
dependencyGraph()275   private ImmutableNetwork<Node, DependencyEdge> dependencyGraph() {
276     MutableNetwork<Node, DependencyEdge> dependencyGraph =
277         NetworkBuilder.from(network())
278             .expectedNodeCount(network().nodes().size())
279             .expectedEdgeCount((int) dependencyEdgeStream().count())
280             .build();
281     network().nodes().forEach(dependencyGraph::addNode); // include disconnected nodes
282     dependencyEdgeStream()
283         .forEach(
284             edge -> {
285               EndpointPair<Node> endpoints = network().incidentNodes(edge);
286               dependencyGraph.addEdge(endpoints.source(), endpoints.target(), edge);
287             });
288     return ImmutableNetwork.copyOf(dependencyGraph);
289   }
290 
291   @SuppressWarnings({"rawtypes", "unchecked"})
nodes(Class<N> clazz)292   private <N extends Node> ImmutableSet<N> nodes(Class<N> clazz) {
293     return (ImmutableSet) nodesByClass().get(clazz);
294   }
295 
296   private static final ImmutableSet<Class<? extends Node>> NODE_TYPES =
297       ImmutableSet.of(Binding.class, MissingBinding.class, ComponentNode.class);
298 
nodesByClass()299   protected ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
300     return network().nodes().stream()
301         .collect(
302             toImmutableSetMultimap(
303                 node ->
304                     NODE_TYPES.stream().filter(clazz -> clazz.isInstance(node)).findFirst().get(),
305                 node -> node));
306   }
307 
dependencyEdgeStream()308   private Stream<DependencyEdge> dependencyEdgeStream() {
309     return network().edges().stream().flatMap(instancesOf(DependencyEdge.class));
310   }
311 
entryPointEdgeStream()312   private Stream<DependencyEdge> entryPointEdgeStream() {
313     return dependencyEdgeStream().filter(DependencyEdge::isEntryPoint);
314   }
315 
316   /**
317    * An edge in the binding graph. Either a {@link DependencyEdge}, a {@link
318    * ChildFactoryMethodEdge}, or a {@link SubcomponentCreatorBindingEdge}.
319    */
320   public interface Edge {}
321 
322   /**
323    * An edge that represents a dependency on a binding.
324    *
325    * <p>Because one {@link DependencyRequest} may represent a dependency from two bindings (e.g., a
326    * dependency of {@code Foo<String>} and {@code Foo<Number>} may have the same key and request
327    * element), this class does not override {@link #equals(Object)} to use value semantics.
328    *
329    * <p>For entry points, the source node is the {@link ComponentNode} that contains the entry
330    * point. Otherwise the source node is a {@link Binding}.
331    *
332    * <p>For dependencies on missing bindings, the target node is a {@link MissingBinding}. Otherwise
333    * the target node is a {@link Binding}.
334    */
335   public interface DependencyEdge extends Edge {
336     /** The dependency request. */
dependencyRequest()337     DependencyRequest dependencyRequest();
338 
339     /** Returns {@code true} if this edge represents an entry point. */
isEntryPoint()340     boolean isEntryPoint();
341   }
342 
343   /**
344    * An edge that represents a subcomponent factory method linking a parent component to a child
345    * subcomponent.
346    */
347   public interface ChildFactoryMethodEdge extends Edge {
348     /** The subcomponent factory method element. */
factoryMethod()349     ExecutableElement factoryMethod();
350   }
351 
352   /**
353    * An edge that represents the link between a parent component and a child subcomponent implied by
354    * a subcomponent creator ({@linkplain dagger.Subcomponent.Builder builder} or {@linkplain
355    * dagger.Subcomponent.Factory factory}) binding.
356    *
357    * <p>The {@linkplain com.google.common.graph.EndpointPair#source() source node} of this edge is a
358    * {@link Binding} for the subcomponent creator {@link Key} and the {@linkplain
359    * com.google.common.graph.EndpointPair#target() target node} is a {@link ComponentNode} for the
360    * child subcomponent.
361    */
362   public interface SubcomponentCreatorBindingEdge extends Edge {
363     /**
364      * The modules that {@linkplain Module#subcomponents() declare the subcomponent} that generated
365      * this edge. Empty if the parent component has a subcomponent creator method and there are no
366      * declaring modules.
367      */
declaringModules()368     ImmutableSet<TypeElement> declaringModules();
369   }
370 
371   /** A node in the binding graph. Either a {@link Binding} or a {@link ComponentNode}. */
372   // TODO(dpb): Make all the node/edge types top-level.
373   public interface Node {
374     /** The component this node belongs to. */
componentPath()375     ComponentPath componentPath();
376   }
377 
378   /** A node in the binding graph that is either a {@link Binding} or a {@link MissingBinding}. */
379   public interface MaybeBinding extends Node {
380 
381     /** The component that owns the binding, or in which the binding is missing. */
382     @Override
componentPath()383     ComponentPath componentPath();
384 
385     /** The key of the binding, or for which there is no binding. */
key()386     Key key();
387 
388     /** The binding, or empty if missing. */
binding()389     Optional<Binding> binding();
390   }
391 
392   /** A node in the binding graph that represents a missing binding for a key in a component. */
393   public abstract static class MissingBinding implements MaybeBinding {
394     /** The component in which the binding is missing. */
395     @Override
componentPath()396     public abstract ComponentPath componentPath();
397 
398     /** The key for which there is no binding. */
399     @Override
key()400     public abstract Key key();
401 
402     /** @deprecated This always returns {@code Optional.empty()}. */
403     @Override
404     @Deprecated
binding()405     public Optional<Binding> binding() {
406       return Optional.empty();
407     }
408 
409     @Override
toString()410     public String toString() {
411       return String.format("missing binding for %s in %s", key(), componentPath());
412     }
413   }
414 
415   /**
416    * A <b>component node</b> in the graph. Every entry point {@linkplain DependencyEdge dependency
417    * edge}'s source node is a component node for the component containing the entry point.
418    */
419   public interface ComponentNode extends Node {
420 
421     /** The component represented by this node. */
422     @Override
componentPath()423     ComponentPath componentPath();
424 
425     /**
426      * Returns {@code true} if the component is a {@code @Subcomponent} or
427      * {@code @ProductionSubcomponent}.
428      */
isSubcomponent()429     boolean isSubcomponent();
430 
431     /**
432      * Returns {@code true} if the component is a real component, or {@code false} if it is a
433      * fictional component based on a module.
434      */
isRealComponent()435     boolean isRealComponent();
436 
437     /** The entry points on this component. */
entryPoints()438     ImmutableSet<DependencyRequest> entryPoints();
439 
440     /** The scopes declared on this component. */
scopes()441     ImmutableSet<Scope> scopes();
442   }
443 }
444