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