• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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