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