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.RequestKinds.getRequestKind; 22 import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent; 23 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType; 24 import static dagger.internal.codegen.binding.SourceFiles.generatedMonitoringModuleName; 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.XElements.getSimpleName; 32 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; 33 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf; 34 import static java.util.function.Predicate.isEqual; 35 36 import androidx.room.compiler.processing.XProcessingEnv; 37 import androidx.room.compiler.processing.XTypeElement; 38 import com.google.common.collect.HashMultimap; 39 import com.google.common.collect.ImmutableList; 40 import com.google.common.collect.ImmutableSet; 41 import com.google.common.collect.ImmutableSetMultimap; 42 import com.google.common.collect.Iterables; 43 import com.google.common.collect.Multimaps; 44 import dagger.Reusable; 45 import dagger.internal.codegen.base.ClearableCache; 46 import dagger.internal.codegen.base.ContributionType; 47 import dagger.internal.codegen.base.DaggerSuperficialValidation; 48 import dagger.internal.codegen.base.Keys; 49 import dagger.internal.codegen.base.MapType; 50 import dagger.internal.codegen.base.OptionalType; 51 import dagger.internal.codegen.compileroption.CompilerOptions; 52 import dagger.internal.codegen.javapoet.TypeNames; 53 import dagger.internal.codegen.model.BindingGraph.ComponentNode; 54 import dagger.internal.codegen.model.BindingKind; 55 import dagger.internal.codegen.model.ComponentPath; 56 import dagger.internal.codegen.model.DaggerTypeElement; 57 import dagger.internal.codegen.model.DependencyRequest; 58 import dagger.internal.codegen.model.Key; 59 import dagger.internal.codegen.model.RequestKind; 60 import dagger.internal.codegen.model.Scope; 61 import dagger.internal.codegen.xprocessing.XTypeElements; 62 import java.util.ArrayDeque; 63 import java.util.Deque; 64 import java.util.HashMap; 65 import java.util.HashSet; 66 import java.util.LinkedHashMap; 67 import java.util.LinkedHashSet; 68 import java.util.Map; 69 import java.util.Optional; 70 import java.util.Queue; 71 import java.util.Set; 72 import javax.inject.Inject; 73 import javax.inject.Singleton; 74 75 /** A factory for {@link BindingGraph} objects. */ 76 @Singleton 77 public final class BindingGraphFactory implements ClearableCache { 78 79 private final XProcessingEnv processingEnv; 80 private final InjectBindingRegistry injectBindingRegistry; 81 private final KeyFactory keyFactory; 82 private final BindingFactory bindingFactory; 83 private final ModuleDescriptor.Factory moduleDescriptorFactory; 84 private final BindingGraphConverter bindingGraphConverter; 85 private final Map<Key, ImmutableSet<Key>> keysMatchingRequestCache = new HashMap<>(); 86 private final CompilerOptions compilerOptions; 87 88 @Inject BindingGraphFactory( XProcessingEnv processingEnv, InjectBindingRegistry injectBindingRegistry, KeyFactory keyFactory, BindingFactory bindingFactory, ModuleDescriptor.Factory moduleDescriptorFactory, BindingGraphConverter bindingGraphConverter, CompilerOptions compilerOptions)89 BindingGraphFactory( 90 XProcessingEnv processingEnv, 91 InjectBindingRegistry injectBindingRegistry, 92 KeyFactory keyFactory, 93 BindingFactory bindingFactory, 94 ModuleDescriptor.Factory moduleDescriptorFactory, 95 BindingGraphConverter bindingGraphConverter, 96 CompilerOptions compilerOptions) { 97 this.processingEnv = processingEnv; 98 this.injectBindingRegistry = injectBindingRegistry; 99 this.keyFactory = keyFactory; 100 this.bindingFactory = bindingFactory; 101 this.moduleDescriptorFactory = moduleDescriptorFactory; 102 this.bindingGraphConverter = bindingGraphConverter; 103 this.compilerOptions = compilerOptions; 104 } 105 106 /** 107 * Creates a binding graph for a component. 108 * 109 * @param createFullBindingGraph if {@code true}, the binding graph will include all bindings; 110 * otherwise it will include only bindings reachable from at least one entry point 111 */ create( ComponentDescriptor componentDescriptor, boolean createFullBindingGraph)112 public BindingGraph create( 113 ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) { 114 return bindingGraphConverter.convert( 115 createLegacyBindingGraph(Optional.empty(), componentDescriptor, createFullBindingGraph), 116 createFullBindingGraph); 117 } 118 createLegacyBindingGraph( Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor, boolean createFullBindingGraph)119 private LegacyBindingGraph createLegacyBindingGraph( 120 Optional<Resolver> parentResolver, 121 ComponentDescriptor componentDescriptor, 122 boolean createFullBindingGraph) { 123 ImmutableSet.Builder<ContributionBinding> explicitBindingsBuilder = ImmutableSet.builder(); 124 ImmutableSet.Builder<DelegateDeclaration> delegatesBuilder = ImmutableSet.builder(); 125 ImmutableSet.Builder<OptionalBindingDeclaration> optionalsBuilder = ImmutableSet.builder(); 126 127 if (componentDescriptor.isRealComponent()) { 128 // binding for the component itself 129 explicitBindingsBuilder.add( 130 bindingFactory.componentBinding(componentDescriptor.typeElement())); 131 } 132 133 // Collect Component dependencies. 134 for (ComponentRequirement dependency : componentDescriptor.dependencies()) { 135 explicitBindingsBuilder.add(bindingFactory.componentDependencyBinding(dependency)); 136 137 // Within a component dependency, we want to allow the same method to appear multiple 138 // times assuming it is the exact same method. We do this by tracking a set of bindings 139 // we've already added with the binding element removed since that is the only thing 140 // allowed to differ. 141 HashMultimap<String, ContributionBinding> dedupeBindings = HashMultimap.create(); 142 XTypeElements.getAllMethods(dependency.typeElement()).stream() 143 // MembersInjection methods aren't "provided" explicitly, so ignore them. 144 .filter(ComponentDescriptor::isComponentContributionMethod) 145 .forEach( 146 method -> { 147 ContributionBinding binding = 148 bindingFactory.componentDependencyMethodBinding(componentDescriptor, method); 149 if (dedupeBindings.put( 150 getSimpleName(method), 151 // Remove the binding element since we know that will be different, but 152 // everything else we want to be the same to consider it a duplicate. 153 binding.toBuilder().clearBindingElement().build())) { 154 explicitBindingsBuilder.add(binding); 155 } 156 }); 157 } 158 159 // Collect bindings on the creator. 160 componentDescriptor 161 .creatorDescriptor() 162 .ifPresent( 163 creatorDescriptor -> 164 creatorDescriptor.boundInstanceRequirements().stream() 165 .map( 166 requirement -> 167 bindingFactory.boundInstanceBinding( 168 requirement, creatorDescriptor.elementForRequirement(requirement))) 169 .forEach(explicitBindingsBuilder::add)); 170 171 componentDescriptor 172 .childComponentsDeclaredByBuilderEntryPoints() 173 .forEach( 174 (builderEntryPoint, childComponent) -> { 175 if (!componentDescriptor 176 .childComponentsDeclaredByModules() 177 .contains(childComponent)) { 178 explicitBindingsBuilder.add( 179 bindingFactory.subcomponentCreatorBinding( 180 builderEntryPoint.methodElement(), componentDescriptor.typeElement())); 181 } 182 }); 183 184 ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations = ImmutableSet.builder(); 185 ImmutableSet.Builder<SubcomponentDeclaration> subcomponentDeclarations = ImmutableSet.builder(); 186 187 // Collect transitive module bindings and multibinding declarations. 188 ImmutableSet<ModuleDescriptor> modules = modules(componentDescriptor, parentResolver); 189 for (ModuleDescriptor moduleDescriptor : modules) { 190 explicitBindingsBuilder.addAll(moduleDescriptor.bindings()); 191 multibindingDeclarations.addAll(moduleDescriptor.multibindingDeclarations()); 192 subcomponentDeclarations.addAll(moduleDescriptor.subcomponentDeclarations()); 193 delegatesBuilder.addAll(moduleDescriptor.delegateDeclarations()); 194 optionalsBuilder.addAll(moduleDescriptor.optionalDeclarations()); 195 } 196 197 DaggerTypeElement component = DaggerTypeElement.from(componentDescriptor.typeElement()); 198 ComponentPath componentPath = 199 parentResolver.isPresent() 200 ? parentResolver.get().componentPath.childPath(component) 201 : ComponentPath.create(ImmutableList.of(component)); 202 final Resolver requestResolver = 203 new Resolver( 204 componentPath, 205 parentResolver, 206 componentDescriptor, 207 indexBindingDeclarationsByKey(explicitBindingsBuilder.build()), 208 indexBindingDeclarationsByKey(multibindingDeclarations.build()), 209 indexBindingDeclarationsByKey(subcomponentDeclarations.build()), 210 indexBindingDeclarationsByKey(delegatesBuilder.build()), 211 indexBindingDeclarationsByKey(optionalsBuilder.build())); 212 213 componentDescriptor.entryPointMethods().stream() 214 .map(method -> method.dependencyRequest().get()) 215 .forEach( 216 entryPoint -> { 217 if (entryPoint.kind().equals(MEMBERS_INJECTION)) { 218 requestResolver.resolveMembersInjection(entryPoint.key()); 219 } else { 220 requestResolver.resolve(entryPoint.key()); 221 } 222 }); 223 224 if (createFullBindingGraph) { 225 // Resolve the keys for all bindings in all modules, stripping any multibinding contribution 226 // identifier so that the multibinding itself is resolved. 227 modules.stream() 228 .flatMap(module -> module.allBindingKeys().stream()) 229 .map(Key::withoutMultibindingContributionIdentifier) 230 .forEach(requestResolver::resolve); 231 } 232 233 // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have 234 // been detected during binding resolution. If a binding for a subcomponent is never resolved, 235 // no BindingGraph will be created for it and no implementation will be generated. This is 236 // done in a queue since resolving one subcomponent might resolve a key for a subcomponent 237 // from a parent graph. This is done until no more new subcomponents are resolved. 238 Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>(); 239 ImmutableList.Builder<LegacyBindingGraph> subgraphs = ImmutableList.builder(); 240 for (ComponentDescriptor subcomponent : 241 Iterables.consumingIterable(requestResolver.subcomponentsToResolve)) { 242 if (resolvedSubcomponents.add(subcomponent)) { 243 subgraphs.add( 244 createLegacyBindingGraph( 245 Optional.of(requestResolver), subcomponent, createFullBindingGraph)); 246 } 247 } 248 249 return new LegacyBindingGraph(requestResolver, subgraphs.build()); 250 } 251 252 /** 253 * Returns all the modules that should be installed in the component. For production components 254 * and production subcomponents that have a parent that is not a production component or 255 * subcomponent, also includes the production monitoring module for the component and the 256 * production executor module. 257 */ modules( ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver)258 private ImmutableSet<ModuleDescriptor> modules( 259 ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver) { 260 return shouldIncludeImplicitProductionModules(componentDescriptor, parentResolver) 261 ? new ImmutableSet.Builder<ModuleDescriptor>() 262 .addAll(componentDescriptor.modules()) 263 .add( 264 moduleDescriptorFactory.create( 265 DaggerSuperficialValidation.requireTypeElement( 266 processingEnv, 267 generatedMonitoringModuleName(componentDescriptor.typeElement())))) 268 .add( 269 moduleDescriptorFactory.create( 270 processingEnv.requireTypeElement(TypeNames.PRODUCTION_EXECTUTOR_MODULE))) 271 .build() 272 : componentDescriptor.modules(); 273 } 274 shouldIncludeImplicitProductionModules( ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver)275 private boolean shouldIncludeImplicitProductionModules( 276 ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver) { 277 return componentDescriptor.isProduction() 278 && componentDescriptor.isRealComponent() 279 && (parentResolver.isEmpty() || !parentResolver.get().componentDescriptor.isProduction()); 280 } 281 282 /** Indexes {@code bindingDeclarations} by {@link BindingDeclaration#key()}. */ 283 private static <T extends BindingDeclaration> indexBindingDeclarationsByKey(Iterable<T> declarations)284 ImmutableSetMultimap<Key, T> indexBindingDeclarationsByKey(Iterable<T> declarations) { 285 return ImmutableSetMultimap.copyOf(Multimaps.index(declarations, BindingDeclaration::key)); 286 } 287 288 @Override clearCache()289 public void clearCache() { 290 keysMatchingRequestCache.clear(); 291 } 292 293 /** Represents a fully resolved binding graph. */ 294 static final class LegacyBindingGraph { 295 private final Resolver resolver; 296 private final ImmutableList<LegacyBindingGraph> resolvedSubgraphs; 297 private final ComponentNode componentNode; 298 LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs)299 LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs) { 300 this.resolver = resolver; 301 this.resolvedSubgraphs = resolvedSubgraphs; 302 this.componentNode = 303 ComponentNodeImpl.create(resolver.componentPath, resolver.componentDescriptor); 304 } 305 306 /** Returns the {@link ComponentNode} associated with this binding graph. */ componentNode()307 ComponentNode componentNode() { 308 return componentNode; 309 } 310 311 /** Returns the {@link ComponentPath} associated with this binding graph. */ componentPath()312 ComponentPath componentPath() { 313 return resolver.componentPath; 314 } 315 316 /** Returns the {@link ComponentDescriptor} associated with this binding graph. */ componentDescriptor()317 ComponentDescriptor componentDescriptor() { 318 return resolver.componentDescriptor; 319 } 320 321 /** 322 * Returns the {@link ResolvedBindings} in this graph or a parent graph that matches the given 323 * request. 324 * 325 * <p>An exception is thrown if there are no resolved bindings found for the request; however, 326 * this should never happen since all dependencies should have been resolved at this point. 327 */ resolvedBindings(BindingRequest request)328 ResolvedBindings resolvedBindings(BindingRequest request) { 329 return request.isRequestKind(RequestKind.MEMBERS_INJECTION) 330 ? resolver.getResolvedMembersInjectionBindings(request.key()) 331 : resolver.getResolvedContributionBindings(request.key()); 332 } 333 334 /** 335 * Returns all {@link ResolvedBindings} for the given request. 336 * 337 * <p>Note that this only returns the bindings resolved in this component. Bindings resolved in 338 * parent components are not included. 339 */ resolvedBindings()340 Iterable<ResolvedBindings> resolvedBindings() { 341 // Don't return an immutable collection - this is only ever used for looping over all bindings 342 // in the graph. Copying is wasteful, especially if is a hashing collection, since the values 343 // should all, by definition, be distinct. 344 return Iterables.concat( 345 resolver.resolvedMembersInjectionBindings.values(), 346 resolver.resolvedContributionBindings.values()); 347 } 348 349 /** Returns the resolved subgraphs. */ subgraphs()350 ImmutableList<LegacyBindingGraph> subgraphs() { 351 return resolvedSubgraphs; 352 } 353 } 354 355 private final class Resolver { 356 final ComponentPath componentPath; 357 final Optional<Resolver> parentResolver; 358 final ComponentDescriptor componentDescriptor; 359 final ImmutableSetMultimap<Key, ContributionBinding> explicitBindings; 360 final ImmutableSet<ContributionBinding> explicitBindingsSet; 361 final ImmutableSetMultimap<Key, ContributionBinding> explicitMultibindings; 362 final ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations; 363 final ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations; 364 final ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations; 365 final ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations; 366 final ImmutableSetMultimap<Key, DelegateDeclaration> delegateMultibindingDeclarations; 367 final Map<Key, ResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>(); 368 final Map<Key, ResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>(); 369 final Deque<Key> cycleStack = new ArrayDeque<>(); 370 final Map<Key, Boolean> keyDependsOnLocalBindingsCache = new HashMap<>(); 371 final Map<Binding, Boolean> bindingDependsOnLocalBindingsCache = new HashMap<>(); 372 final Queue<ComponentDescriptor> subcomponentsToResolve = new ArrayDeque<>(); 373 Resolver( ComponentPath componentPath, Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor, ImmutableSetMultimap<Key, ContributionBinding> explicitBindings, ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations, ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations, ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations, ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations)374 Resolver( 375 ComponentPath componentPath, 376 Optional<Resolver> parentResolver, 377 ComponentDescriptor componentDescriptor, 378 ImmutableSetMultimap<Key, ContributionBinding> explicitBindings, 379 ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations, 380 ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations, 381 ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations, 382 ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations) { 383 this.componentPath = componentPath; 384 this.parentResolver = parentResolver; 385 this.componentDescriptor = checkNotNull(componentDescriptor); 386 this.explicitBindings = checkNotNull(explicitBindings); 387 this.explicitBindingsSet = ImmutableSet.copyOf(explicitBindings.values()); 388 this.multibindingDeclarations = checkNotNull(multibindingDeclarations); 389 this.subcomponentDeclarations = checkNotNull(subcomponentDeclarations); 390 this.delegateDeclarations = checkNotNull(delegateDeclarations); 391 this.optionalBindingDeclarations = checkNotNull(optionalBindingDeclarations); 392 this.explicitMultibindings = multibindingContributionsByMultibindingKey(explicitBindingsSet); 393 this.delegateMultibindingDeclarations = 394 multibindingContributionsByMultibindingKey(delegateDeclarations.values()); 395 subcomponentsToResolve.addAll( 396 componentDescriptor.childComponentsDeclaredByFactoryMethods().values()); 397 subcomponentsToResolve.addAll( 398 componentDescriptor.childComponentsDeclaredByBuilderEntryPoints().values()); 399 } 400 401 /** 402 * Returns the resolved contribution bindings for the given {@link Key}: 403 * 404 * <ul> 405 * <li>All explicit bindings for: 406 * <ul> 407 * <li>the requested key 408 * <li>{@code Set<T>} if the requested key's type is {@code Set<Produced<T>>} 409 * <li>{@code Map<K, Provider<V>>} if the requested key's type is {@code Map<K, 410 * Producer<V>>}. 411 * </ul> 412 * <li>An implicit {@link Inject @Inject}-annotated constructor binding if there is one and 413 * there are no explicit bindings or synthetic bindings. 414 * </ul> 415 */ lookUpBindings(Key requestKey)416 ResolvedBindings lookUpBindings(Key requestKey) { 417 Set<ContributionBinding> bindings = new LinkedHashSet<>(); 418 Set<ContributionBinding> multibindingContributions = new LinkedHashSet<>(); 419 Set<MultibindingDeclaration> multibindingDeclarations = new LinkedHashSet<>(); 420 Set<OptionalBindingDeclaration> optionalBindingDeclarations = new LinkedHashSet<>(); 421 Set<SubcomponentDeclaration> subcomponentDeclarations = new LinkedHashSet<>(); 422 423 // Gather all bindings, multibindings, optional, and subcomponent declarations/contributions. 424 ImmutableSet<Key> keysMatchingRequest = keysMatchingRequest(requestKey); 425 for (Resolver resolver : getResolverLineage()) { 426 bindings.addAll(resolver.getLocalExplicitBindings(requestKey)); 427 428 for (Key key : keysMatchingRequest) { 429 multibindingContributions.addAll(resolver.getLocalExplicitMultibindings(key)); 430 multibindingDeclarations.addAll(resolver.multibindingDeclarations.get(key)); 431 subcomponentDeclarations.addAll(resolver.subcomponentDeclarations.get(key)); 432 // The optional binding declarations are keyed by the unwrapped type. 433 keyFactory.unwrapOptional(key) 434 .map(resolver.optionalBindingDeclarations::get) 435 .ifPresent(optionalBindingDeclarations::addAll); 436 } 437 } 438 439 // Add synthetic multibinding 440 if (!multibindingContributions.isEmpty() || !multibindingDeclarations.isEmpty()) { 441 bindings.add(bindingFactory.syntheticMultibinding(requestKey, multibindingContributions)); 442 } 443 444 // Add synthetic optional binding 445 if (!optionalBindingDeclarations.isEmpty()) { 446 bindings.add( 447 bindingFactory.syntheticOptionalBinding( 448 requestKey, 449 getRequestKind(OptionalType.from(requestKey).valueType()), 450 lookUpBindings(keyFactory.unwrapOptional(requestKey).get()).bindings())); 451 } 452 453 // Add subcomponent creator binding 454 if (!subcomponentDeclarations.isEmpty()) { 455 ProvisionBinding binding = 456 bindingFactory.subcomponentCreatorBinding( 457 ImmutableSet.copyOf(subcomponentDeclarations)); 458 bindings.add(binding); 459 addSubcomponentToOwningResolver(binding); 460 } 461 462 // Add members injector binding 463 if (isTypeOf(requestKey.type().xprocessing(), TypeNames.MEMBERS_INJECTOR)) { 464 injectBindingRegistry 465 .getOrFindMembersInjectorProvisionBinding(requestKey) 466 .ifPresent(bindings::add); 467 } 468 469 // Add Assisted Factory binding 470 if (isDeclared(requestKey.type().xprocessing()) 471 && isAssistedFactoryType(requestKey.type().xprocessing().getTypeElement())) { 472 bindings.add( 473 bindingFactory.assistedFactoryBinding( 474 requestKey.type().xprocessing().getTypeElement(), 475 Optional.of(requestKey.type().xprocessing()))); 476 } 477 478 // If there are no bindings, add the implicit @Inject-constructed binding if there is one. 479 if (bindings.isEmpty()) { 480 injectBindingRegistry 481 .getOrFindProvisionBinding(requestKey) 482 .filter(this::isCorrectlyScopedInSubcomponent) 483 .ifPresent(bindings::add); 484 } 485 486 return ResolvedBindings.forContributionBindings( 487 componentPath, 488 requestKey, 489 Multimaps.index(bindings, binding -> getOwningComponent(requestKey, binding)), 490 multibindingDeclarations, 491 subcomponentDeclarations, 492 optionalBindingDeclarations); 493 } 494 495 /** 496 * Returns true if this binding graph resolution is for a subcomponent and the {@code @Inject} 497 * binding's scope correctly matches one of the components in the current component ancestry. 498 * If not, it means the binding is not owned by any of the currently known components, and will 499 * be owned by a future ancestor (or, if never owned, will result in an incompatibly scoped 500 * binding error at the root component). 501 */ isCorrectlyScopedInSubcomponent(ProvisionBinding binding)502 private boolean isCorrectlyScopedInSubcomponent(ProvisionBinding binding) { 503 checkArgument(binding.kind() == INJECTION || binding.kind() == ASSISTED_INJECTION); 504 if (!rootComponent().isSubcomponent() 505 || !binding.scope().isPresent() 506 || binding.scope().get().isReusable()) { 507 return true; 508 } 509 510 Resolver owningResolver = getOwningResolver(binding).orElse(this); 511 ComponentDescriptor owningComponent = owningResolver.componentDescriptor; 512 return owningComponent.scopes().contains(binding.scope().get()); 513 } 514 rootComponent()515 private ComponentDescriptor rootComponent() { 516 return parentResolver.map(Resolver::rootComponent).orElse(componentDescriptor); 517 } 518 519 /** Returns the resolved members injection bindings for the given {@link Key}. */ lookUpMembersInjectionBinding(Key requestKey)520 ResolvedBindings lookUpMembersInjectionBinding(Key requestKey) { 521 // no explicit deps for members injection, so just look it up 522 Optional<MembersInjectionBinding> binding = 523 injectBindingRegistry.getOrFindMembersInjectionBinding(requestKey); 524 return binding.isPresent() 525 ? ResolvedBindings.forMembersInjectionBinding( 526 componentPath, requestKey, componentDescriptor, binding.get()) 527 : ResolvedBindings.noBindings(componentPath, requestKey); 528 } 529 530 /** 531 * When a binding is resolved for a {@link SubcomponentDeclaration}, adds corresponding {@link 532 * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue 533 * will be used to detect which subcomponents need to be resolved. 534 */ addSubcomponentToOwningResolver(ProvisionBinding subcomponentCreatorBinding)535 private void addSubcomponentToOwningResolver(ProvisionBinding subcomponentCreatorBinding) { 536 checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR)); 537 Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get(); 538 539 XTypeElement builderType = 540 subcomponentCreatorBinding.key().type().xprocessing().getTypeElement(); 541 owningResolver.subcomponentsToResolve.add( 542 owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType)); 543 } 544 545 /** 546 * Profiling has determined that computing the keys matching {@code requestKey} has measurable 547 * performance impact. It is called repeatedly (at least 3 times per key resolved per {@link 548 * BindingGraph}. {@code javac}'s name-checking performance seems suboptimal (converting byte 549 * strings to Strings repeatedly), and the matching keys creations relies on that. This also 550 * ensures that the resulting keys have their hash codes cached on successive calls to this 551 * method. 552 * 553 * <p>This caching may become obsolete if: 554 * 555 * <ul> 556 * <li>We decide to intern all {@link Key} instances 557 * <li>We fix javac's name-checking peformance (though we may want to keep this for older 558 * javac users) 559 * </ul> 560 */ keysMatchingRequest(Key requestKey)561 private ImmutableSet<Key> keysMatchingRequest(Key requestKey) { 562 return keysMatchingRequestCache.computeIfAbsent( 563 requestKey, this::keysMatchingRequestUncached); 564 } 565 keysMatchingRequestUncached(Key requestKey)566 private ImmutableSet<Key> keysMatchingRequestUncached(Key requestKey) { 567 ImmutableSet.Builder<Key> keys = ImmutableSet.builder(); 568 keys.add(requestKey); 569 keyFactory.unwrapSetKey(requestKey, TypeNames.PRODUCED).ifPresent(keys::add); 570 keyFactory 571 .rewrapMapKey(requestKey, TypeNames.PRODUCER, TypeNames.PROVIDER) 572 .ifPresent(keys::add); 573 keyFactory 574 .rewrapMapKey(requestKey, TypeNames.PROVIDER, TypeNames.PRODUCER) 575 .ifPresent(keys::add); 576 keys.addAll(keyFactory.implicitFrameworkMapKeys(requestKey)); 577 return keys.build(); 578 } 579 createDelegateBindings( ImmutableSet<DelegateDeclaration> delegateDeclarations)580 private ImmutableSet<ContributionBinding> createDelegateBindings( 581 ImmutableSet<DelegateDeclaration> delegateDeclarations) { 582 ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder(); 583 for (DelegateDeclaration delegateDeclaration : delegateDeclarations) { 584 builder.add(createDelegateBinding(delegateDeclaration)); 585 } 586 return builder.build(); 587 } 588 589 /** 590 * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved 591 * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate 592 * bindings for the dependency key, there should still be only one binding for the delegate key. 593 */ createDelegateBinding(DelegateDeclaration delegateDeclaration)594 private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) { 595 Key delegateKey = delegateDeclaration.delegateRequest().key(); 596 if (cycleStack.contains(delegateKey)) { 597 return bindingFactory.unresolvedDelegateBinding(delegateDeclaration); 598 } 599 600 ResolvedBindings resolvedDelegate; 601 try { 602 cycleStack.push(delegateKey); 603 resolvedDelegate = lookUpBindings(delegateKey); 604 } finally { 605 cycleStack.pop(); 606 } 607 if (resolvedDelegate.contributionBindings().isEmpty()) { 608 // This is guaranteed to result in a missing binding error, so it doesn't matter if the 609 // binding is a Provision or Production, except if it is a @IntoMap method, in which 610 // case the key will be of type Map<K, Provider<V>>, which will be "upgraded" into a 611 // Map<K, Producer<V>> if it's requested in a ProductionComponent. This may result in a 612 // strange error, that the RHS needs to be provided with an @Inject or @Provides 613 // annotated method, but a user should be able to figure out if a @Produces annotation 614 // is needed. 615 // TODO(gak): revisit how we model missing delegates if/when we clean up how we model 616 // binding declarations 617 return bindingFactory.unresolvedDelegateBinding(delegateDeclaration); 618 } 619 // It doesn't matter which of these is selected, since they will later on produce a 620 // duplicate binding error. 621 ContributionBinding explicitDelegate = 622 resolvedDelegate.contributionBindings().iterator().next(); 623 return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate); 624 } 625 626 /** 627 * Returns the component that should contain the framework field for {@code binding}. 628 * 629 * <p>If {@code binding} is either not bound in an ancestor component or depends transitively on 630 * bindings in this component, returns this component. 631 * 632 * <p>Otherwise, resolves {@code request} in this component's parent in order to resolve any 633 * multibinding contributions in the parent, and returns the parent-resolved {@link 634 * ResolvedBindings#owningComponent(ContributionBinding)}. 635 */ getOwningComponent(Key requestKey, ContributionBinding binding)636 private XTypeElement getOwningComponent(Key requestKey, ContributionBinding binding) { 637 if (isResolvedInParent(requestKey, binding) && !requiresResolution(binding)) { 638 ResolvedBindings parentResolvedBindings = 639 parentResolver.get().resolvedContributionBindings.get(requestKey); 640 return parentResolvedBindings.owningComponent(binding); 641 } else { 642 return componentDescriptor.typeElement(); 643 } 644 } 645 646 /** 647 * Returns {@code true} if {@code binding} is owned by an ancestor. If so, {@linkplain #resolve 648 * resolves} the {@link Key} in this component's parent. Don't resolve directly in the owning 649 * component in case it depends on multibindings in any of its descendants. 650 */ isResolvedInParent(Key requestKey, ContributionBinding binding)651 private boolean isResolvedInParent(Key requestKey, ContributionBinding binding) { 652 Optional<Resolver> owningResolver = getOwningResolver(binding); 653 if (owningResolver.isPresent() && !owningResolver.get().equals(this)) { 654 parentResolver.get().resolve(requestKey); 655 return true; 656 } else { 657 return false; 658 } 659 } 660 getOwningResolver(ContributionBinding binding)661 private Optional<Resolver> getOwningResolver(ContributionBinding binding) { 662 // TODO(ronshapiro): extract the different pieces of this method into their own methods 663 if ((binding.scope().isPresent() && binding.scope().get().isProductionScope()) 664 || binding.bindingType().equals(BindingType.PRODUCTION)) { 665 for (Resolver requestResolver : getResolverLineage()) { 666 // Resolve @Inject @ProductionScope bindings at the highest production component. 667 if (binding.kind().equals(INJECTION) 668 && requestResolver.componentDescriptor.isProduction()) { 669 return Optional.of(requestResolver); 670 } 671 672 // Resolve explicit @Produces and @ProductionScope bindings at the highest component that 673 // installs the binding. 674 if (requestResolver.containsExplicitBinding(binding)) { 675 return Optional.of(requestResolver); 676 } 677 } 678 } 679 680 if (binding.scope().isPresent() && binding.scope().get().isReusable()) { 681 for (Resolver requestResolver : getResolverLineage().reverse()) { 682 // If a @Reusable binding was resolved in an ancestor, use that component. 683 ResolvedBindings resolvedBindings = 684 requestResolver.resolvedContributionBindings.get(binding.key()); 685 if (resolvedBindings != null 686 && resolvedBindings.contributionBindings().contains(binding)) { 687 return Optional.of(requestResolver); 688 } 689 } 690 // If a @Reusable binding was not resolved in any ancestor, resolve it here. 691 return Optional.empty(); 692 } 693 694 for (Resolver requestResolver : getResolverLineage().reverse()) { 695 if (requestResolver.containsExplicitBinding(binding)) { 696 return Optional.of(requestResolver); 697 } 698 } 699 700 // look for scope separately. we do this for the case where @Singleton can appear twice 701 // in the † compatibility mode 702 Optional<Scope> bindingScope = binding.scope(); 703 if (bindingScope.isPresent()) { 704 for (Resolver requestResolver : getResolverLineage().reverse()) { 705 if (requestResolver.componentDescriptor.scopes().contains(bindingScope.get())) { 706 return Optional.of(requestResolver); 707 } 708 } 709 } 710 return Optional.empty(); 711 } 712 containsExplicitBinding(ContributionBinding binding)713 private boolean containsExplicitBinding(ContributionBinding binding) { 714 return explicitBindingsSet.contains(binding) 715 || resolverContainsDelegateDeclarationForBinding(binding) 716 || subcomponentDeclarations.containsKey(binding.key()); 717 } 718 719 /** Returns true if {@code binding} was installed in a module in this resolver's component. */ resolverContainsDelegateDeclarationForBinding(ContributionBinding binding)720 private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) { 721 if (!binding.kind().equals(DELEGATE)) { 722 return false; 723 } 724 725 // Map multibinding key values are wrapped with a framework type. This needs to be undone 726 // to look it up in the delegate declarations map. 727 // TODO(erichang): See if we can standardize the way map keys are used in these data 728 // structures, either always wrapped or unwrapped to be consistent and less errorprone. 729 Key bindingKey = binding.key(); 730 if (compilerOptions.strictMultibindingValidation() 731 && binding.contributionType().equals(ContributionType.MAP)) { 732 bindingKey = keyFactory.unwrapMapValueType(bindingKey); 733 } 734 735 return delegateDeclarations.get(bindingKey).stream() 736 .anyMatch( 737 declaration -> 738 declaration.contributingModule().equals(binding.contributingModule()) 739 && declaration.bindingElement().equals(binding.bindingElement())); 740 } 741 742 /** Returns the resolver lineage from parent to child. */ getResolverLineage()743 private ImmutableList<Resolver> getResolverLineage() { 744 ImmutableList.Builder<Resolver> resolverList = ImmutableList.builder(); 745 for (Optional<Resolver> currentResolver = Optional.of(this); 746 currentResolver.isPresent(); 747 currentResolver = currentResolver.get().parentResolver) { 748 resolverList.add(currentResolver.get()); 749 } 750 return resolverList.build().reverse(); 751 } 752 753 /** 754 * Returns the explicit {@link ContributionBinding}s that match the {@code key} from this 755 * resolver. 756 */ getLocalExplicitBindings(Key key)757 private ImmutableSet<ContributionBinding> getLocalExplicitBindings(Key key) { 758 return new ImmutableSet.Builder<ContributionBinding>() 759 .addAll(explicitBindings.get(key)) 760 // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces 761 // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's 762 // value type if it's a Map<K, Provider/Producer<V>> before looking in 763 // delegateDeclarations. createDelegateBindings() will create bindings with the properly 764 // wrapped key type. 765 .addAll( 766 createDelegateBindings(delegateDeclarations.get(keyFactory.unwrapMapValueType(key)))) 767 .build(); 768 } 769 770 /** 771 * Returns the explicit multibinding contributions that contribute to the map or set requested 772 * by {@code key} from this resolver. 773 */ getLocalExplicitMultibindings(Key key)774 private ImmutableSet<ContributionBinding> getLocalExplicitMultibindings(Key key) { 775 ImmutableSet.Builder<ContributionBinding> multibindings = ImmutableSet.builder(); 776 multibindings.addAll(explicitMultibindings.get(key)); 777 if (!MapType.isMap(key) 778 || MapType.from(key).isRawType() 779 || MapType.from(key).valuesAreFrameworkType()) { 780 // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces 781 // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's 782 // value type if it's a Map<K, Provider/Producer<V>> before looking in 783 // delegateMultibindingDeclarations. createDelegateBindings() will create bindings with the 784 // properly wrapped key type. 785 multibindings.addAll( 786 createDelegateBindings( 787 delegateMultibindingDeclarations.get(keyFactory.unwrapMapValueType(key)))); 788 } 789 return multibindings.build(); 790 } 791 792 /** 793 * Returns the {@link OptionalBindingDeclaration}s that match the {@code key} from this and all 794 * ancestor resolvers. 795 */ getOptionalBindingDeclarations(Key key)796 private ImmutableSet<OptionalBindingDeclaration> getOptionalBindingDeclarations(Key key) { 797 Optional<Key> unwrapped = keyFactory.unwrapOptional(key); 798 if (!unwrapped.isPresent()) { 799 return ImmutableSet.of(); 800 } 801 ImmutableSet.Builder<OptionalBindingDeclaration> declarations = ImmutableSet.builder(); 802 for (Resolver resolver : getResolverLineage()) { 803 declarations.addAll(resolver.optionalBindingDeclarations.get(unwrapped.get())); 804 } 805 return declarations.build(); 806 } 807 808 /** 809 * Returns the {@link ResolvedBindings} for {@code key} that was resolved in this resolver or an 810 * ancestor resolver. Only checks for {@link ContributionBinding}s as {@link 811 * MembersInjectionBinding}s are not inherited. 812 */ getPreviouslyResolvedBindings(Key key)813 private Optional<ResolvedBindings> getPreviouslyResolvedBindings(Key key) { 814 Optional<ResolvedBindings> result = 815 Optional.ofNullable(resolvedContributionBindings.get(key)); 816 if (result.isPresent()) { 817 return result; 818 } else if (parentResolver.isPresent()) { 819 return parentResolver.get().getPreviouslyResolvedBindings(key); 820 } else { 821 return Optional.empty(); 822 } 823 } 824 resolveMembersInjection(Key key)825 private void resolveMembersInjection(Key key) { 826 ResolvedBindings bindings = lookUpMembersInjectionBinding(key); 827 resolveDependencies(bindings); 828 resolvedMembersInjectionBindings.put(key, bindings); 829 } 830 resolve(Key key)831 void resolve(Key key) { 832 // If we find a cycle, stop resolving. The original request will add it with all of the 833 // other resolved deps. 834 if (cycleStack.contains(key)) { 835 return; 836 } 837 838 // If the binding was previously resolved in this (sub)component, don't resolve it again. 839 if (resolvedContributionBindings.containsKey(key)) { 840 return; 841 } 842 843 /* 844 * If the binding was previously resolved in an ancestor component, then we may be able to 845 * avoid resolving it here and just depend on the ancestor component resolution. 846 * 847 * 1. If it depends transitively on multibinding contributions or optional bindings with 848 * bindings from this subcomponent, then we have to resolve it in this subcomponent so 849 * that it sees the local bindings. 850 * 851 * 2. If there are any explicit bindings in this component, they may conflict with those in 852 * the ancestor component, so resolve them here so that conflicts can be caught. 853 */ 854 if (getPreviouslyResolvedBindings(key).isPresent() && !Keys.isComponentOrCreator(key)) { 855 /* Resolve in the parent in case there are multibinding contributions or conflicts in some 856 * component between this one and the previously-resolved one. */ 857 parentResolver.get().resolve(key); 858 ResolvedBindings previouslyResolvedBindings = getPreviouslyResolvedBindings(key).get(); 859 // TODO(b/305748522): Allow caching for assisted injection bindings. 860 boolean isAssistedInjectionBinding = 861 previouslyResolvedBindings.bindings().stream() 862 .anyMatch(binding -> binding.kind() == BindingKind.ASSISTED_INJECTION); 863 if (!isAssistedInjectionBinding 864 && !requiresResolution(key) 865 && getLocalExplicitBindings(key).isEmpty()) { 866 /* Cache the inherited parent component's bindings in case resolving at the parent found 867 * bindings in some component between this one and the previously-resolved one. */ 868 resolvedContributionBindings.put(key, previouslyResolvedBindings); 869 return; 870 } 871 } 872 873 cycleStack.push(key); 874 try { 875 ResolvedBindings bindings = lookUpBindings(key); 876 resolvedContributionBindings.put(key, bindings); 877 resolveDependencies(bindings); 878 } finally { 879 cycleStack.pop(); 880 } 881 } 882 883 /** 884 * {@link #resolve(Key) Resolves} each of the dependencies of the bindings owned by this 885 * component. 886 */ resolveDependencies(ResolvedBindings resolvedBindings)887 private void resolveDependencies(ResolvedBindings resolvedBindings) { 888 for (Binding binding : resolvedBindings.bindingsOwnedBy(componentDescriptor)) { 889 for (DependencyRequest dependency : binding.dependencies()) { 890 resolve(dependency.key()); 891 } 892 } 893 } 894 getResolvedContributionBindings(Key key)895 private ResolvedBindings getResolvedContributionBindings(Key key) { 896 if (resolvedContributionBindings.containsKey(key)) { 897 return resolvedContributionBindings.get(key); 898 } 899 if (parentResolver.isPresent()) { 900 return parentResolver.get().getResolvedContributionBindings(key); 901 } 902 throw new AssertionError("No resolved bindings for key: " + key); 903 } 904 getResolvedMembersInjectionBindings(Key key)905 private ResolvedBindings getResolvedMembersInjectionBindings(Key key) { 906 return resolvedMembersInjectionBindings.get(key); 907 } 908 requiresResolution(Key key)909 private boolean requiresResolution(Key key) { 910 return new LegacyRequiresResolutionChecker().requiresResolution(key); 911 } 912 requiresResolution(Binding binding)913 private boolean requiresResolution(Binding binding) { 914 return new LegacyRequiresResolutionChecker().requiresResolution(binding); 915 } 916 917 private final class LegacyRequiresResolutionChecker { 918 private final Set<Object> cycleChecker = new HashSet<>(); 919 920 /** 921 * Returns {@code true} if any of the bindings resolved for {@code key} are multibindings with 922 * contributions declared within this component's modules or optional bindings with present 923 * values declared within this component's modules, or if any of its unscoped dependencies 924 * depend on such bindings. 925 * 926 * <p>We don't care about scoped dependencies because they will never depend on bindings from 927 * subcomponents. 928 * 929 * @throws IllegalArgumentException if {@link #getPreviouslyResolvedBindings(Key)} is empty 930 */ requiresResolution(Key key)931 private boolean requiresResolution(Key key) { 932 // Don't recur infinitely if there are valid cycles in the dependency graph. 933 // http://b/23032377 934 if (!cycleChecker.add(key)) { 935 return false; 936 } 937 return reentrantComputeIfAbsent( 938 keyDependsOnLocalBindingsCache, key, this::requiresResolutionUncached); 939 } 940 941 /** 942 * Returns {@code true} if {@code binding} is unscoped (or has {@link Reusable @Reusable} 943 * scope) and depends on multibindings with contributions declared within this component's 944 * modules, or if any of its unscoped or {@link Reusable @Reusable} scoped dependencies depend 945 * on such local multibindings. 946 * 947 * <p>We don't care about non-reusable scoped dependencies because they will never depend on 948 * multibindings with contributions from subcomponents. 949 */ requiresResolution(Binding binding)950 private boolean requiresResolution(Binding binding) { 951 if (!cycleChecker.add(binding)) { 952 return false; 953 } 954 return reentrantComputeIfAbsent( 955 bindingDependsOnLocalBindingsCache, binding, this::requiresResolutionUncached); 956 } 957 requiresResolutionUncached(Key key)958 private boolean requiresResolutionUncached(Key key) { 959 checkArgument( 960 getPreviouslyResolvedBindings(key).isPresent(), 961 "no previously resolved bindings in %s for %s", 962 Resolver.this, 963 key); 964 ResolvedBindings previouslyResolvedBindings = getPreviouslyResolvedBindings(key).get(); 965 if (hasLocalBindings(previouslyResolvedBindings)) { 966 return true; 967 } 968 969 for (Binding binding : previouslyResolvedBindings.bindings()) { 970 if (requiresResolution(binding)) { 971 return true; 972 } 973 } 974 return false; 975 } 976 requiresResolutionUncached(Binding binding)977 private boolean requiresResolutionUncached(Binding binding) { 978 if ((!binding.scope().isPresent() || binding.scope().get().isReusable()) 979 // TODO(beder): Figure out what happens with production subcomponents. 980 && !binding.bindingType().equals(BindingType.PRODUCTION)) { 981 for (DependencyRequest dependency : binding.dependencies()) { 982 if (requiresResolution(dependency.key())) { 983 return true; 984 } 985 } 986 } 987 return false; 988 } 989 } 990 hasLocalBindings(Binding binding)991 private boolean hasLocalBindings(Binding binding) { 992 return hasLocalMultibindingContributions(binding.key()) 993 || hasLocalOptionalBindingContribution( 994 binding.key(), ImmutableSet.of((ContributionBinding) binding)); 995 } 996 hasLocalBindings(ResolvedBindings resolvedBindings)997 private boolean hasLocalBindings(ResolvedBindings resolvedBindings) { 998 return hasLocalMultibindingContributions(resolvedBindings.key()) 999 || hasLocalOptionalBindingContribution(resolvedBindings); 1000 } 1001 1002 /** 1003 * Returns {@code true} if there is at least one multibinding contribution declared within 1004 * this component's modules that matches the key. 1005 */ hasLocalMultibindingContributions(Key requestKey)1006 private boolean hasLocalMultibindingContributions(Key requestKey) { 1007 return keysMatchingRequest(requestKey) 1008 .stream() 1009 .anyMatch(key -> !getLocalExplicitMultibindings(key).isEmpty()); 1010 } 1011 1012 /** 1013 * Returns {@code true} if there is a contribution in this component for an {@code 1014 * Optional<Foo>} key that has not been contributed in a parent. 1015 */ hasLocalOptionalBindingContribution(ResolvedBindings resolvedBindings)1016 private boolean hasLocalOptionalBindingContribution(ResolvedBindings resolvedBindings) { 1017 return hasLocalOptionalBindingContribution( 1018 resolvedBindings.key(), resolvedBindings.contributionBindings()); 1019 } 1020 hasLocalOptionalBindingContribution( Key key, ImmutableSet<ContributionBinding> previousContributionBindings)1021 private boolean hasLocalOptionalBindingContribution( 1022 Key key, ImmutableSet<ContributionBinding> previousContributionBindings) { 1023 if (previousContributionBindings.stream() 1024 .map(ContributionBinding::kind) 1025 .anyMatch(isEqual(OPTIONAL))) { 1026 return !getLocalExplicitBindings(keyFactory.unwrapOptional(key).get()) 1027 .isEmpty(); 1028 } else { 1029 // If a parent contributes a @Provides Optional<Foo> binding and a child has a 1030 // @BindsOptionalOf Foo method, the two should conflict, even if there is no binding for 1031 // Foo on its own 1032 return !getOptionalBindingDeclarations(key).isEmpty(); 1033 } 1034 } 1035 } 1036 1037 /** 1038 * A multimap of those {@code declarations} that are multibinding contribution declarations, 1039 * indexed by the key of the set or map to which they contribute. 1040 */ 1041 static <T extends BindingDeclaration> multibindingContributionsByMultibindingKey( Iterable<T> declarations)1042 ImmutableSetMultimap<Key, T> multibindingContributionsByMultibindingKey( 1043 Iterable<T> declarations) { 1044 ImmutableSetMultimap.Builder<Key, T> builder = ImmutableSetMultimap.builder(); 1045 for (T declaration : declarations) { 1046 if (declaration.key().multibindingContributionIdentifier().isPresent()) { 1047 builder.put(declaration.key().withoutMultibindingContributionIdentifier(), declaration); 1048 } 1049 } 1050 return builder.build(); 1051 } 1052 } 1053