1 /* 2 * Copyright (C) 2014 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.internal.codegen.binding; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent; 22 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType; 23 import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement; 24 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 25 import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION; 26 import static dagger.internal.codegen.model.BindingKind.DELEGATE; 27 import static dagger.internal.codegen.model.BindingKind.INJECTION; 28 import static dagger.internal.codegen.model.BindingKind.OPTIONAL; 29 import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR; 30 import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION; 31 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; 32 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf; 33 import static java.util.function.Predicate.isEqual; 34 35 import androidx.room.compiler.processing.XTypeElement; 36 import com.google.auto.value.AutoValue; 37 import com.google.auto.value.extension.memoized.Memoized; 38 import com.google.common.collect.ImmutableList; 39 import com.google.common.collect.ImmutableSet; 40 import com.google.common.collect.Iterables; 41 import dagger.Reusable; 42 import dagger.internal.codegen.base.ContributionType; 43 import dagger.internal.codegen.base.Keys; 44 import dagger.internal.codegen.base.MapType; 45 import dagger.internal.codegen.base.SetType; 46 import dagger.internal.codegen.compileroption.CompilerOptions; 47 import dagger.internal.codegen.javapoet.TypeNames; 48 import dagger.internal.codegen.model.BindingGraph.ComponentNode; 49 import dagger.internal.codegen.model.BindingKind; 50 import dagger.internal.codegen.model.ComponentPath; 51 import dagger.internal.codegen.model.DaggerTypeElement; 52 import dagger.internal.codegen.model.DependencyRequest; 53 import dagger.internal.codegen.model.Key; 54 import dagger.internal.codegen.model.RequestKind; 55 import dagger.internal.codegen.model.Scope; 56 import java.util.ArrayDeque; 57 import java.util.Deque; 58 import java.util.HashMap; 59 import java.util.HashSet; 60 import java.util.LinkedHashMap; 61 import java.util.LinkedHashSet; 62 import java.util.Map; 63 import java.util.Optional; 64 import java.util.Queue; 65 import java.util.Set; 66 import javax.inject.Inject; 67 68 /** A factory for {@link BindingGraph} objects. */ 69 public final class LegacyBindingGraphFactory { 70 useLegacyBindingGraphFactory( CompilerOptions compilerOptions, ComponentDescriptor componentDescriptor)71 static boolean useLegacyBindingGraphFactory( 72 CompilerOptions compilerOptions, ComponentDescriptor componentDescriptor) { 73 return !compilerOptions.useBindingGraphFix(); 74 } 75 hasStrictMultibindingsExemption( CompilerOptions compilerOptions, ContributionBinding binding)76 static boolean hasStrictMultibindingsExemption( 77 CompilerOptions compilerOptions, ContributionBinding binding) { 78 // We only give the exemption to multibound map contributions. 79 if (!binding.contributionType().equals(ContributionType.MAP)) { 80 return false; 81 } 82 return !compilerOptions.strictMultibindingValidation(); 83 } 84 85 private final InjectBindingRegistry injectBindingRegistry; 86 private final KeyFactory keyFactory; 87 private final BindingFactory bindingFactory; 88 private final BindingNode.Factory bindingNodeFactory; 89 private final ComponentDeclarations.Factory componentDeclarationsFactory; 90 private final LegacyBindingGraphConverter legacyBindingGraphConverter; 91 private final CompilerOptions compilerOptions; 92 93 @Inject LegacyBindingGraphFactory( InjectBindingRegistry injectBindingRegistry, KeyFactory keyFactory, BindingFactory bindingFactory, BindingNode.Factory bindingNodeFactory, ComponentDeclarations.Factory componentDeclarationsFactory, LegacyBindingGraphConverter legacyBindingGraphConverter, CompilerOptions compilerOptions)94 LegacyBindingGraphFactory( 95 InjectBindingRegistry injectBindingRegistry, 96 KeyFactory keyFactory, 97 BindingFactory bindingFactory, 98 BindingNode.Factory bindingNodeFactory, 99 ComponentDeclarations.Factory componentDeclarationsFactory, 100 LegacyBindingGraphConverter legacyBindingGraphConverter, 101 CompilerOptions compilerOptions) { 102 this.injectBindingRegistry = injectBindingRegistry; 103 this.keyFactory = keyFactory; 104 this.bindingFactory = bindingFactory; 105 this.bindingNodeFactory = bindingNodeFactory; 106 this.componentDeclarationsFactory = componentDeclarationsFactory; 107 this.legacyBindingGraphConverter = legacyBindingGraphConverter; 108 this.compilerOptions = compilerOptions; 109 } 110 111 /** 112 * Creates a binding graph for a component. 113 * 114 * @param createFullBindingGraph if {@code true}, the binding graph will include all bindings; 115 * otherwise it will include only bindings reachable from at least one entry point 116 */ create( ComponentDescriptor componentDescriptor, boolean createFullBindingGraph)117 public BindingGraph create( 118 ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) { 119 return legacyBindingGraphConverter.convert( 120 createLegacyBindingGraph(Optional.empty(), componentDescriptor, createFullBindingGraph), 121 createFullBindingGraph); 122 } 123 createLegacyBindingGraph( Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor, boolean createFullBindingGraph)124 private LegacyBindingGraph createLegacyBindingGraph( 125 Optional<Resolver> parentResolver, 126 ComponentDescriptor componentDescriptor, 127 boolean createFullBindingGraph) { 128 Resolver requestResolver = new Resolver(parentResolver, componentDescriptor); 129 130 componentDescriptor.entryPointMethods().stream() 131 .map(method -> method.dependencyRequest().get()) 132 .forEach( 133 entryPoint -> { 134 if (entryPoint.kind().equals(MEMBERS_INJECTION)) { 135 requestResolver.resolveMembersInjection(entryPoint.key()); 136 } else { 137 requestResolver.resolve(entryPoint.key()); 138 } 139 }); 140 141 if (createFullBindingGraph) { 142 // Resolve the keys for all bindings in all modules, stripping any multibinding contribution 143 // identifier so that the multibinding itself is resolved. 144 requestResolver.declarations.allDeclarations().stream() 145 // TODO(b/349155899): Consider resolving all declarations in full binding graph mode, not 146 // just those from modules. 147 .filter(declaration -> declaration.contributingModule().isPresent()) 148 .map(Declaration::key) 149 .map(Key::withoutMultibindingContributionIdentifier) 150 .forEach(requestResolver::resolve); 151 } 152 153 // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have 154 // been detected during binding resolution. If a binding for a subcomponent is never resolved, 155 // no BindingGraph will be created for it and no implementation will be generated. This is 156 // done in a queue since resolving one subcomponent might resolve a key for a subcomponent 157 // from a parent graph. This is done until no more new subcomponents are resolved. 158 Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>(); 159 ImmutableList.Builder<LegacyBindingGraph> subgraphs = ImmutableList.builder(); 160 for (ComponentDescriptor subcomponent : 161 Iterables.consumingIterable(requestResolver.subcomponentsToResolve)) { 162 if (resolvedSubcomponents.add(subcomponent)) { 163 subgraphs.add( 164 createLegacyBindingGraph( 165 Optional.of(requestResolver), subcomponent, createFullBindingGraph)); 166 } 167 } 168 169 return new LegacyBindingGraph(requestResolver, subgraphs.build()); 170 } 171 172 /** Represents a fully resolved binding graph. */ 173 static final class LegacyBindingGraph { 174 private final Resolver resolver; 175 private final ImmutableList<LegacyBindingGraph> resolvedSubgraphs; 176 private final ComponentNode componentNode; 177 LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs)178 LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs) { 179 this.resolver = resolver; 180 this.resolvedSubgraphs = resolvedSubgraphs; 181 this.componentNode = 182 ComponentNodeImpl.create(resolver.componentPath, resolver.componentDescriptor); 183 } 184 185 /** Returns the {@link ComponentNode} associated with this binding graph. */ componentNode()186 public ComponentNode componentNode() { 187 return componentNode; 188 } 189 190 /** Returns the {@link ComponentPath} associated with this binding graph. */ componentPath()191 public ComponentPath componentPath() { 192 return resolver.componentPath; 193 } 194 195 /** Returns the {@link ComponentDescriptor} associated with this binding graph. */ componentDescriptor()196 public ComponentDescriptor componentDescriptor() { 197 return resolver.componentDescriptor; 198 } 199 200 /** 201 * Returns the {@link LegacyResolvedBindings} in this graph or a parent graph that matches the 202 * given request. 203 * 204 * <p>An exception is thrown if there are no resolved bindings found for the request; however, 205 * this should never happen since all dependencies should have been resolved at this point. 206 */ resolvedBindings(BindingRequest request)207 public LegacyResolvedBindings resolvedBindings(BindingRequest request) { 208 return request.isRequestKind(RequestKind.MEMBERS_INJECTION) 209 ? resolver.getResolvedMembersInjectionBindings(request.key()) 210 : resolver.getResolvedContributionBindings(request.key()); 211 } 212 213 /** 214 * Returns all {@link LegacyResolvedBindings} for the given request. 215 * 216 * <p>Note that this only returns the bindings resolved in this component. Bindings resolved in 217 * parent components are not included. 218 */ resolvedBindings()219 public Iterable<LegacyResolvedBindings> resolvedBindings() { 220 // Don't return an immutable collection - this is only ever used for looping over all bindings 221 // in the graph. Copying is wasteful, especially if is a hashing collection, since the values 222 // should all, by definition, be distinct. 223 return Iterables.concat( 224 resolver.resolvedMembersInjectionBindings.values(), 225 resolver.resolvedContributionBindings.values()); 226 } 227 228 /** Returns the resolved subgraphs. */ subgraphs()229 public ImmutableList<LegacyBindingGraph> subgraphs() { 230 return resolvedSubgraphs; 231 } 232 } 233 234 /** 235 * The collection of bindings that have been resolved for a key. For valid graphs, contains 236 * exactly one binding. 237 * 238 * <p>Separate {@link LegacyResolvedBindings} instances should be used if a {@link 239 * MembersInjectionBinding} and a {@link ProvisionBinding} for the same key exist in the same 240 * component. (This will only happen if a type has an {@code @Inject} constructor and members, the 241 * component has a members injection method, and the type is also requested normally.) 242 */ 243 @AutoValue 244 abstract static class LegacyResolvedBindings { 245 /** 246 * Creates a {@link LegacyResolvedBindings} appropriate for when there are no bindings for a 247 * key. 248 */ create(Key key)249 static LegacyResolvedBindings create(Key key) { 250 return create(key, ImmutableSet.of()); 251 } 252 253 /** Creates a {@link LegacyResolvedBindings} for a single binding. */ create(Key key, BindingNode bindingNode)254 static LegacyResolvedBindings create(Key key, BindingNode bindingNode) { 255 return create(key, ImmutableSet.of(bindingNode)); 256 } 257 258 /** Creates a {@link LegacyResolvedBindings} for multiple bindings. */ create(Key key, ImmutableSet<BindingNode> bindingNodes)259 static LegacyResolvedBindings create(Key key, ImmutableSet<BindingNode> bindingNodes) { 260 return new AutoValue_LegacyBindingGraphFactory_LegacyResolvedBindings(key, bindingNodes); 261 } 262 263 /** The binding key for which the {@link #bindings()} have been resolved. */ key()264 abstract Key key(); 265 266 /** All binding nodes for {@link #key()}, regardless of which component owns them. */ bindingNodes()267 abstract ImmutableSet<BindingNode> bindingNodes(); 268 269 // Computing the hash code is an expensive operation. 270 @Memoized 271 @Override hashCode()272 public abstract int hashCode(); 273 274 // Suppresses ErrorProne warning that hashCode was overridden w/o equals 275 @Override equals(Object other)276 public abstract boolean equals(Object other); 277 278 /** All bindings for {@link #key()}, regardless of which component owns them. */ bindings()279 final ImmutableSet<Binding> bindings() { 280 return bindingNodes().stream() 281 .map(BindingNode::delegate) 282 .collect(toImmutableSet()); 283 } 284 285 /** Returns {@code true} if there are no {@link #bindings()}. */ isEmpty()286 final boolean isEmpty() { 287 return bindingNodes().isEmpty(); 288 } 289 290 /** All bindings for {@link #key()} that are owned by a component. */ bindingNodesOwnedBy(ComponentPath componentPath)291 ImmutableSet<BindingNode> bindingNodesOwnedBy(ComponentPath componentPath) { 292 return bindingNodes().stream() 293 .filter(bindingNode -> bindingNode.componentPath().equals(componentPath)) 294 .collect(toImmutableSet()); 295 } 296 297 /** Returns the binding node representing the given binding, or throws ISE if none exist. */ forBinding(Binding binding)298 final BindingNode forBinding(Binding binding) { 299 return bindingNodes().stream() 300 .filter(bindingNode -> bindingNode.delegate().equals(binding)) 301 .collect(onlyElement()); 302 } 303 } 304 305 private final class Resolver { 306 final ComponentPath componentPath; 307 final Optional<Resolver> parentResolver; 308 final ComponentDescriptor componentDescriptor; 309 final ComponentDeclarations declarations; 310 final Map<Key, LegacyResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>(); 311 final Map<Key, LegacyResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>(); 312 final Deque<Key> cycleStack = new ArrayDeque<>(); 313 final Map<Key, Boolean> keyDependsOnLocalBindingsCache = new HashMap<>(); 314 final Map<Binding, Boolean> bindingDependsOnLocalBindingsCache = new HashMap<>(); 315 final Queue<ComponentDescriptor> subcomponentsToResolve = new ArrayDeque<>(); 316 Resolver(Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor)317 Resolver(Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) { 318 this.parentResolver = parentResolver; 319 this.componentDescriptor = checkNotNull(componentDescriptor); 320 DaggerTypeElement componentType = DaggerTypeElement.from(componentDescriptor.typeElement()); 321 componentPath = 322 parentResolver.isPresent() 323 ? parentResolver.get().componentPath.childPath(componentType) 324 : ComponentPath.create(ImmutableList.of(componentType)); 325 declarations = 326 componentDeclarationsFactory.create( 327 parentResolver.map(parent -> parent.componentDescriptor), 328 componentDescriptor); 329 subcomponentsToResolve.addAll( 330 componentDescriptor.childComponentsDeclaredByFactoryMethods().values()); 331 subcomponentsToResolve.addAll( 332 componentDescriptor.childComponentsDeclaredByBuilderEntryPoints().values()); 333 } 334 335 /** 336 * Returns the resolved contribution bindings for the given {@link Key}: 337 * 338 * <ul> 339 * <li>All explicit bindings for: 340 * <ul> 341 * <li>the requested key 342 * <li>{@code Set<T>} if the requested key's type is {@code Set<Produced<T>>} 343 * <li>{@code Map<K, Provider<V>>} if the requested key's type is {@code Map<K, 344 * Producer<V>>}. 345 * </ul> 346 * <li>An implicit {@link Inject @Inject}-annotated constructor binding if there is one and 347 * there are no explicit bindings or synthetic bindings. 348 * </ul> 349 */ lookUpBindings(Key requestKey)350 LegacyResolvedBindings lookUpBindings(Key requestKey) { 351 Set<ContributionBinding> bindings = new LinkedHashSet<>(); 352 Set<ContributionBinding> multibindingContributions = new LinkedHashSet<>(); 353 Set<MultibindingDeclaration> multibindingDeclarations = new LinkedHashSet<>(); 354 Set<OptionalBindingDeclaration> optionalBindingDeclarations = new LinkedHashSet<>(); 355 Set<SubcomponentDeclaration> subcomponentDeclarations = new LinkedHashSet<>(); 356 357 // Gather all bindings, multibindings, optional, and subcomponent declarations/contributions. 358 for (Resolver resolver : getResolverLineage()) { 359 bindings.addAll(resolver.getLocalExplicitBindings(requestKey)); 360 multibindingContributions.addAll(resolver.getLocalMultibindingContributions(requestKey)); 361 multibindingDeclarations.addAll(resolver.declarations.multibindings(requestKey)); 362 subcomponentDeclarations.addAll(resolver.declarations.subcomponents(requestKey)); 363 // The optional binding declarations are keyed by the unwrapped type. 364 keyFactory.unwrapOptional(requestKey) 365 .map(resolver.declarations::optionalBindings) 366 .ifPresent(optionalBindingDeclarations::addAll); 367 } 368 369 // Add synthetic multibinding 370 if (!multibindingContributions.isEmpty() || !multibindingDeclarations.isEmpty()) { 371 if (MapType.isMap(requestKey)) { 372 bindings.add(bindingFactory.multiboundMap(requestKey, multibindingContributions)); 373 } else if (SetType.isSet(requestKey)) { 374 bindings.add(bindingFactory.multiboundSet(requestKey, multibindingContributions)); 375 } else { 376 throw new AssertionError("Unexpected type in multibinding key: " + requestKey); 377 } 378 } 379 380 // Add synthetic optional binding 381 if (!optionalBindingDeclarations.isEmpty()) { 382 ImmutableSet<Binding> optionalContributions = 383 lookUpBindings(keyFactory.unwrapOptional(requestKey).get()).bindings(); 384 bindings.add( 385 optionalContributions.isEmpty() 386 ? bindingFactory.syntheticAbsentOptionalDeclaration(requestKey) 387 : bindingFactory.syntheticPresentOptionalDeclaration( 388 requestKey, optionalContributions)); 389 } 390 391 // Add subcomponent creator binding 392 if (!subcomponentDeclarations.isEmpty()) { 393 ContributionBinding binding = 394 bindingFactory.subcomponentCreatorBinding( 395 ImmutableSet.copyOf(subcomponentDeclarations)); 396 bindings.add(binding); 397 addSubcomponentToOwningResolver(binding); 398 } 399 400 // Add members injector binding 401 if (isTypeOf(requestKey.type().xprocessing(), TypeNames.MEMBERS_INJECTOR)) { 402 injectBindingRegistry.getOrFindMembersInjectorBinding(requestKey).ifPresent(bindings::add); 403 } 404 405 // Add Assisted Factory binding 406 if (isDeclared(requestKey.type().xprocessing()) 407 && isAssistedFactoryType(requestKey.type().xprocessing().getTypeElement())) { 408 bindings.add( 409 bindingFactory.assistedFactoryBinding( 410 requestKey.type().xprocessing().getTypeElement(), 411 Optional.of(requestKey.type().xprocessing()))); 412 } 413 414 // If there are no bindings, add the implicit @Inject-constructed binding if there is one. 415 if (bindings.isEmpty()) { 416 injectBindingRegistry 417 .getOrFindInjectionBinding(requestKey) 418 .filter(this::isCorrectlyScopedInSubcomponent) 419 .ifPresent(bindings::add); 420 } 421 422 return LegacyResolvedBindings.create( 423 requestKey, 424 bindings.stream() 425 .map( 426 binding -> { 427 Optional<BindingNode> bindingNodeOwnedByAncestor = 428 getBindingNodeOwnedByAncestor(requestKey, binding); 429 // If a binding is owned by an ancestor we use the corresponding BindingNode 430 // instance directly rather than creating a new instance to avoid accidentally 431 // including additional multi/optional/subcomponent declarations that don't 432 // exist in the ancestor's BindingNode instance. 433 return bindingNodeOwnedByAncestor.isPresent() 434 ? bindingNodeOwnedByAncestor.get() 435 : bindingNodeFactory.forContributionBindings( 436 componentPath, 437 binding, 438 multibindingDeclarations, 439 optionalBindingDeclarations, 440 subcomponentDeclarations); 441 }) 442 .collect(toImmutableSet())); 443 } 444 445 /** 446 * Returns true if this binding graph resolution is for a subcomponent and the {@code @Inject} 447 * binding's scope correctly matches one of the components in the current component ancestry. 448 * If not, it means the binding is not owned by any of the currently known components, and will 449 * be owned by a future ancestor (or, if never owned, will result in an incompatibly scoped 450 * binding error at the root component). 451 */ isCorrectlyScopedInSubcomponent(ContributionBinding binding)452 private boolean isCorrectlyScopedInSubcomponent(ContributionBinding binding) { 453 checkArgument(binding.kind() == INJECTION || binding.kind() == ASSISTED_INJECTION); 454 if (!rootComponent().isSubcomponent() 455 || !binding.scope().isPresent() 456 || binding.scope().get().isReusable()) { 457 return true; 458 } 459 460 Resolver owningResolver = getOwningResolver(binding).orElse(this); 461 ComponentDescriptor owningComponent = owningResolver.componentDescriptor; 462 return owningComponent.scopes().contains(binding.scope().get()); 463 } 464 rootComponent()465 private ComponentDescriptor rootComponent() { 466 return parentResolver.map(Resolver::rootComponent).orElse(componentDescriptor); 467 } 468 469 /** Returns the resolved members injection bindings for the given {@link Key}. */ lookUpMembersInjectionBinding(Key requestKey)470 LegacyResolvedBindings lookUpMembersInjectionBinding(Key requestKey) { 471 // no explicit deps for members injection, so just look it up 472 Optional<MembersInjectionBinding> binding = 473 injectBindingRegistry.getOrFindMembersInjectionBinding(requestKey); 474 return binding.isPresent() 475 ? LegacyResolvedBindings.create( 476 requestKey, 477 bindingNodeFactory.forMembersInjectionBinding(componentPath, binding.get())) 478 : LegacyResolvedBindings.create(requestKey); 479 } 480 481 /** 482 * When a binding is resolved for a {@link SubcomponentDeclaration}, adds corresponding {@link 483 * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue 484 * will be used to detect which subcomponents need to be resolved. 485 */ addSubcomponentToOwningResolver(ContributionBinding subcomponentCreatorBinding)486 private void addSubcomponentToOwningResolver(ContributionBinding subcomponentCreatorBinding) { 487 checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR)); 488 Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get(); 489 490 XTypeElement builderType = 491 subcomponentCreatorBinding.key().type().xprocessing().getTypeElement(); 492 owningResolver.subcomponentsToResolve.add( 493 owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType)); 494 } 495 createDelegateBindings( ImmutableSet<DelegateDeclaration> delegateDeclarations)496 private ImmutableSet<ContributionBinding> createDelegateBindings( 497 ImmutableSet<DelegateDeclaration> delegateDeclarations) { 498 ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder(); 499 for (DelegateDeclaration delegateDeclaration : delegateDeclarations) { 500 builder.add(createDelegateBinding(delegateDeclaration)); 501 } 502 return builder.build(); 503 } 504 505 /** 506 * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved 507 * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate 508 * bindings for the dependency key, there should still be only one binding for the delegate key. 509 */ createDelegateBinding(DelegateDeclaration delegateDeclaration)510 private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) { 511 Key delegateKey = delegateDeclaration.delegateRequest().key(); 512 if (cycleStack.contains(delegateKey)) { 513 return bindingFactory.unresolvedDelegateBinding(delegateDeclaration); 514 } 515 516 LegacyResolvedBindings resolvedDelegate; 517 try { 518 cycleStack.push(delegateKey); 519 resolvedDelegate = lookUpBindings(delegateKey); 520 } finally { 521 cycleStack.pop(); 522 } 523 if (resolvedDelegate.bindings().isEmpty()) { 524 // This is guaranteed to result in a missing binding error, so it doesn't matter if the 525 // binding is a Provision or Production, except if it is a @IntoMap method, in which 526 // case the key will be of type Map<K, Provider<V>>, which will be "upgraded" into a 527 // Map<K, Producer<V>> if it's requested in a ProductionComponent. This may result in a 528 // strange error, that the RHS needs to be provided with an @Inject or @Provides 529 // annotated method, but a user should be able to figure out if a @Produces annotation 530 // is needed. 531 // TODO(gak): revisit how we model missing delegates if/when we clean up how we model 532 // binding declarations 533 return bindingFactory.unresolvedDelegateBinding(delegateDeclaration); 534 } 535 // It doesn't matter which of these is selected, since they will later on produce a 536 // duplicate binding error. 537 ContributionBinding explicitDelegate = 538 (ContributionBinding) resolvedDelegate.bindings().iterator().next(); 539 return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate); 540 } 541 542 /** 543 * Returns a {@link BindingNode} for the given binding that is owned by an ancestor component, 544 * if one exists. Otherwise returns {@link Optional#empty()}. 545 */ getBindingNodeOwnedByAncestor( Key requestKey, ContributionBinding binding)546 private Optional<BindingNode> getBindingNodeOwnedByAncestor( 547 Key requestKey, ContributionBinding binding) { 548 if (canBeResolvedInParent(requestKey, binding)) { 549 // Resolve in the parent to make sure we have the most recent multi/optional contributions. 550 parentResolver.get().resolve(requestKey); 551 if (!requiresResolution(binding)) { 552 return Optional.of(getPreviouslyResolvedBindings(requestKey).get().forBinding(binding)); 553 } 554 } 555 return Optional.empty(); 556 } 557 canBeResolvedInParent(Key requestKey, ContributionBinding binding)558 private boolean canBeResolvedInParent(Key requestKey, ContributionBinding binding) { 559 if (parentResolver.isEmpty()) { 560 return false; 561 } 562 Optional<Resolver> owningResolver = getOwningResolver(binding); 563 if (owningResolver.isPresent()) { 564 return !owningResolver.get().equals(this); 565 } 566 return !Keys.isComponentOrCreator(requestKey) 567 // TODO(b/305748522): Allow caching for assisted injection bindings. 568 && binding.kind() != BindingKind.ASSISTED_INJECTION 569 && getPreviouslyResolvedBindings(requestKey).isPresent() 570 && getPreviouslyResolvedBindings(requestKey).get().bindings().contains(binding); 571 } 572 getOwningResolver(ContributionBinding binding)573 private Optional<Resolver> getOwningResolver(ContributionBinding binding) { 574 // TODO(ronshapiro): extract the different pieces of this method into their own methods 575 if ((binding.scope().isPresent() && binding.scope().get().isProductionScope()) 576 || binding.kind().equals(BindingKind.PRODUCTION)) { 577 for (Resolver requestResolver : getResolverLineage()) { 578 // Resolve @Inject @ProductionScope bindings at the highest production component. 579 if (binding.kind().equals(INJECTION) 580 && requestResolver.componentDescriptor.isProduction()) { 581 return Optional.of(requestResolver); 582 } 583 584 // Resolve explicit @Produces and @ProductionScope bindings at the highest component that 585 // installs the binding. 586 if (requestResolver.containsExplicitBinding(binding)) { 587 return Optional.of(requestResolver); 588 } 589 } 590 } 591 592 if (binding.scope().isPresent() && binding.scope().get().isReusable()) { 593 for (Resolver requestResolver : getResolverLineage().reverse()) { 594 // If a @Reusable binding was resolved in an ancestor, use that component. 595 LegacyResolvedBindings resolvedBindings = 596 requestResolver.resolvedContributionBindings.get(binding.key()); 597 if (resolvedBindings != null && resolvedBindings.bindings().contains(binding)) { 598 return Optional.of(requestResolver); 599 } 600 } 601 // If a @Reusable binding was not resolved in any ancestor, resolve it here. 602 return Optional.empty(); 603 } 604 605 // TODO(b/359893922): we currently iterate from child to parent to find an owning resolver, 606 // but we probably want to iterate from parent to child to catch missing bindings in 607 // misconfigured repeated modules. 608 for (Resolver requestResolver : getResolverLineage().reverse()) { 609 if (requestResolver.containsExplicitBinding(binding)) { 610 return Optional.of(requestResolver); 611 } 612 } 613 614 // look for scope separately. we do this for the case where @Singleton can appear twice 615 // in the † compatibility mode 616 Optional<Scope> bindingScope = binding.scope(); 617 if (bindingScope.isPresent()) { 618 for (Resolver requestResolver : getResolverLineage().reverse()) { 619 if (requestResolver.componentDescriptor.scopes().contains(bindingScope.get())) { 620 return Optional.of(requestResolver); 621 } 622 } 623 } 624 return Optional.empty(); 625 } 626 containsExplicitBinding(ContributionBinding binding)627 private boolean containsExplicitBinding(ContributionBinding binding) { 628 return declarations.bindings(binding.key()).contains(binding) 629 || resolverContainsDelegateDeclarationForBinding(binding) 630 || !declarations.subcomponents(binding.key()).isEmpty(); 631 } 632 633 /** Returns true if {@code binding} was installed in a module in this resolver's component. */ resolverContainsDelegateDeclarationForBinding(ContributionBinding binding)634 private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) { 635 if (!binding.kind().equals(DELEGATE)) { 636 return false; 637 } 638 if (hasStrictMultibindingsExemption(compilerOptions, binding)) { 639 return false; 640 } 641 return declarations.delegates(binding.key()).stream() 642 .anyMatch( 643 declaration -> 644 declaration.contributingModule().equals(binding.contributingModule()) 645 && declaration.bindingElement().equals(binding.bindingElement())); 646 } 647 648 /** Returns the resolver lineage from parent to child. */ getResolverLineage()649 private ImmutableList<Resolver> getResolverLineage() { 650 ImmutableList.Builder<Resolver> resolverList = ImmutableList.builder(); 651 for (Optional<Resolver> currentResolver = Optional.of(this); 652 currentResolver.isPresent(); 653 currentResolver = currentResolver.get().parentResolver) { 654 resolverList.add(currentResolver.get()); 655 } 656 return resolverList.build().reverse(); 657 } 658 659 /** 660 * Returns the explicit {@link ContributionBinding}s that match the {@code key} from this 661 * resolver. 662 */ getLocalExplicitBindings(Key key)663 private ImmutableSet<ContributionBinding> getLocalExplicitBindings(Key key) { 664 return ImmutableSet.<ContributionBinding>builder() 665 .addAll(declarations.bindings(key)) 666 .addAll(createDelegateBindings(declarations.delegates(key))) 667 .build(); 668 } 669 670 /** 671 * Returns the explicit multibinding contributions that contribute to the map or set requested 672 * by {@code key} from this resolver. 673 */ getLocalMultibindingContributions(Key key)674 private ImmutableSet<ContributionBinding> getLocalMultibindingContributions(Key key) { 675 return ImmutableSet.<ContributionBinding>builder() 676 .addAll(declarations.multibindingContributions(key)) 677 .addAll(createDelegateBindings(declarations.delegateMultibindingContributions(key))) 678 .build(); 679 } 680 681 /** 682 * Returns the {@link OptionalBindingDeclaration}s that match the {@code key} from this and all 683 * ancestor resolvers. 684 */ getOptionalBindingDeclarations(Key key)685 private ImmutableSet<OptionalBindingDeclaration> getOptionalBindingDeclarations(Key key) { 686 Optional<Key> unwrapped = keyFactory.unwrapOptional(key); 687 if (unwrapped.isEmpty()) { 688 return ImmutableSet.of(); 689 } 690 ImmutableSet.Builder<OptionalBindingDeclaration> declarations = ImmutableSet.builder(); 691 for (Resolver resolver : getResolverLineage()) { 692 declarations.addAll(resolver.declarations.optionalBindings(unwrapped.get())); 693 } 694 return declarations.build(); 695 } 696 697 /** 698 * Returns the {@link LegacyResolvedBindings} for {@code key} that was resolved in this resolver 699 * or an ancestor resolver. Only checks for {@link ContributionBinding}s as {@link 700 * MembersInjectionBinding}s are not inherited. 701 */ getPreviouslyResolvedBindings(Key key)702 private Optional<LegacyResolvedBindings> getPreviouslyResolvedBindings(Key key) { 703 Optional<LegacyResolvedBindings> result = 704 Optional.ofNullable(resolvedContributionBindings.get(key)); 705 if (result.isPresent()) { 706 return result; 707 } else if (parentResolver.isPresent()) { 708 return parentResolver.get().getPreviouslyResolvedBindings(key); 709 } else { 710 return Optional.empty(); 711 } 712 } 713 resolveMembersInjection(Key key)714 private void resolveMembersInjection(Key key) { 715 LegacyResolvedBindings bindings = lookUpMembersInjectionBinding(key); 716 resolveDependencies(bindings); 717 resolvedMembersInjectionBindings.put(key, bindings); 718 } 719 resolve(Key key)720 void resolve(Key key) { 721 // If we find a cycle, stop resolving. The original request will add it with all of the 722 // other resolved deps. 723 if (cycleStack.contains(key)) { 724 return; 725 } 726 727 // If the binding was previously resolved in this (sub)component, don't resolve it again. 728 if (resolvedContributionBindings.containsKey(key)) { 729 return; 730 } 731 732 cycleStack.push(key); 733 try { 734 LegacyResolvedBindings bindings = lookUpBindings(key); 735 resolvedContributionBindings.put(key, bindings); 736 resolveDependencies(bindings); 737 } finally { 738 cycleStack.pop(); 739 } 740 } 741 742 /** 743 * {@link #resolve(Key) Resolves} each of the dependencies of the bindings owned by this 744 * component. 745 */ resolveDependencies(LegacyResolvedBindings resolvedBindings)746 private void resolveDependencies(LegacyResolvedBindings resolvedBindings) { 747 for (BindingNode binding : resolvedBindings.bindingNodesOwnedBy(componentPath)) { 748 for (DependencyRequest dependency : binding.dependencies()) { 749 resolve(dependency.key()); 750 } 751 } 752 } 753 getResolvedContributionBindings(Key key)754 private LegacyResolvedBindings getResolvedContributionBindings(Key key) { 755 if (resolvedContributionBindings.containsKey(key)) { 756 return resolvedContributionBindings.get(key); 757 } 758 if (parentResolver.isPresent()) { 759 return parentResolver.get().getResolvedContributionBindings(key); 760 } 761 throw new AssertionError("No resolved bindings for key: " + key); 762 } 763 getResolvedMembersInjectionBindings(Key key)764 private LegacyResolvedBindings getResolvedMembersInjectionBindings(Key key) { 765 return resolvedMembersInjectionBindings.get(key); 766 } 767 requiresResolution(Binding binding)768 private boolean requiresResolution(Binding binding) { 769 return new RequiresResolutionChecker().requiresResolution(binding); 770 } 771 772 private final class RequiresResolutionChecker { 773 private final Set<Object> cycleChecker = new HashSet<>(); 774 775 /** 776 * Returns {@code true} if any of the bindings resolved for {@code key} are multibindings with 777 * contributions declared within this component's modules or optional bindings with present 778 * values declared within this component's modules, or if any of its unscoped dependencies 779 * depend on such bindings. 780 * 781 * <p>We don't care about scoped dependencies because they will never depend on bindings from 782 * subcomponents. 783 * 784 * @throws IllegalArgumentException if {@link #getPreviouslyResolvedBindings(Key)} is empty 785 */ requiresResolution(Key key)786 private boolean requiresResolution(Key key) { 787 // Don't recur infinitely if there are valid cycles in the dependency graph. 788 // http://b/23032377 789 if (!cycleChecker.add(key)) { 790 return false; 791 } 792 return reentrantComputeIfAbsent( 793 keyDependsOnLocalBindingsCache, key, this::requiresResolutionUncached); 794 } 795 796 /** 797 * Returns {@code true} if {@code binding} is unscoped (or has {@link Reusable @Reusable} 798 * scope) and depends on multibindings with contributions declared within this component's 799 * modules, or if any of its unscoped or {@link Reusable @Reusable} scoped dependencies depend 800 * on such local multibindings. 801 * 802 * <p>We don't care about non-reusable scoped dependencies because they will never depend on 803 * multibindings with contributions from subcomponents. 804 */ requiresResolution(Binding binding)805 private boolean requiresResolution(Binding binding) { 806 if (!cycleChecker.add(binding)) { 807 return false; 808 } 809 return reentrantComputeIfAbsent( 810 bindingDependsOnLocalBindingsCache, binding, this::requiresResolutionUncached); 811 } 812 requiresResolutionUncached(Key key)813 private boolean requiresResolutionUncached(Key key) { 814 checkArgument( 815 getPreviouslyResolvedBindings(key).isPresent(), 816 "no previously resolved bindings in %s for %s", 817 Resolver.this, 818 key); 819 LegacyResolvedBindings previouslyResolvedBindings = 820 getPreviouslyResolvedBindings(key).get(); 821 if (hasLocalBindings(previouslyResolvedBindings)) { 822 return true; 823 } 824 825 for (Binding binding : previouslyResolvedBindings.bindings()) { 826 if (requiresResolution(binding)) { 827 return true; 828 } 829 } 830 return false; 831 } 832 requiresResolutionUncached(Binding binding)833 private boolean requiresResolutionUncached(Binding binding) { 834 if ((!binding.scope().isPresent() || binding.scope().get().isReusable()) 835 // TODO(beder): Figure out what happens with production subcomponents. 836 && !binding.kind().equals(BindingKind.PRODUCTION)) { 837 for (DependencyRequest dependency : binding.dependencies()) { 838 if (requiresResolution(dependency.key())) { 839 return true; 840 } 841 } 842 } 843 return false; 844 } 845 } 846 hasLocalBindings(LegacyResolvedBindings resolvedBindings)847 private boolean hasLocalBindings(LegacyResolvedBindings resolvedBindings) { 848 return hasLocalMultibindingContributions(resolvedBindings.key()) 849 || hasLocalOptionalBindingContribution(resolvedBindings); 850 } 851 852 /** 853 * Returns {@code true} if there is at least one multibinding contribution declared within 854 * this component's modules that matches the key. 855 */ hasLocalMultibindingContributions(Key requestKey)856 private boolean hasLocalMultibindingContributions(Key requestKey) { 857 return !declarations.multibindingContributions(requestKey).isEmpty() 858 || !declarations.delegateMultibindingContributions(requestKey).isEmpty(); 859 } 860 861 /** 862 * Returns {@code true} if there is a contribution in this component for an {@code 863 * Optional<Foo>} key that has not been contributed in a parent. 864 */ hasLocalOptionalBindingContribution(LegacyResolvedBindings resolvedBindings)865 private boolean hasLocalOptionalBindingContribution(LegacyResolvedBindings resolvedBindings) { 866 return hasLocalOptionalBindingContribution( 867 resolvedBindings.key(), resolvedBindings.bindings()); 868 } 869 hasLocalOptionalBindingContribution( Key key, ImmutableSet<? extends Binding> previouslyResolvedBindings)870 private boolean hasLocalOptionalBindingContribution( 871 Key key, ImmutableSet<? extends Binding> previouslyResolvedBindings) { 872 if (previouslyResolvedBindings.stream() 873 .map(Binding::kind) 874 .anyMatch(isEqual(OPTIONAL))) { 875 return hasLocalExplicitBindings(keyFactory.unwrapOptional(key).get()); 876 } else { 877 // If a parent contributes a @Provides Optional<Foo> binding and a child has a 878 // @BindsOptionalOf Foo method, the two should conflict, even if there is no binding for 879 // Foo on its own 880 return !getOptionalBindingDeclarations(key).isEmpty(); 881 } 882 } 883 884 /** 885 * Returns {@code true} if there is at least one explicit binding that matches the given key. 886 */ hasLocalExplicitBindings(Key requestKey)887 private boolean hasLocalExplicitBindings(Key requestKey) { 888 return !declarations.bindings(requestKey).isEmpty() 889 || !declarations.delegates(requestKey).isEmpty(); 890 } 891 } 892 } 893