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