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