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