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