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