Home | History | Annotate | Download | only in codegen
      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 
    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 
    170   protected final TypeElement componentDefinitionType() {
    171     return graph.componentDescriptor().componentDefinitionType();
    172   }
    173 
    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    */
    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    */
    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 
    218   private Snippet getMemberSelectSnippet(BindingKey key) {
    219     return getMemberSelect(key).getSnippetFor(name);
    220   }
    221 
    222   protected MemberSelect getMemberSelect(BindingKey key) {
    223     return memberSelectSnippets.get(key);
    224   }
    225 
    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    */
    233   protected InitializationState getInitializationState(BindingKey bindingKey) {
    234     return initializationStates.containsKey(bindingKey)
    235         ? initializationStates.get(bindingKey)
    236         : UNINITIALIZED;
    237   }
    238 
    239   private void setInitializationState(BindingKey bindingKey, InitializationState state) {
    240     initializationStates.put(bindingKey, state);
    241   }
    242 
    243   private InitializationState getContributionInitializationState(Binding binding) {
    244     return contributionInitializationStates.containsKey(binding)
    245         ? contributionInitializationStates.get(binding)
    246         : UNINITIALIZED;
    247   }
    248 
    249   private void setContributionInitializationState(Binding binding, InitializationState state) {
    250     contributionInitializationStates.put(binding, state);
    251   }
    252 
    253   ImmutableSet<JavaWriter> write() {
    254     if (javaWriters.isEmpty()) {
    255       writeComponent();
    256     }
    257     return ImmutableSet.copyOf(javaWriters);
    258   }
    259 
    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    */
    274   protected abstract ClassWriter createComponentClass();
    275 
    276   private void addConstructor() {
    277     constructorWriter = componentWriter.addConstructor();
    278     constructorWriter.addModifiers(PRIVATE);
    279   }
    280 
    281   /**
    282    * Adds a builder type.
    283    */
    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    */
    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. */
    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    */
    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 
    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 
    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    */
    448   protected abstract ClassWriter createBuilder();
    449 
    450   /**
    451    * Adds component factory methods.
    452    */
    453   protected abstract void addFactoryMethods();
    454 
    455   private void addFields() {
    456     for (ResolvedBindings resolvedBindings : graph.resolvedBindings().values()) {
    457       addField(resolvedBindings);
    458     }
    459   }
    460 
    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 
    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    */
    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 
    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 
    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 
    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    */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    884   private Snippet delegateFactoryVariableSnippet(BindingKey key) {
    885     return Snippet.format("%sDelegate", getMemberSelectSnippet(key).toString().replace('.', '_'));
    886   }
    887 
    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 
   1032   private Snippet nullableSnippet(Optional<DeclaredType> nullableType) {
   1033     return nullableType.isPresent()
   1034         ? Snippet.format("@%s ", TypeNames.forTypeMirror(nullableType.get()))
   1035         : Snippet.format("");
   1036   }
   1037 
   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 
   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?
   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 
   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 
   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 
   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