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