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