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