• 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 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