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