• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 Google, Inc.
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 package dagger.internal.codegen;
17 
18 import com.google.auto.common.MoreElements;
19 import com.google.auto.common.MoreTypes;
20 import com.google.common.base.Joiner;
21 import com.google.common.base.Optional;
22 import com.google.common.collect.FluentIterable;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.ImmutableMap;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.collect.Iterables;
27 import com.google.common.collect.Lists;
28 import com.google.common.collect.Maps;
29 import com.google.common.collect.Sets;
30 import com.google.common.util.concurrent.ListenableFuture;
31 import dagger.MembersInjector;
32 import dagger.internal.DelegateFactory;
33 import dagger.internal.Factory;
34 import dagger.internal.InstanceFactory;
35 import dagger.internal.MapFactory;
36 import dagger.internal.MapProviderFactory;
37 import dagger.internal.MembersInjectors;
38 import dagger.internal.ScopedProvider;
39 import dagger.internal.SetFactory;
40 import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
41 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
42 import dagger.internal.codegen.ComponentGenerator.MemberSelect;
43 import dagger.internal.codegen.writer.ClassName;
44 import dagger.internal.codegen.writer.ClassWriter;
45 import dagger.internal.codegen.writer.ConstructorWriter;
46 import dagger.internal.codegen.writer.FieldWriter;
47 import dagger.internal.codegen.writer.JavaWriter;
48 import dagger.internal.codegen.writer.MethodWriter;
49 import dagger.internal.codegen.writer.ParameterizedTypeName;
50 import dagger.internal.codegen.writer.Snippet;
51 import dagger.internal.codegen.writer.StringLiteral;
52 import dagger.internal.codegen.writer.TypeName;
53 import dagger.internal.codegen.writer.TypeNames;
54 import dagger.internal.codegen.writer.VoidName;
55 import dagger.producers.Producer;
56 import dagger.producers.internal.Producers;
57 import dagger.producers.internal.SetOfProducedProducer;
58 import dagger.producers.internal.SetProducer;
59 import java.util.Collection;
60 import java.util.HashMap;
61 import java.util.HashSet;
62 import java.util.LinkedHashSet;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Set;
66 import javax.inject.Provider;
67 import javax.lang.model.element.Element;
68 import javax.lang.model.element.ElementKind;
69 import javax.lang.model.element.ExecutableElement;
70 import javax.lang.model.element.Name;
71 import javax.lang.model.element.TypeElement;
72 import javax.lang.model.element.VariableElement;
73 import javax.lang.model.type.DeclaredType;
74 import javax.lang.model.type.ExecutableType;
75 import javax.lang.model.type.TypeKind;
76 import javax.lang.model.type.TypeMirror;
77 import javax.lang.model.util.Elements;
78 import javax.lang.model.util.Types;
79 import javax.tools.Diagnostic;
80 import javax.tools.Diagnostic.Kind;
81 
82 import static com.google.auto.common.MoreTypes.asDeclared;
83 import static com.google.common.base.CaseFormat.LOWER_CAMEL;
84 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
85 import static com.google.common.base.Preconditions.checkState;
86 import static com.google.common.collect.Iterables.any;
87 import static com.google.common.collect.Iterables.getOnlyElement;
88 import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.DELEGATED;
89 import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.INITIALIZED;
90 import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED;
91 import static dagger.internal.codegen.Binding.bindingPackageFor;
92 import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticMethodInvocationWithCast;
93 import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticSelect;
94 import static dagger.internal.codegen.ContributionBinding.contributionTypeFor;
95 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.ENUM_INSTANCE;
96 import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION;
97 import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD;
98 import static dagger.internal.codegen.MapKeys.getMapKeySnippet;
99 import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
100 import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
101 import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
102 import static dagger.internal.codegen.SourceFiles.indexDependenciesByUnresolvedKey;
103 import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
104 import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
105 import static dagger.internal.codegen.Util.getKeyTypeOfMap;
106 import static dagger.internal.codegen.Util.getProvidedValueTypeOfMap;
107 import static dagger.internal.codegen.Util.isMapWithNonProvidedValues;
108 import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
109 import static dagger.internal.codegen.writer.Snippet.memberSelectSnippet;
110 import static dagger.internal.codegen.writer.Snippet.nullCheck;
111 import static javax.lang.model.element.Modifier.ABSTRACT;
112 import static javax.lang.model.element.Modifier.FINAL;
113 import static javax.lang.model.element.Modifier.PRIVATE;
114 import static javax.lang.model.element.Modifier.PUBLIC;
115 import static javax.lang.model.element.Modifier.STATIC;
116 import static javax.lang.model.type.TypeKind.DECLARED;
117 import static javax.lang.model.type.TypeKind.VOID;
118 
119 /**
120  * Creates the implementation class for a component or subcomponent.
121  */
122 abstract class AbstractComponentWriter {
123   // TODO(dpb): Make all these fields private after refactoring is complete.
124   protected final Elements elements;
125   protected final Types types;
126   protected final Key.Factory keyFactory;
127   protected final Kind nullableValidationType;
128   protected final Set<JavaWriter> javaWriters = new LinkedHashSet<>();
129   protected final ClassName name;
130   protected final BindingGraph graph;
131   private final Map<BindingKey, InitializationState> initializationStates = new HashMap<>();
132   private final Map<Binding, InitializationState> contributionInitializationStates =
133       new HashMap<>();
134   protected ClassWriter componentWriter;
135   private final Map<BindingKey, MemberSelect> memberSelectSnippets = new HashMap<>();
136   private final Map<ContributionBinding, MemberSelect> multibindingContributionSnippets =
137       new HashMap<>();
138   protected ConstructorWriter constructorWriter;
139   protected Optional<ClassName> builderName = Optional.absent();
140 
141   /**
142    * For each component requirement, the builder field. This map is empty for subcomponents that do
143    * not use a builder.
144    */
145   private ImmutableMap<TypeElement, FieldWriter> builderFields = ImmutableMap.of();
146 
147   /**
148    * For each component requirement, the snippet for the component field that holds it.
149    *
150    * <p>Fields are written for all requirements for subcomponents that do not use a builder, and for
151    * any requirement that is reused from a subcomponent of this component.
152    */
153   protected final Map<TypeElement, MemberSelect> componentContributionFields = Maps.newHashMap();
154 
AbstractComponentWriter( Types types, Elements elements, Key.Factory keyFactory, Diagnostic.Kind nullableValidationType, ClassName name, BindingGraph graph)155   AbstractComponentWriter(
156       Types types,
157       Elements elements,
158       Key.Factory keyFactory,
159       Diagnostic.Kind nullableValidationType,
160       ClassName name,
161       BindingGraph graph) {
162     this.types = types;
163     this.elements = elements;
164     this.keyFactory = keyFactory;
165     this.nullableValidationType = nullableValidationType;
166     this.name = name;
167     this.graph = graph;
168   }
169 
componentDefinitionType()170   protected final TypeElement componentDefinitionType() {
171     return graph.componentDescriptor().componentDefinitionType();
172   }
173 
componentDefinitionTypeName()174   protected final ClassName componentDefinitionTypeName() {
175     return ClassName.fromTypeElement(componentDefinitionType());
176   }
177 
178   /**
179    * Returns an expression snippet that evaluates to an instance of the contribution, looking for
180    * either a builder field or a component field.
181    */
getComponentContributionSnippet(TypeElement contributionType)182   private Snippet getComponentContributionSnippet(TypeElement contributionType) {
183     if (builderFields.containsKey(contributionType)) {
184       return Snippet.format("builder.%s", builderFields.get(contributionType).name());
185     } else {
186       Optional<Snippet> snippet = getOrCreateComponentContributionFieldSnippet(contributionType);
187       checkState(snippet.isPresent(), "no builder or component field for %s", contributionType);
188       return snippet.get();
189     }
190   }
191 
192   /**
193    * Returns a snippet for a component contribution field. Adds a field the first time one is
194    * requested for a contribution type if this component's builder has a field for it.
195    */
getOrCreateComponentContributionFieldSnippet( TypeElement contributionType)196   protected Optional<Snippet> getOrCreateComponentContributionFieldSnippet(
197       TypeElement contributionType) {
198     MemberSelect fieldSelect = componentContributionFields.get(contributionType);
199     if (fieldSelect == null) {
200       if (!builderFields.containsKey(contributionType)) {
201         return Optional.absent();
202       }
203       FieldWriter componentField =
204           componentWriter.addField(contributionType, simpleVariableName(contributionType));
205       componentField.addModifiers(PRIVATE, FINAL);
206       constructorWriter
207           .body()
208           .addSnippet(
209               "this.%s = builder.%s;",
210               componentField.name(),
211               builderFields.get(contributionType).name());
212       fieldSelect = MemberSelect.instanceSelect(name, Snippet.format("%s", componentField.name()));
213       componentContributionFields.put(contributionType, fieldSelect);
214     }
215     return Optional.of(fieldSelect.getSnippetFor(name));
216   }
217 
getMemberSelectSnippet(BindingKey key)218   private Snippet getMemberSelectSnippet(BindingKey key) {
219     return getMemberSelect(key).getSnippetFor(name);
220   }
221 
getMemberSelect(BindingKey key)222   protected MemberSelect getMemberSelect(BindingKey key) {
223     return memberSelectSnippets.get(key);
224   }
225 
getMultibindingContributionSnippet(ContributionBinding binding)226   protected Optional<MemberSelect> getMultibindingContributionSnippet(ContributionBinding binding) {
227     return Optional.fromNullable(multibindingContributionSnippets.get(binding));
228   }
229 
230   /**
231    * Returns the initialization state of the factory field for a binding key in this component.
232    */
getInitializationState(BindingKey bindingKey)233   protected InitializationState getInitializationState(BindingKey bindingKey) {
234     return initializationStates.containsKey(bindingKey)
235         ? initializationStates.get(bindingKey)
236         : UNINITIALIZED;
237   }
238 
setInitializationState(BindingKey bindingKey, InitializationState state)239   private void setInitializationState(BindingKey bindingKey, InitializationState state) {
240     initializationStates.put(bindingKey, state);
241   }
242 
getContributionInitializationState(Binding binding)243   private InitializationState getContributionInitializationState(Binding binding) {
244     return contributionInitializationStates.containsKey(binding)
245         ? contributionInitializationStates.get(binding)
246         : UNINITIALIZED;
247   }
248 
setContributionInitializationState(Binding binding, InitializationState state)249   private void setContributionInitializationState(Binding binding, InitializationState state) {
250     contributionInitializationStates.put(binding, state);
251   }
252 
write()253   ImmutableSet<JavaWriter> write() {
254     if (javaWriters.isEmpty()) {
255       writeComponent();
256     }
257     return ImmutableSet.copyOf(javaWriters);
258   }
259 
writeComponent()260   private void writeComponent() {
261     componentWriter = createComponentClass();
262     addConstructor();
263     addBuilder();
264     addFactoryMethods();
265     addFields();
266     initializeFrameworkTypes();
267     implementInterfaceMethods();
268     addSubcomponents();
269   }
270 
271   /**
272    * Creates the component implementation class.
273    */
createComponentClass()274   protected abstract ClassWriter createComponentClass();
275 
addConstructor()276   private void addConstructor() {
277     constructorWriter = componentWriter.addConstructor();
278     constructorWriter.addModifiers(PRIVATE);
279   }
280 
281   /**
282    * Adds a builder type.
283    */
addBuilder()284   protected void addBuilder() {
285     ClassWriter builderWriter = createBuilder();
286     builderWriter.addModifiers(FINAL);
287     builderWriter.addConstructor().addModifiers(PRIVATE);
288     builderName = Optional.of(builderWriter.name());
289 
290     Optional<BuilderSpec> builderSpec = graph.componentDescriptor().builderSpec();
291     if (builderSpec.isPresent()) {
292       builderWriter.addModifiers(PRIVATE);
293       builderWriter.setSupertype(builderSpec.get().builderDefinitionType());
294     } else {
295       builderWriter.addModifiers(PUBLIC);
296     }
297 
298     builderFields = addBuilderFields(builderWriter);
299     addBuildMethod(builderWriter, builderSpec);
300     addBuilderMethods(builderWriter, builderSpec);
301 
302     constructorWriter.addParameter(builderWriter, "builder");
303     constructorWriter.body().addSnippet("assert builder != null;");
304   }
305 
306   /**
307    * Adds fields for each of the {@linkplain BindingGraph#componentRequirements component
308    * requirements}. Regardless of builder spec, there is always one field per requirement.
309    */
addBuilderFields(ClassWriter builderWriter)310   private ImmutableMap<TypeElement, FieldWriter> addBuilderFields(ClassWriter builderWriter) {
311     ImmutableMap.Builder<TypeElement, FieldWriter> builderFieldsBuilder = ImmutableMap.builder();
312     for (TypeElement contributionElement : graph.componentRequirements()) {
313       String contributionName = simpleVariableName(contributionElement);
314       FieldWriter builderField = builderWriter.addField(contributionElement, contributionName);
315       builderField.addModifiers(PRIVATE);
316       builderFieldsBuilder.put(contributionElement, builderField);
317     }
318     return builderFieldsBuilder.build();
319   }
320 
321   /** Adds the build method to the builder. */
addBuildMethod(ClassWriter builderWriter, Optional<BuilderSpec> builderSpec)322   private void addBuildMethod(ClassWriter builderWriter, Optional<BuilderSpec> builderSpec) {
323     MethodWriter buildMethod;
324     if (builderSpec.isPresent()) {
325       ExecutableElement specBuildMethod = builderSpec.get().buildMethod();
326       // Note: we don't use the specBuildMethod.getReturnType() as the return type
327       // because it might be a type variable.  We make use of covariant returns to allow
328       // us to return the component type, which will always be valid.
329       buildMethod =
330           builderWriter.addMethod(
331               componentDefinitionTypeName(), specBuildMethod.getSimpleName().toString());
332       buildMethod.annotate(Override.class);
333     } else {
334       buildMethod = builderWriter.addMethod(componentDefinitionTypeName(), "build");
335     }
336     buildMethod.addModifiers(PUBLIC);
337 
338     for (Map.Entry<TypeElement, FieldWriter> builderFieldEntry : builderFields.entrySet()) {
339       FieldWriter builderField = builderFieldEntry.getValue();
340       if (componentCanMakeNewInstances(builderFieldEntry.getKey())) {
341         buildMethod.body()
342             .addSnippet("if (%1$s == null) { this.%1$s = new %2$s(); }",
343                 builderField.name(),
344                 builderField.type());
345       } else {
346         buildMethod.body()
347             .addSnippet(
348                 "if (%s == null) { throw new %s(%s.class.getCanonicalName() + \" must be set\"); }",
349                 builderField.name(),
350                 ClassName.fromClass(IllegalStateException.class),
351                 builderField.type());
352       }
353     }
354 
355     buildMethod.body().addSnippet("return new %s(this);", name);
356   }
357 
358   /**
359    * Adds the methods that set each of parameters on the builder. If the {@link BuilderSpec} is
360    * present, it will tailor the methods to match the spec.
361    */
addBuilderMethods( ClassWriter builderWriter, Optional<BuilderSpec> builderSpec)362   private void addBuilderMethods(
363       ClassWriter builderWriter,
364       Optional<BuilderSpec> builderSpec) {
365     if (builderSpec.isPresent()) {
366       for (Map.Entry<TypeElement, ExecutableElement> builderMethodEntry :
367           builderSpec.get().methodMap().entrySet()) {
368         TypeElement builderMethodType = builderMethodEntry.getKey();
369         ExecutableElement specMethod = builderMethodEntry.getValue();
370         MethodWriter builderMethod = addBuilderMethodFromSpec(builderWriter, specMethod);
371         String parameterName =
372             Iterables.getOnlyElement(specMethod.getParameters()).getSimpleName().toString();
373         builderMethod.addParameter(builderMethodType, parameterName);
374         builderMethod.body().addSnippet(nullCheck(parameterName));
375         if (graph.componentRequirements().contains(builderMethodType)) {
376           // required type
377           builderMethod.body().addSnippet("this.%s = %s;",
378               builderFields.get(builderMethodType).name(),
379               parameterName);
380           addBuilderMethodReturnStatementForSpec(specMethod, builderMethod);
381         } else if (graph.ownedModuleTypes().contains(builderMethodType)) {
382           // owned, but not required
383           builderMethod.body()
384               .addSnippet("// This module is declared, but not used in the component. "
385                   + "This method is a no-op");
386           addBuilderMethodReturnStatementForSpec(specMethod, builderMethod);
387         } else {
388           // neither owned nor required, so it must be an inherited module
389           builderMethod
390               .body()
391               .addSnippet(
392                   "throw new %s(%s.format(%s, %s.class.getCanonicalName()));",
393                   ClassName.fromClass(UnsupportedOperationException.class),
394                   ClassName.fromClass(String.class),
395                   StringLiteral.forValue(
396                       "%s cannot be set because it is inherited from the enclosing component"),
397                   ClassName.fromTypeElement(builderMethodType));
398         }
399       }
400     } else {
401       for (TypeElement componentRequirement : graph.availableDependencies()) {
402         String componentRequirementName = simpleVariableName(componentRequirement);
403         MethodWriter builderMethod = builderWriter.addMethod(
404             builderWriter.name(),
405             componentRequirementName);
406         builderMethod.addModifiers(PUBLIC);
407         builderMethod.addParameter(componentRequirement, componentRequirementName);
408         builderMethod.body().addSnippet(nullCheck(componentRequirementName));
409         if (graph.componentRequirements().contains(componentRequirement)) {
410           builderMethod.body()
411               .addSnippet("this.%s = %s;",
412                   builderFields.get(componentRequirement).name(),
413                   componentRequirementName);
414         } else {
415           builderMethod.annotate(Deprecated.class);
416         }
417         builderMethod.body().addSnippet("return this;");
418       }
419     }
420   }
421 
addBuilderMethodReturnStatementForSpec( ExecutableElement specMethod, MethodWriter builderMethod)422   private void addBuilderMethodReturnStatementForSpec(
423       ExecutableElement specMethod, MethodWriter builderMethod) {
424     if (!specMethod.getReturnType().getKind().equals(VOID)) {
425       builderMethod.body().addSnippet("return this;");
426     }
427   }
428 
addBuilderMethodFromSpec( ClassWriter builderWriter, ExecutableElement method)429   private MethodWriter addBuilderMethodFromSpec(
430       ClassWriter builderWriter, ExecutableElement method) {
431     String methodName = method.getSimpleName().toString();
432     TypeMirror returnType = method.getReturnType();
433     // If the return type is void, we add a method with the void return type.
434     // Otherwise we use the builderWriter and take advantage of covariant returns
435     // (so that we don't have to worry about setter methods that return type variables).
436     MethodWriter builderMethod =
437         returnType.getKind().equals(TypeKind.VOID)
438             ? builderWriter.addMethod(returnType, methodName)
439             : builderWriter.addMethod(builderWriter, methodName);
440     builderMethod.annotate(Override.class);
441     builderMethod.addModifiers(Sets.difference(method.getModifiers(), ImmutableSet.of(ABSTRACT)));
442     return builderMethod;
443   }
444 
445   /**
446    * Creates the builder class.
447    */
createBuilder()448   protected abstract ClassWriter createBuilder();
449 
450   /**
451    * Adds component factory methods.
452    */
addFactoryMethods()453   protected abstract void addFactoryMethods();
454 
addFields()455   private void addFields() {
456     for (ResolvedBindings resolvedBindings : graph.resolvedBindings().values()) {
457       addField(resolvedBindings);
458     }
459   }
460 
addField(ResolvedBindings resolvedBindings)461   private void addField(ResolvedBindings resolvedBindings) {
462     BindingKey bindingKey = resolvedBindings.bindingKey();
463 
464     // No field needed if there are no owned bindings.
465     if (resolvedBindings.ownedBindings().isEmpty()) {
466       return;
467     }
468 
469     // No field needed for bindings with no dependencies or state.
470     Optional<MemberSelect> staticMemberSelect = staticMemberSelect(resolvedBindings);
471     if (staticMemberSelect.isPresent()) {
472       memberSelectSnippets.put(bindingKey, staticMemberSelect.get());
473       return;
474     }
475 
476     Optional<String> bindingPackage = bindingPackageFor(resolvedBindings.bindings());
477     boolean useRawType = bindingPackage.isPresent()
478         && !bindingPackage.get().equals(name.packageName());
479     if (bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION)) {
480       ImmutableSet<ContributionBinding> contributionBindings =
481           resolvedBindings.contributionBindings();
482       if (ContributionBinding.contributionTypeFor(contributionBindings).isMultibinding()) {
483         // note that here we rely on the order of the resolved bindings being from parent to child
484         // otherwise, the numbering wouldn't work
485         int contributionNumber = 0;
486         for (ContributionBinding contributionBinding : contributionBindings) {
487           if (!contributionBinding.isSyntheticBinding()) {
488             contributionNumber++;
489             if (resolvedBindings.ownedContributionBindings().contains(contributionBinding)) {
490               FrameworkField contributionBindingField =
491                   FrameworkField.createForSyntheticContributionBinding(
492                       contributionNumber, contributionBinding);
493               FieldWriter contributionField =
494                   addFrameworkField(useRawType, contributionBindingField);
495 
496               ImmutableList<String> contributionSelectTokens =
497                   new ImmutableList.Builder<String>()
498                       .add(contributionField.name())
499                       .build();
500               multibindingContributionSnippets.put(
501                   contributionBinding,
502                   MemberSelect.instanceSelect(name, memberSelectSnippet(contributionSelectTokens)));
503             }
504           }
505         }
506       }
507     }
508 
509     FrameworkField bindingField = FrameworkField.createForResolvedBindings(resolvedBindings);
510     FieldWriter frameworkField = addFrameworkField(useRawType, bindingField);
511 
512     ImmutableList<String> memberSelectTokens =
513         new ImmutableList.Builder<String>()
514             .add(frameworkField.name())
515             .build();
516     memberSelectSnippets.put(
517         bindingKey,
518         MemberSelect.instanceSelect(name, Snippet.memberSelectSnippet(memberSelectTokens)));
519   }
520 
addFrameworkField(boolean useRawType, FrameworkField contributionBindingField)521   private FieldWriter addFrameworkField(boolean useRawType,
522       FrameworkField contributionBindingField) {
523     FieldWriter contributionField =
524         componentWriter.addField(
525             useRawType
526                 ? contributionBindingField.frameworkType().type()
527                 : contributionBindingField.frameworkType(),
528             contributionBindingField.name());
529     contributionField.addModifiers(PRIVATE);
530     if (useRawType) {
531       contributionField.annotate(SuppressWarnings.class).setValue("rawtypes");
532     }
533     return contributionField;
534   }
535 
536   /**
537    * If {@code resolvedBindings} is an unscoped provision binding with no factory arguments or a
538    * no-op members injection binding, then we don't need a field to hold its factory. In that case,
539    * this method returns the static member select snippet that returns the factory or no-op members
540    * injector.
541    */
staticMemberSelect(ResolvedBindings resolvedBindings)542   private Optional<MemberSelect> staticMemberSelect(ResolvedBindings resolvedBindings) {
543     switch (resolvedBindings.bindingKey().kind()) {
544       case CONTRIBUTION:
545         if (resolvedBindings.contributionBindings().size() != 1) {
546           return Optional.absent();
547         }
548         ContributionBinding contributionBinding =
549             getOnlyElement(resolvedBindings.contributionBindings());
550         if (contributionBinding.contributionType().isMultibinding()
551             || !(contributionBinding.bindingType().equals(Binding.Type.PROVISION))) {
552           return Optional.absent();
553         }
554         if (contributionBinding.factoryCreationStrategy().equals(ENUM_INSTANCE)
555             && !contributionBinding.scope().isPresent()) {
556           return Optional.of(
557               staticSelect(
558                   generatedClassNameForBinding(contributionBinding), Snippet.format("create()")));
559         }
560         break;
561 
562       case MEMBERS_INJECTION:
563         Optional<MembersInjectionBinding> membersInjectionBinding =
564             resolvedBindings.membersInjectionBinding();
565         if (membersInjectionBinding.isPresent()
566             && membersInjectionBinding.get().injectionStrategy().equals(NO_OP)) {
567           return Optional.of(
568               staticMethodInvocationWithCast(
569                   ClassName.fromClass(MembersInjectors.class),
570                   Snippet.format("noOp()"),
571                   ClassName.fromClass(MembersInjector.class)));
572         }
573         break;
574 
575       default:
576         throw new AssertionError();
577     }
578     return Optional.absent();
579   }
580 
implementInterfaceMethods()581   private void implementInterfaceMethods() {
582     Set<MethodSignature> interfaceMethods = Sets.newHashSet();
583     for (ComponentMethodDescriptor componentMethod :
584         graph.componentDescriptor().componentMethods()) {
585       if (componentMethod.dependencyRequest().isPresent()) {
586         DependencyRequest interfaceRequest = componentMethod.dependencyRequest().get();
587         ExecutableElement requestElement =
588             MoreElements.asExecutable(interfaceRequest.requestElement());
589         ExecutableType requestType = MoreTypes.asExecutable(types.asMemberOf(
590             MoreTypes.asDeclared(componentDefinitionType().asType()), requestElement));
591         MethodSignature signature = MethodSignature.fromExecutableType(
592             requestElement.getSimpleName().toString(), requestType);
593         if (!interfaceMethods.contains(signature)) {
594           interfaceMethods.add(signature);
595           MethodWriter interfaceMethod =
596               requestType.getReturnType().getKind().equals(VOID)
597                   ? componentWriter.addMethod(
598                       VoidName.VOID, requestElement.getSimpleName().toString())
599                   : componentWriter.addMethod(
600                       requestType.getReturnType(), requestElement.getSimpleName().toString());
601           interfaceMethod.annotate(Override.class);
602           interfaceMethod.addModifiers(PUBLIC);
603           BindingKey bindingKey = interfaceRequest.bindingKey();
604           MemberSelect memberSelect = getMemberSelect(bindingKey);
605           Snippet memberSelectSnippet = memberSelect.getSnippetFor(name);
606           switch (interfaceRequest.kind()) {
607             case MEMBERS_INJECTOR:
608               List<? extends VariableElement> parameters = requestElement.getParameters();
609               if (parameters.isEmpty()) {
610                 // we're returning the framework type
611                 interfaceMethod.body().addSnippet("return %s;", memberSelectSnippet);
612               } else {
613                 VariableElement parameter = Iterables.getOnlyElement(parameters);
614                 Name parameterName = parameter.getSimpleName();
615                 interfaceMethod.addParameter(
616                     TypeNames.forTypeMirror(
617                         Iterables.getOnlyElement(requestType.getParameterTypes())),
618                     parameterName.toString());
619                 interfaceMethod
620                     .body()
621                     .addSnippet(
622                         "%s.injectMembers(%s);",
623                         memberSelectSnippet,
624                         parameterName);
625                 if (!requestType.getReturnType().getKind().equals(VOID)) {
626                   interfaceMethod.body().addSnippet("return %s;", parameterName);
627                 }
628               }
629               break;
630             case INSTANCE:
631               if (memberSelect.staticMember()
632                   && bindingKey.key().type().getKind().equals(DECLARED)
633                   && !((DeclaredType) bindingKey.key().type()).getTypeArguments().isEmpty()) {
634                 // If using a parameterized enum type, then we need to store the factory
635                 // in a temporary variable, in order to help javac be able to infer
636                 // the generics of the Factory.create methods.
637                 TypeName factoryType =
638                     ParameterizedTypeName.create(
639                         Provider.class, TypeNames.forTypeMirror(requestType.getReturnType()));
640                 interfaceMethod
641                     .body()
642                     .addSnippet(
643                         "%s factory = %s;", factoryType, memberSelectSnippet);
644                 interfaceMethod.body().addSnippet("return factory.get();");
645                 break;
646               }
647               // fall through in the else case.
648             case LAZY:
649             case PRODUCED:
650             case PRODUCER:
651             case PROVIDER:
652             case FUTURE:
653               interfaceMethod
654                   .body()
655                   .addSnippet(
656                       "return %s;",
657                       frameworkTypeUsageStatement(
658                           memberSelectSnippet, interfaceRequest.kind()));
659               break;
660             default:
661               throw new AssertionError();
662           }
663         }
664       }
665     }
666   }
667 
addSubcomponents()668   private void addSubcomponents() {
669     for (Map.Entry<ExecutableElement, BindingGraph> subgraphEntry : graph.subgraphs().entrySet()) {
670       SubcomponentWriter subcomponent =
671           new SubcomponentWriter(this, subgraphEntry.getKey(), subgraphEntry.getValue());
672       javaWriters.addAll(subcomponent.write());
673     }
674   }
675 
676   private static final int SNIPPETS_PER_INITIALIZATION_METHOD = 100;
677 
initializeFrameworkTypes()678   private void initializeFrameworkTypes() {
679     ImmutableList.Builder<Snippet> snippetsBuilder = ImmutableList.builder();
680     for (BindingKey bindingKey : graph.resolvedBindings().keySet()) {
681       snippetsBuilder.add(initializeFrameworkType(bindingKey));
682     }
683     ImmutableList<Snippet> snippets = snippetsBuilder.build();
684 
685     List<List<Snippet>> partitions = Lists.partition(snippets, SNIPPETS_PER_INITIALIZATION_METHOD);
686     for (int i = 0; i < partitions.size(); i++) {
687       MethodWriter initializeMethod =
688           componentWriter.addMethod(VoidName.VOID, "initialize" + ((i == 0) ? "" : i));
689       /* TODO(gak): Strictly speaking, we only need the suppression here if we are also initializing
690        * a raw field in this method, but the structure of this code makes it awkward to pass that
691        * bit through.  This will be cleaned up when we no longer separate fields and initilization
692        * as we do now. */
693       initializeMethod.annotate(SuppressWarnings.class).setValue("unchecked");
694       for (Snippet snippet : partitions.get(i)) {
695         initializeMethod.body().addSnippet(snippet);
696       }
697       initializeMethod.addModifiers(PRIVATE);
698       if (builderName.isPresent()) {
699         initializeMethod.addParameter(builderName.get(), "builder").addModifiers(FINAL);
700         constructorWriter.body().addSnippet("%s(builder);", initializeMethod.name());
701       } else {
702         constructorWriter.body().addSnippet("%s();", initializeMethod.name());
703       }
704     }
705   }
706 
707   /**
708    * Returns a single snippet representing the initialization of the framework type.
709    *
710    * <p>Note that this must be a single snippet because initialization snippets can be invoked from
711    * any place in any order.  By requiring a single snippet (often of concatenated snippets) we
712    * ensure that things like local variables always behave as expected by the initialization logic.
713    */
initializeFrameworkType(BindingKey bindingKey)714   private Snippet initializeFrameworkType(BindingKey bindingKey) {
715     ResolvedBindings resolvedBindings = graph.resolvedBindings().get(bindingKey);
716 
717     // There's no field for inherited bindings.
718     if (resolvedBindings.ownedBindings().isEmpty()) {
719       return Snippet.format("");
720     }
721 
722     switch (bindingKey.kind()) {
723       case CONTRIBUTION:
724         switch (contributionTypeFor(resolvedBindings.contributionBindings())) {
725           case SET:
726             return initializeSetMultibindings(resolvedBindings);
727           case MAP:
728             return initializeMapMultibindings(resolvedBindings);
729           case UNIQUE:
730             return initializeUniqueContributionBinding(resolvedBindings);
731           default:
732             throw new AssertionError();
733         }
734 
735       case MEMBERS_INJECTION:
736         return initializeMembersInjectionBinding(resolvedBindings);
737 
738       default:
739         throw new AssertionError();
740     }
741   }
742 
initializeSetMultibindings(ResolvedBindings resolvedBindings)743   private Snippet initializeSetMultibindings(ResolvedBindings resolvedBindings) {
744     ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
745 
746     ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder();
747     for (ContributionBinding binding : resolvedBindings.contributionBindings()) {
748       Optional<MemberSelect> multibindingContributionSnippet =
749           getMultibindingContributionSnippet(binding);
750       checkState(multibindingContributionSnippet.isPresent(), "%s was not found", binding);
751       Snippet snippet = multibindingContributionSnippet.get().getSnippetFor(name);
752       if (multibindingContributionSnippet.get().owningClass().equals(name)
753           // the binding might already be initialized by a different set binding that shares the
754           // same contributions (e.g., Set<T> and Set<Produced<T>>)
755           && getContributionInitializationState(binding)
756               .equals(InitializationState.UNINITIALIZED)) {
757         Snippet initializeSnippet = initializeFactoryForContributionBinding(binding);
758         initializationSnippets.add(Snippet.format("this.%s = %s;", snippet, initializeSnippet));
759         setContributionInitializationState(binding, InitializationState.INITIALIZED);
760       }
761       parameterSnippets.add(snippet);
762     }
763     Class<?> factoryClass =
764         Iterables.all(resolvedBindings.contributionBindings(), Binding.Type.PROVISION)
765             ? SetFactory.class
766             : Util.isSetOfProduced(resolvedBindings.bindingKey().key().type())
767                 ? SetOfProducedProducer.class
768                 : SetProducer.class;
769     Snippet initializeSetSnippet =
770         Snippet.format(
771             "%s.create(%s)",
772             ClassName.fromClass(factoryClass),
773             makeParametersSnippet(parameterSnippets.build()));
774     initializationSnippets.add(
775         initializeMember(resolvedBindings.bindingKey(), initializeSetSnippet));
776 
777     return Snippet.concat(initializationSnippets.build());
778   }
779 
initializeMapMultibindings(ResolvedBindings resolvedBindings)780   private Snippet initializeMapMultibindings(ResolvedBindings resolvedBindings) {
781     ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
782 
783     if (any(resolvedBindings.contributionBindings(), Binding.Type.PRODUCTION)) {
784       // TODO(beder): Implement producer map bindings.
785       throw new IllegalStateException("producer map bindings not implemented yet");
786     }
787     for (ContributionBinding binding : resolvedBindings.contributionBindings()) {
788       Optional<MemberSelect> multibindingContributionSnippet =
789           getMultibindingContributionSnippet(binding);
790       if (!isMapWithNonProvidedValues(binding.key().type())
791           && multibindingContributionSnippet.isPresent()
792           && multibindingContributionSnippet.get().owningClass().equals(name)) {
793         initializationSnippets.add(
794             Snippet.format(
795                 "this.%s = %s;",
796                 multibindingContributionSnippet.get().getSnippetFor(name),
797                 initializeFactoryForContributionBinding(binding)));
798       }
799     }
800     initializationSnippets.add(
801         initializeMember(
802             resolvedBindings.bindingKey(),
803             initializeMapBinding(resolvedBindings.contributionBindings())));
804 
805     return Snippet.concat(initializationSnippets.build());
806   }
807 
initializeUniqueContributionBinding(ResolvedBindings resolvedBindings)808   private Snippet initializeUniqueContributionBinding(ResolvedBindings resolvedBindings) {
809     ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
810 
811     ContributionBinding binding = getOnlyElement(resolvedBindings.ownedContributionBindings());
812     if (!binding.factoryCreationStrategy().equals(ENUM_INSTANCE) || binding.scope().isPresent()) {
813       initializationSnippets.add(initializeDelegateFactories(binding));
814       initializationSnippets.add(
815           initializeMember(
816               resolvedBindings.bindingKey(), initializeFactoryForContributionBinding(binding)));
817     }
818 
819     return Snippet.concat(initializationSnippets.build());
820   }
821 
initializeMembersInjectionBinding(ResolvedBindings resolvedBindings)822   private Snippet initializeMembersInjectionBinding(ResolvedBindings resolvedBindings) {
823     ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
824 
825     MembersInjectionBinding binding = resolvedBindings.membersInjectionBinding().get();
826     if (!binding.injectionStrategy().equals(MembersInjectionBinding.Strategy.NO_OP)) {
827       initializationSnippets.add(initializeDelegateFactories(binding));
828       initializationSnippets.add(
829           initializeMember(
830               resolvedBindings.bindingKey(), initializeMembersInjectorForBinding(binding)));
831     }
832 
833     return Snippet.concat(initializationSnippets.build());
834   }
835 
initializeDelegateFactories(Binding binding)836   private Snippet initializeDelegateFactories(Binding binding) {
837     ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
838 
839     for (Collection<DependencyRequest> requestsForKey :
840         indexDependenciesByUnresolvedKey(types, binding.dependencies()).asMap().values()) {
841       BindingKey dependencyKey =
842           Iterables.getOnlyElement(
843               FluentIterable.from(requestsForKey)
844                   .transform(DependencyRequest.BINDING_KEY_FUNCTION)
845                   .toSet());
846       if (!getMemberSelect(dependencyKey).staticMember()
847           && getInitializationState(dependencyKey).equals(UNINITIALIZED)) {
848         initializationSnippets.add(
849             Snippet.format(
850                 "this.%s = new %s();",
851                 getMemberSelectSnippet(dependencyKey),
852                 ClassName.fromClass(DelegateFactory.class)));
853         setInitializationState(dependencyKey, DELEGATED);
854       }
855     }
856 
857     return Snippet.concat(initializationSnippets.build());
858   }
859 
initializeMember(BindingKey bindingKey, Snippet initializationSnippet)860   private Snippet initializeMember(BindingKey bindingKey, Snippet initializationSnippet) {
861     ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
862 
863     Snippet memberSelect = getMemberSelectSnippet(bindingKey);
864     Snippet delegateFactoryVariable = delegateFactoryVariableSnippet(bindingKey);
865     if (getInitializationState(bindingKey).equals(DELEGATED)) {
866       initializationSnippets.add(
867           Snippet.format(
868               "%1$s %2$s = (%1$s) %3$s;",
869               ClassName.fromClass(DelegateFactory.class),
870               delegateFactoryVariable,
871               memberSelect));
872     }
873     initializationSnippets.add(
874         Snippet.format("this.%s = %s;", memberSelect, initializationSnippet));
875     if (getInitializationState(bindingKey).equals(DELEGATED)) {
876       initializationSnippets.add(
877           Snippet.format("%s.setDelegatedProvider(%s);", delegateFactoryVariable, memberSelect));
878     }
879     setInitializationState(bindingKey, INITIALIZED);
880 
881     return Snippet.concat(initializationSnippets.build());
882   }
883 
delegateFactoryVariableSnippet(BindingKey key)884   private Snippet delegateFactoryVariableSnippet(BindingKey key) {
885     return Snippet.format("%sDelegate", getMemberSelectSnippet(key).toString().replace('.', '_'));
886   }
887 
initializeFactoryForContributionBinding(ContributionBinding binding)888   private Snippet initializeFactoryForContributionBinding(ContributionBinding binding) {
889     TypeName bindingKeyTypeName = TypeNames.forTypeMirror(binding.key().type());
890     switch (binding.bindingKind()) {
891       case COMPONENT:
892         return Snippet.format(
893             "%s.<%s>create(%s)",
894             ClassName.fromClass(InstanceFactory.class),
895             bindingKeyTypeName,
896             bindingKeyTypeName.equals(componentDefinitionTypeName())
897                 ? "this"
898                 : getComponentContributionSnippet(MoreTypes.asTypeElement(binding.key().type())));
899 
900       case COMPONENT_PROVISION:
901         {
902           TypeElement bindingTypeElement =
903               graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement());
904           String localFactoryVariable = simpleVariableName(bindingTypeElement);
905           Snippet callFactoryMethodSnippet =
906               Snippet.format(
907                   "%s.%s()",
908                   localFactoryVariable,
909                   binding.bindingElement().getSimpleName().toString());
910           // TODO(sameb): This throws a very vague NPE right now.  The stack trace doesn't
911           // help to figure out what the method or return type is.  If we include a string
912           // of the return type or method name in the error message, that can defeat obfuscation.
913           // We can easily include the raw type (no generics) + annotation type (no values),
914           // using .class & String.format -- but that wouldn't be the whole story.
915           // What should we do?
916           StringLiteral failMsg =
917               StringLiteral.forValue(CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD);
918           Snippet getMethodBody =
919               binding.nullableType().isPresent()
920                       || nullableValidationType.equals(Diagnostic.Kind.WARNING)
921                   ? Snippet.format("return %s;", callFactoryMethodSnippet)
922                   : Snippet.format(
923                       Joiner.on('\n')
924                           .join(
925                               "%s provided = %s;",
926                               "if (provided == null) {",
927                               "  throw new NullPointerException(%s);",
928                               "}",
929                               "return provided;"),
930                       bindingKeyTypeName,
931                       callFactoryMethodSnippet,
932                       failMsg);
933           return Snippet.format(
934               Joiner.on('\n')
935                   .join(
936                       "new %1$s<%2$s>() {",
937                       "  private final %5$s %6$s = %3$s;",
938                       "  %4$s@Override public %2$s get() {",
939                       "    %7$s",
940                       "  }",
941                       "}"),
942               /* 1 */ ClassName.fromClass(Factory.class),
943               /* 2 */ bindingKeyTypeName,
944               /* 3 */ getComponentContributionSnippet(bindingTypeElement),
945               /* 4 */ nullableSnippet(binding.nullableType()),
946               /* 5 */ TypeNames.forTypeMirror(bindingTypeElement.asType()),
947               /* 6 */ localFactoryVariable,
948               /* 7 */ getMethodBody);
949         }
950 
951       case SUBCOMPONENT_BUILDER:
952         return Snippet.format(
953             Joiner.on('\n')
954                 .join(
955                     "new %1$s<%2$s>() {",
956                     "  @Override public %2$s get() {",
957                     "    return %3$s();",
958                     "  }",
959                     "}"),
960             /* 1 */ ClassName.fromClass(Factory.class),
961             /* 2 */ bindingKeyTypeName,
962             /* 3 */ binding.bindingElement().getSimpleName().toString());
963 
964       case INJECTION:
965       case PROVISION:
966         {
967           List<Snippet> parameters =
968               Lists.newArrayListWithCapacity(binding.dependencies().size() + 1);
969           if (binding.bindingKind().equals(PROVISION)
970               && !binding.bindingElement().getModifiers().contains(STATIC)) {
971             parameters.add(getComponentContributionSnippet(binding.contributedBy().get()));
972           }
973           parameters.addAll(getDependencyParameters(binding));
974 
975           Snippet factorySnippet =
976               Snippet.format(
977                   "%s.create(%s)",
978                   generatedClassNameForBinding(binding),
979                   Snippet.makeParametersSnippet(parameters));
980           return binding.scope().isPresent()
981               ? Snippet.format(
982                   "%s.create(%s)", ClassName.fromClass(ScopedProvider.class), factorySnippet)
983               : factorySnippet;
984         }
985 
986       case COMPONENT_PRODUCTION:
987         {
988           TypeElement bindingTypeElement =
989               graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement());
990           return Snippet.format(
991               Joiner.on('\n')
992                   .join(
993                       "new %1$s<%2$s>() {",
994                       "  private final %6$s %7$s = %4$s;",
995                       "  @Override public %3$s<%2$s> get() {",
996                       "    return %7$s.%5$s();",
997                       "  }",
998                       "}"),
999               /* 1 */ ClassName.fromClass(Producer.class),
1000               /* 2 */ TypeNames.forTypeMirror(binding.key().type()),
1001               /* 3 */ ClassName.fromClass(ListenableFuture.class),
1002               /* 4 */ getComponentContributionSnippet(bindingTypeElement),
1003               /* 5 */ binding.bindingElement().getSimpleName().toString(),
1004               /* 6 */ TypeNames.forTypeMirror(bindingTypeElement.asType()),
1005               /* 7 */ simpleVariableName(bindingTypeElement));
1006         }
1007 
1008       case IMMEDIATE:
1009       case FUTURE_PRODUCTION:
1010         {
1011           List<Snippet> parameters =
1012               Lists.newArrayListWithCapacity(binding.implicitDependencies().size() + 2);
1013           if (!binding.bindingElement().getModifiers().contains(STATIC)) {
1014             parameters.add(getComponentContributionSnippet(binding.bindingTypeElement()));
1015           }
1016           parameters.add(
1017               getComponentContributionSnippet(
1018                   graph.componentDescriptor().executorDependency().get()));
1019           parameters.addAll(getProducerDependencyParameters(binding));
1020 
1021           return Snippet.format(
1022               "new %s(%s)",
1023               generatedClassNameForBinding(binding),
1024               Snippet.makeParametersSnippet(parameters));
1025         }
1026 
1027       default:
1028         throw new AssertionError();
1029     }
1030   }
1031 
nullableSnippet(Optional<DeclaredType> nullableType)1032   private Snippet nullableSnippet(Optional<DeclaredType> nullableType) {
1033     return nullableType.isPresent()
1034         ? Snippet.format("@%s ", TypeNames.forTypeMirror(nullableType.get()))
1035         : Snippet.format("");
1036   }
1037 
initializeMembersInjectorForBinding(MembersInjectionBinding binding)1038   private Snippet initializeMembersInjectorForBinding(MembersInjectionBinding binding) {
1039     switch (binding.injectionStrategy()) {
1040       case NO_OP:
1041         return Snippet.format("%s.noOp()", ClassName.fromClass(MembersInjectors.class));
1042       case INJECT_MEMBERS:
1043         List<Snippet> parameters = getDependencyParameters(binding);
1044         return Snippet.format(
1045             "%s.create(%s)",
1046             membersInjectorNameForType(binding.bindingElement()),
1047             Snippet.makeParametersSnippet(parameters));
1048       default:
1049         throw new AssertionError();
1050     }
1051   }
1052 
getDependencyParameters(Binding binding)1053   private List<Snippet> getDependencyParameters(Binding binding) {
1054     ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
1055     Set<Key> keysSeen = new HashSet<>();
1056     for (Collection<DependencyRequest> requestsForKey :
1057         indexDependenciesByUnresolvedKey(types, binding.implicitDependencies()).asMap().values()) {
1058       Set<BindingKey> requestedBindingKeys = new HashSet<>();
1059       for (DependencyRequest dependencyRequest : requestsForKey) {
1060         Element requestElement = dependencyRequest.requestElement();
1061         TypeMirror typeMirror = typeMirrorAsMemberOf(binding.bindingTypeElement(), requestElement);
1062         Key key = keyFactory.forQualifiedType(dependencyRequest.key().qualifier(), typeMirror);
1063         if (keysSeen.add(key)) {
1064           requestedBindingKeys.add(dependencyRequest.bindingKey());
1065         }
1066       }
1067       if (!requestedBindingKeys.isEmpty()) {
1068         BindingKey key = Iterables.getOnlyElement(requestedBindingKeys);
1069         parameters.add(getMemberSelect(key).getSnippetWithRawTypeCastFor(name));
1070       }
1071     }
1072     return parameters.build();
1073   }
1074 
1075   // TODO(dpb): Investigate use of asMemberOf here. Why aren't the dependency requests already
1076   // resolved?
typeMirrorAsMemberOf(TypeElement bindingTypeElement, Element requestElement)1077   private TypeMirror typeMirrorAsMemberOf(TypeElement bindingTypeElement, Element requestElement) {
1078     TypeMirror requestType = requestElement.asType();
1079     if (requestType.getKind() == TypeKind.TYPEVAR) {
1080       return types.asMemberOf(
1081           MoreTypes.asDeclared(bindingTypeElement.asType()),
1082           (requestElement.getKind() == ElementKind.PARAMETER)
1083               ? MoreTypes.asElement(requestType)
1084               : requestElement);
1085     } else {
1086       return requestType;
1087     }
1088   }
1089 
getProducerDependencyParameters(Binding binding)1090   private List<Snippet> getProducerDependencyParameters(Binding binding) {
1091     ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
1092     for (Collection<DependencyRequest> requestsForKey :
1093         SourceFiles.indexDependenciesByUnresolvedKey(types, binding.implicitDependencies())
1094             .asMap()
1095             .values()) {
1096       BindingKey key = Iterables.getOnlyElement(FluentIterable.from(requestsForKey)
1097           .transform(DependencyRequest.BINDING_KEY_FUNCTION));
1098       ResolvedBindings resolvedBindings = graph.resolvedBindings().get(key);
1099       Class<?> frameworkClass =
1100           DependencyRequestMapper.FOR_PRODUCER.getFrameworkClass(requestsForKey);
1101       if (FrameworkField.frameworkClassForResolvedBindings(resolvedBindings).equals(Provider.class)
1102           && frameworkClass.equals(Producer.class)) {
1103         parameters.add(
1104             Snippet.format(
1105                 "%s.producerFromProvider(%s)",
1106                 ClassName.fromClass(Producers.class),
1107                 getMemberSelectSnippet(key)));
1108       } else {
1109         parameters.add(getMemberSelectSnippet(key));
1110       }
1111     }
1112     return parameters.build();
1113   }
1114 
initializeMapBinding(Set<ContributionBinding> bindings)1115   private Snippet initializeMapBinding(Set<ContributionBinding> bindings) {
1116     // Get type information from the first binding.
1117     ContributionBinding firstBinding = bindings.iterator().next();
1118     DeclaredType mapType = asDeclared(firstBinding.key().type());
1119 
1120     if (isMapWithNonProvidedValues(mapType)) {
1121       return Snippet.format(
1122           "%s.create(%s)",
1123           ClassName.fromClass(MapFactory.class),
1124           getMemberSelectSnippet(getOnlyElement(firstBinding.dependencies()).bindingKey()));
1125     }
1126 
1127     ImmutableList.Builder<dagger.internal.codegen.writer.Snippet> snippets =
1128         ImmutableList.builder();
1129     snippets.add(Snippet.format("%s.<%s, %s>builder(%d)",
1130         ClassName.fromClass(MapProviderFactory.class),
1131         TypeNames.forTypeMirror(getKeyTypeOfMap(mapType)),
1132         TypeNames.forTypeMirror(getProvidedValueTypeOfMap(mapType)), // V of Map<K, Provider<V>>
1133         bindings.size()));
1134 
1135     for (ContributionBinding binding : bindings) {
1136       snippets.add(
1137           Snippet.format(
1138               "    .put(%s, %s)",
1139               getMapKeySnippet(binding.bindingElement()),
1140               getMultibindingContributionSnippet(binding).get().getSnippetFor(name)));
1141     }
1142 
1143     snippets.add(Snippet.format("    .build()"));
1144 
1145     return Snippet.concat(snippets.build());
1146   }
1147 
simpleVariableName(TypeElement typeElement)1148   private static String simpleVariableName(TypeElement typeElement) {
1149     return UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString());
1150   }
1151 
1152   /**
1153    * Initialization state for a factory field.
1154    */
1155   enum InitializationState {
1156     /** The field is {@code null}. */
1157     UNINITIALIZED,
1158 
1159     /** The field is set to a {@link DelegateFactory}. */
1160     DELEGATED,
1161 
1162     /** The field is set to an undelegated factory. */
1163     INITIALIZED;
1164   }
1165 }
1166