1 /* 2 * Copyright (C) 2017 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.auto.common.MoreElements.isAnnotationPresent; 20 import static com.google.auto.common.MoreTypes.asDeclared; 21 import static com.google.common.base.Preconditions.checkArgument; 22 import static com.google.common.base.Preconditions.checkNotNull; 23 import static com.google.common.base.Preconditions.checkState; 24 import static com.google.common.collect.Iterables.getOnlyElement; 25 import static dagger.internal.codegen.base.MoreAnnotationMirrors.wrapOptionalInEquivalence; 26 import static dagger.internal.codegen.base.Scopes.uniqueScopeOf; 27 import static dagger.internal.codegen.binding.Binding.hasNonDefaultTypeParameters; 28 import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentProductionMethod; 29 import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType; 30 import static dagger.internal.codegen.binding.ContributionBinding.bindingKindForMultibindingKey; 31 import static dagger.internal.codegen.binding.MapKeys.getMapKey; 32 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 33 import static dagger.model.BindingKind.ASSISTED_FACTORY; 34 import static dagger.model.BindingKind.ASSISTED_INJECTION; 35 import static dagger.model.BindingKind.BOUND_INSTANCE; 36 import static dagger.model.BindingKind.COMPONENT; 37 import static dagger.model.BindingKind.COMPONENT_DEPENDENCY; 38 import static dagger.model.BindingKind.COMPONENT_PRODUCTION; 39 import static dagger.model.BindingKind.COMPONENT_PROVISION; 40 import static dagger.model.BindingKind.DELEGATE; 41 import static dagger.model.BindingKind.INJECTION; 42 import static dagger.model.BindingKind.MEMBERS_INJECTOR; 43 import static dagger.model.BindingKind.OPTIONAL; 44 import static dagger.model.BindingKind.PRODUCTION; 45 import static dagger.model.BindingKind.PROVISION; 46 import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR; 47 import static javax.lang.model.element.ElementKind.CONSTRUCTOR; 48 import static javax.lang.model.element.ElementKind.METHOD; 49 50 import com.google.auto.common.MoreElements; 51 import com.google.auto.common.MoreTypes; 52 import com.google.common.collect.ImmutableCollection; 53 import com.google.common.collect.ImmutableSet; 54 import com.google.common.collect.ImmutableSortedSet; 55 import com.google.common.collect.Iterables; 56 import dagger.Module; 57 import dagger.assisted.AssistedInject; 58 import dagger.internal.codegen.base.ContributionType; 59 import dagger.internal.codegen.base.MapType; 60 import dagger.internal.codegen.base.SetType; 61 import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite; 62 import dagger.internal.codegen.binding.ProductionBinding.ProductionKind; 63 import dagger.internal.codegen.kotlin.KotlinMetadataUtil; 64 import dagger.internal.codegen.langmodel.DaggerElements; 65 import dagger.internal.codegen.langmodel.DaggerTypes; 66 import dagger.model.DependencyRequest; 67 import dagger.model.Key; 68 import dagger.model.RequestKind; 69 import dagger.producers.Produced; 70 import dagger.producers.Producer; 71 import java.util.Optional; 72 import java.util.function.BiFunction; 73 import javax.inject.Inject; 74 import javax.inject.Provider; 75 import javax.lang.model.element.Element; 76 import javax.lang.model.element.ExecutableElement; 77 import javax.lang.model.element.TypeElement; 78 import javax.lang.model.element.VariableElement; 79 import javax.lang.model.type.DeclaredType; 80 import javax.lang.model.type.ExecutableType; 81 import javax.lang.model.type.TypeMirror; 82 83 /** A factory for {@link Binding} objects. */ 84 public final class BindingFactory { 85 private final DaggerTypes types; 86 private final KeyFactory keyFactory; 87 private final DependencyRequestFactory dependencyRequestFactory; 88 private final InjectionSiteFactory injectionSiteFactory; 89 private final DaggerElements elements; 90 private final InjectionAnnotations injectionAnnotations; 91 private final KotlinMetadataUtil metadataUtil; 92 93 @Inject BindingFactory( DaggerTypes types, DaggerElements elements, KeyFactory keyFactory, DependencyRequestFactory dependencyRequestFactory, InjectionSiteFactory injectionSiteFactory, InjectionAnnotations injectionAnnotations, KotlinMetadataUtil metadataUtil)94 BindingFactory( 95 DaggerTypes types, 96 DaggerElements elements, 97 KeyFactory keyFactory, 98 DependencyRequestFactory dependencyRequestFactory, 99 InjectionSiteFactory injectionSiteFactory, 100 InjectionAnnotations injectionAnnotations, 101 KotlinMetadataUtil metadataUtil) { 102 this.types = types; 103 this.elements = elements; 104 this.keyFactory = keyFactory; 105 this.dependencyRequestFactory = dependencyRequestFactory; 106 this.injectionSiteFactory = injectionSiteFactory; 107 this.injectionAnnotations = injectionAnnotations; 108 this.metadataUtil = metadataUtil; 109 } 110 111 /** 112 * Returns an {@link dagger.model.BindingKind#INJECTION} binding. 113 * 114 * @param constructorElement the {@code @Inject}-annotated constructor 115 * @param resolvedType the parameterized type if the constructor is for a generic class and the 116 * binding should be for the parameterized type 117 */ 118 // TODO(dpb): See if we can just pass the parameterized type and not also the constructor. injectionBinding( ExecutableElement constructorElement, Optional<TypeMirror> resolvedType)119 public ProvisionBinding injectionBinding( 120 ExecutableElement constructorElement, Optional<TypeMirror> resolvedType) { 121 checkArgument(constructorElement.getKind().equals(CONSTRUCTOR)); 122 checkArgument( 123 isAnnotationPresent(constructorElement, Inject.class) 124 || isAnnotationPresent(constructorElement, AssistedInject.class)); 125 checkArgument(!injectionAnnotations.getQualifier(constructorElement).isPresent()); 126 127 ExecutableType constructorType = MoreTypes.asExecutable(constructorElement.asType()); 128 DeclaredType constructedType = 129 MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType()); 130 // If the class this is constructing has some type arguments, resolve everything. 131 if (!constructedType.getTypeArguments().isEmpty() && resolvedType.isPresent()) { 132 DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get()); 133 // Validate that we're resolving from the correct type. 134 checkState( 135 types.isSameType(types.erasure(resolved), types.erasure(constructedType)), 136 "erased expected type: %s, erased actual type: %s", 137 types.erasure(resolved), 138 types.erasure(constructedType)); 139 constructorType = MoreTypes.asExecutable(types.asMemberOf(resolved, constructorElement)); 140 constructedType = resolved; 141 } 142 143 // Collect all dependency requests within the provision method. 144 // Note: we filter out @Assisted parameters since these aren't considered dependency requests. 145 ImmutableSet.Builder<DependencyRequest> provisionDependencies = ImmutableSet.builder(); 146 for (int i = 0; i < constructorElement.getParameters().size(); i++) { 147 VariableElement parameter = constructorElement.getParameters().get(i); 148 TypeMirror parameterType = constructorType.getParameterTypes().get(i); 149 if (!AssistedInjectionAnnotations.isAssistedParameter(parameter)) { 150 provisionDependencies.add( 151 dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType)); 152 } 153 } 154 155 Key key = keyFactory.forInjectConstructorWithResolvedType(constructedType); 156 ProvisionBinding.Builder builder = 157 ProvisionBinding.builder() 158 .contributionType(ContributionType.UNIQUE) 159 .bindingElement(constructorElement) 160 .key(key) 161 .provisionDependencies(provisionDependencies.build()) 162 .injectionSites(injectionSiteFactory.getInjectionSites(constructedType)) 163 .kind( 164 isAnnotationPresent(constructorElement, AssistedInject.class) 165 ? ASSISTED_INJECTION 166 : INJECTION) 167 .scope(uniqueScopeOf(constructorElement.getEnclosingElement())); 168 169 TypeElement bindingTypeElement = MoreElements.asType(constructorElement.getEnclosingElement()); 170 if (hasNonDefaultTypeParameters(bindingTypeElement, key.type(), types)) { 171 builder.unresolved(injectionBinding(constructorElement, Optional.empty())); 172 } 173 return builder.build(); 174 } 175 assistedFactoryBinding( TypeElement factory, Optional<TypeMirror> resolvedType)176 public ProvisionBinding assistedFactoryBinding( 177 TypeElement factory, Optional<TypeMirror> resolvedType) { 178 179 // If the class this is constructing has some type arguments, resolve everything. 180 DeclaredType factoryType = MoreTypes.asDeclared(factory.asType()); 181 if (!factoryType.getTypeArguments().isEmpty() && resolvedType.isPresent()) { 182 DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get()); 183 // Validate that we're resolving from the correct type by checking that the erasure of the 184 // resolvedType is the same as the erasure of the factoryType. 185 checkState( 186 types.isSameType(types.erasure(resolved), types.erasure(factoryType)), 187 "erased expected type: %s, erased actual type: %s", 188 types.erasure(resolved), 189 types.erasure(factoryType)); 190 factoryType = resolved; 191 } 192 193 ExecutableElement factoryMethod = 194 AssistedInjectionAnnotations.assistedFactoryMethod(factory, elements, types); 195 ExecutableType factoryMethodType = 196 MoreTypes.asExecutable(types.asMemberOf(factoryType, factoryMethod)); 197 return ProvisionBinding.builder() 198 .contributionType(ContributionType.UNIQUE) 199 .key(Key.builder(factoryType).build()) 200 .bindingElement(factory) 201 .provisionDependencies( 202 ImmutableSet.of( 203 DependencyRequest.builder() 204 .key(Key.builder(factoryMethodType.getReturnType()).build()) 205 .kind(RequestKind.PROVIDER) 206 .build())) 207 .kind(ASSISTED_FACTORY) 208 .build(); 209 } 210 211 /** 212 * Returns a {@link dagger.model.BindingKind#PROVISION} binding for a {@code @Provides}-annotated 213 * method. 214 * 215 * @param contributedBy the installed module that declares or inherits the method 216 */ providesMethodBinding( ExecutableElement providesMethod, TypeElement contributedBy)217 public ProvisionBinding providesMethodBinding( 218 ExecutableElement providesMethod, TypeElement contributedBy) { 219 return setMethodBindingProperties( 220 ProvisionBinding.builder(), 221 providesMethod, 222 contributedBy, 223 keyFactory.forProvidesMethod(providesMethod, contributedBy), 224 this::providesMethodBinding) 225 .kind(PROVISION) 226 .scope(uniqueScopeOf(providesMethod)) 227 .nullableType(getNullableType(providesMethod)) 228 .build(); 229 } 230 231 /** 232 * Returns a {@link dagger.model.BindingKind#PRODUCTION} binding for a {@code @Produces}-annotated 233 * method. 234 * 235 * @param contributedBy the installed module that declares or inherits the method 236 */ producesMethodBinding( ExecutableElement producesMethod, TypeElement contributedBy)237 public ProductionBinding producesMethodBinding( 238 ExecutableElement producesMethod, TypeElement contributedBy) { 239 // TODO(beder): Add nullability checking with Java 8. 240 ProductionBinding.Builder builder = 241 setMethodBindingProperties( 242 ProductionBinding.builder(), 243 producesMethod, 244 contributedBy, 245 keyFactory.forProducesMethod(producesMethod, contributedBy), 246 this::producesMethodBinding) 247 .kind(PRODUCTION) 248 .productionKind(ProductionKind.fromProducesMethod(producesMethod)) 249 .thrownTypes(producesMethod.getThrownTypes()) 250 .executorRequest(dependencyRequestFactory.forProductionImplementationExecutor()) 251 .monitorRequest(dependencyRequestFactory.forProductionComponentMonitor()); 252 return builder.build(); 253 } 254 255 private <C extends ContributionBinding, B extends ContributionBinding.Builder<C, B>> setMethodBindingProperties( B builder, ExecutableElement method, TypeElement contributedBy, Key key, BiFunction<ExecutableElement, TypeElement, C> create)256 B setMethodBindingProperties( 257 B builder, 258 ExecutableElement method, 259 TypeElement contributedBy, 260 Key key, 261 BiFunction<ExecutableElement, TypeElement, C> create) { 262 checkArgument(method.getKind().equals(METHOD)); 263 ExecutableType methodType = 264 MoreTypes.asExecutable( 265 types.asMemberOf(MoreTypes.asDeclared(contributedBy.asType()), method)); 266 if (!types.isSameType(methodType, method.asType())) { 267 builder.unresolved(create.apply(method, MoreElements.asType(method.getEnclosingElement()))); 268 } 269 boolean isKotlinObject = 270 metadataUtil.isObjectClass(contributedBy) 271 || metadataUtil.isCompanionObjectClass(contributedBy); 272 return builder 273 .contributionType(ContributionType.fromBindingElement(method)) 274 .bindingElement(method) 275 .contributingModule(contributedBy) 276 .isContributingModuleKotlinObject(isKotlinObject) 277 .key(key) 278 .dependencies( 279 dependencyRequestFactory.forRequiredResolvedVariables( 280 method.getParameters(), methodType.getParameterTypes())) 281 .wrappedMapKeyAnnotation(wrapOptionalInEquivalence(getMapKey(method))); 282 } 283 284 /** 285 * Returns a {@link dagger.model.BindingKind#MULTIBOUND_MAP} or {@link 286 * dagger.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding contribution 287 * bindings. 288 * 289 * @param key a key that may be satisfied by a multibinding 290 */ syntheticMultibinding( Key key, Iterable<ContributionBinding> multibindingContributions)291 public ContributionBinding syntheticMultibinding( 292 Key key, Iterable<ContributionBinding> multibindingContributions) { 293 ContributionBinding.Builder<?, ?> builder = 294 multibindingRequiresProduction(key, multibindingContributions) 295 ? ProductionBinding.builder() 296 : ProvisionBinding.builder(); 297 return builder 298 .contributionType(ContributionType.UNIQUE) 299 .key(key) 300 .dependencies( 301 dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions)) 302 .kind(bindingKindForMultibindingKey(key)) 303 .build(); 304 } 305 multibindingRequiresProduction( Key key, Iterable<ContributionBinding> multibindingContributions)306 private boolean multibindingRequiresProduction( 307 Key key, Iterable<ContributionBinding> multibindingContributions) { 308 if (MapType.isMap(key)) { 309 MapType mapType = MapType.from(key); 310 if (mapType.valuesAreTypeOf(Producer.class) || mapType.valuesAreTypeOf(Produced.class)) { 311 return true; 312 } 313 } else if (SetType.isSet(key) && SetType.from(key).elementsAreTypeOf(Produced.class)) { 314 return true; 315 } 316 return Iterables.any( 317 multibindingContributions, binding -> binding.bindingType().equals(BindingType.PRODUCTION)); 318 } 319 320 /** Returns a {@link dagger.model.BindingKind#COMPONENT} binding for the component. */ componentBinding(TypeElement componentDefinitionType)321 public ProvisionBinding componentBinding(TypeElement componentDefinitionType) { 322 checkNotNull(componentDefinitionType); 323 return ProvisionBinding.builder() 324 .contributionType(ContributionType.UNIQUE) 325 .bindingElement(componentDefinitionType) 326 .key(keyFactory.forType(componentDefinitionType.asType())) 327 .kind(COMPONENT) 328 .build(); 329 } 330 331 /** 332 * Returns a {@link dagger.model.BindingKind#COMPONENT_DEPENDENCY} binding for a component's 333 * dependency. 334 */ componentDependencyBinding(ComponentRequirement dependency)335 public ProvisionBinding componentDependencyBinding(ComponentRequirement dependency) { 336 checkNotNull(dependency); 337 return ProvisionBinding.builder() 338 .contributionType(ContributionType.UNIQUE) 339 .bindingElement(dependency.typeElement()) 340 .key(keyFactory.forType(dependency.type())) 341 .kind(COMPONENT_DEPENDENCY) 342 .build(); 343 } 344 345 /** 346 * Returns a {@link dagger.model.BindingKind#COMPONENT_PROVISION} or {@link 347 * dagger.model.BindingKind#COMPONENT_PRODUCTION} binding for a method on a component's 348 * dependency. 349 * 350 * @param componentDescriptor the component with the dependency, not the dependency that has the 351 * method 352 */ componentDependencyMethodBinding( ComponentDescriptor componentDescriptor, ExecutableElement dependencyMethod)353 public ContributionBinding componentDependencyMethodBinding( 354 ComponentDescriptor componentDescriptor, ExecutableElement dependencyMethod) { 355 checkArgument(dependencyMethod.getKind().equals(METHOD)); 356 checkArgument(dependencyMethod.getParameters().isEmpty()); 357 ContributionBinding.Builder<?, ?> builder; 358 if (componentDescriptor.isProduction() 359 && isComponentProductionMethod(elements, dependencyMethod)) { 360 builder = 361 ProductionBinding.builder() 362 .key(keyFactory.forProductionComponentMethod(dependencyMethod)) 363 .kind(COMPONENT_PRODUCTION) 364 .thrownTypes(dependencyMethod.getThrownTypes()); 365 } else { 366 builder = 367 ProvisionBinding.builder() 368 .key(keyFactory.forComponentMethod(dependencyMethod)) 369 .nullableType(getNullableType(dependencyMethod)) 370 .kind(COMPONENT_PROVISION) 371 .scope(uniqueScopeOf(dependencyMethod)); 372 } 373 return builder 374 .contributionType(ContributionType.UNIQUE) 375 .bindingElement(dependencyMethod) 376 .build(); 377 } 378 379 /** 380 * Returns a {@link dagger.model.BindingKind#BOUND_INSTANCE} binding for a 381 * {@code @BindsInstance}-annotated builder setter method or factory method parameter. 382 */ boundInstanceBinding(ComponentRequirement requirement, Element element)383 ProvisionBinding boundInstanceBinding(ComponentRequirement requirement, Element element) { 384 checkArgument(element instanceof VariableElement || element instanceof ExecutableElement); 385 VariableElement parameterElement = 386 element instanceof VariableElement 387 ? MoreElements.asVariable(element) 388 : getOnlyElement(MoreElements.asExecutable(element).getParameters()); 389 return ProvisionBinding.builder() 390 .contributionType(ContributionType.UNIQUE) 391 .bindingElement(element) 392 .key(requirement.key().get()) 393 .nullableType(getNullableType(parameterElement)) 394 .kind(BOUND_INSTANCE) 395 .build(); 396 } 397 398 /** 399 * Returns a {@link dagger.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared by a component 400 * method that returns a subcomponent builder. Use {{@link 401 * #subcomponentCreatorBinding(ImmutableSet)}} for bindings declared using {@link 402 * Module#subcomponents()}. 403 * 404 * @param component the component that declares or inherits the method 405 */ subcomponentCreatorBinding( ExecutableElement subcomponentCreatorMethod, TypeElement component)406 ProvisionBinding subcomponentCreatorBinding( 407 ExecutableElement subcomponentCreatorMethod, TypeElement component) { 408 checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD)); 409 checkArgument(subcomponentCreatorMethod.getParameters().isEmpty()); 410 Key key = 411 keyFactory.forSubcomponentCreatorMethod( 412 subcomponentCreatorMethod, asDeclared(component.asType())); 413 return ProvisionBinding.builder() 414 .contributionType(ContributionType.UNIQUE) 415 .bindingElement(subcomponentCreatorMethod) 416 .key(key) 417 .kind(SUBCOMPONENT_CREATOR) 418 .build(); 419 } 420 421 /** 422 * Returns a {@link dagger.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared using {@link 423 * Module#subcomponents()}. 424 */ subcomponentCreatorBinding( ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations)425 ProvisionBinding subcomponentCreatorBinding( 426 ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) { 427 SubcomponentDeclaration subcomponentDeclaration = subcomponentDeclarations.iterator().next(); 428 return ProvisionBinding.builder() 429 .contributionType(ContributionType.UNIQUE) 430 .key(subcomponentDeclaration.key()) 431 .kind(SUBCOMPONENT_CREATOR) 432 .build(); 433 } 434 435 /** 436 * Returns a {@link dagger.model.BindingKind#DELEGATE} binding. 437 * 438 * @param delegateDeclaration the {@code @Binds}-annotated declaration 439 * @param actualBinding the binding that satisfies the {@code @Binds} declaration 440 */ delegateBinding( DelegateDeclaration delegateDeclaration, ContributionBinding actualBinding)441 ContributionBinding delegateBinding( 442 DelegateDeclaration delegateDeclaration, ContributionBinding actualBinding) { 443 switch (actualBinding.bindingType()) { 444 case PRODUCTION: 445 return buildDelegateBinding( 446 ProductionBinding.builder().nullableType(actualBinding.nullableType()), 447 delegateDeclaration, 448 Producer.class); 449 450 case PROVISION: 451 return buildDelegateBinding( 452 ProvisionBinding.builder() 453 .scope(uniqueScopeOf(delegateDeclaration.bindingElement().get())) 454 .nullableType(actualBinding.nullableType()), 455 delegateDeclaration, 456 Provider.class); 457 458 case MEMBERS_INJECTION: // fall-through to throw 459 } 460 throw new AssertionError("bindingType: " + actualBinding); 461 } 462 463 /** 464 * Returns a {@link dagger.model.BindingKind#DELEGATE} binding used when there is no binding that 465 * satisfies the {@code @Binds} declaration. 466 */ unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration)467 public ContributionBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) { 468 return buildDelegateBinding( 469 ProvisionBinding.builder().scope(uniqueScopeOf(delegateDeclaration.bindingElement().get())), 470 delegateDeclaration, 471 Provider.class); 472 } 473 buildDelegateBinding( ContributionBinding.Builder<?, ?> builder, DelegateDeclaration delegateDeclaration, Class<?> frameworkType)474 private ContributionBinding buildDelegateBinding( 475 ContributionBinding.Builder<?, ?> builder, 476 DelegateDeclaration delegateDeclaration, 477 Class<?> frameworkType) { 478 boolean isKotlinObject = 479 metadataUtil.isObjectClass(delegateDeclaration.contributingModule().get()) 480 || metadataUtil.isCompanionObjectClass(delegateDeclaration.contributingModule().get()); 481 return builder 482 .contributionType(delegateDeclaration.contributionType()) 483 .bindingElement(delegateDeclaration.bindingElement().get()) 484 .contributingModule(delegateDeclaration.contributingModule().get()) 485 .isContributingModuleKotlinObject(isKotlinObject) 486 .key(keyFactory.forDelegateBinding(delegateDeclaration, frameworkType)) 487 .dependencies(delegateDeclaration.delegateRequest()) 488 .wrappedMapKeyAnnotation(delegateDeclaration.wrappedMapKey()) 489 .kind(DELEGATE) 490 .build(); 491 } 492 493 /** 494 * Returns an {@link dagger.model.BindingKind#OPTIONAL} binding for {@code key}. 495 * 496 * @param requestKind the kind of request for the optional binding 497 * @param underlyingKeyBindings the possibly empty set of bindings that exist in the component for 498 * the underlying (non-optional) key 499 */ syntheticOptionalBinding( Key key, RequestKind requestKind, ImmutableCollection<? extends Binding> underlyingKeyBindings)500 ContributionBinding syntheticOptionalBinding( 501 Key key, 502 RequestKind requestKind, 503 ImmutableCollection<? extends Binding> underlyingKeyBindings) { 504 if (underlyingKeyBindings.isEmpty()) { 505 return ProvisionBinding.builder() 506 .contributionType(ContributionType.UNIQUE) 507 .key(key) 508 .kind(OPTIONAL) 509 .build(); 510 } 511 512 boolean requiresProduction = 513 underlyingKeyBindings.stream() 514 .anyMatch(binding -> binding.bindingType() == BindingType.PRODUCTION) 515 || requestKind.equals(RequestKind.PRODUCER) // handles producerFromProvider cases 516 || requestKind.equals(RequestKind.PRODUCED); // handles producerFromProvider cases 517 518 return (requiresProduction ? ProductionBinding.builder() : ProvisionBinding.builder()) 519 .contributionType(ContributionType.UNIQUE) 520 .key(key) 521 .kind(OPTIONAL) 522 .dependencies(dependencyRequestFactory.forSyntheticPresentOptionalBinding(key, requestKind)) 523 .build(); 524 } 525 526 /** Returns a {@link dagger.model.BindingKind#MEMBERS_INJECTOR} binding. */ membersInjectorBinding( Key key, MembersInjectionBinding membersInjectionBinding)527 public ProvisionBinding membersInjectorBinding( 528 Key key, MembersInjectionBinding membersInjectionBinding) { 529 return ProvisionBinding.builder() 530 .key(key) 531 .contributionType(ContributionType.UNIQUE) 532 .kind(MEMBERS_INJECTOR) 533 .bindingElement(MoreTypes.asTypeElement(membersInjectionBinding.key().type())) 534 .provisionDependencies(membersInjectionBinding.dependencies()) 535 .injectionSites(membersInjectionBinding.injectionSites()) 536 .build(); 537 } 538 539 /** 540 * Returns a {@link dagger.model.BindingKind#MEMBERS_INJECTION} binding. 541 * 542 * @param resolvedType if {@code declaredType} is a generic class and {@code resolvedType} is a 543 * parameterization of that type, the returned binding will be for the resolved type 544 */ 545 // TODO(dpb): See if we can just pass one nongeneric/parameterized type. membersInjectionBinding( DeclaredType declaredType, Optional<TypeMirror> resolvedType)546 public MembersInjectionBinding membersInjectionBinding( 547 DeclaredType declaredType, Optional<TypeMirror> resolvedType) { 548 // If the class this is injecting has some type arguments, resolve everything. 549 if (!declaredType.getTypeArguments().isEmpty() && resolvedType.isPresent()) { 550 DeclaredType resolved = asDeclared(resolvedType.get()); 551 // Validate that we're resolving from the correct type. 552 checkState( 553 types.isSameType(types.erasure(resolved), types.erasure(declaredType)), 554 "erased expected type: %s, erased actual type: %s", 555 types.erasure(resolved), 556 types.erasure(declaredType)); 557 declaredType = resolved; 558 } 559 ImmutableSortedSet<InjectionSite> injectionSites = 560 injectionSiteFactory.getInjectionSites(declaredType); 561 ImmutableSet<DependencyRequest> dependencies = 562 injectionSites.stream() 563 .flatMap(injectionSite -> injectionSite.dependencies().stream()) 564 .collect(toImmutableSet()); 565 566 Key key = keyFactory.forMembersInjectedType(declaredType); 567 TypeElement typeElement = MoreElements.asType(declaredType.asElement()); 568 return new AutoValue_MembersInjectionBinding( 569 key, 570 dependencies, 571 typeElement, 572 hasNonDefaultTypeParameters(typeElement, key.type(), types) 573 ? Optional.of( 574 membersInjectionBinding(asDeclared(typeElement.asType()), Optional.empty())) 575 : Optional.empty(), 576 injectionSites); 577 } 578 } 579