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