Add ordering to fields and methods in GeneratedComponentModel.

RELNOTES=n/a

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=178006667
diff --git a/java/dagger/internal/codegen/AbstractComponentWriter.java b/java/dagger/internal/codegen/AbstractComponentWriter.java
index b3a7893..f091823 100644
--- a/java/dagger/internal/codegen/AbstractComponentWriter.java
+++ b/java/dagger/internal/codegen/AbstractComponentWriter.java
@@ -21,7 +21,10 @@
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static dagger.internal.codegen.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.TypeSpecs.addSupertype;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.COMPONENT_METHOD;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.CONSTRUCTOR;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.INITIALIZE_METHOD;
+import static dagger.internal.codegen.GeneratedComponentModel.TypeSpecKind.SUBCOMPONENT;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PRIVATE;
 
@@ -35,7 +38,6 @@
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.TypeSpec;
 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import javax.lang.model.element.ExecutableElement;
@@ -54,8 +56,6 @@
   private final ComponentBindingExpressions bindingExpressions;
   protected final ComponentRequirementFields componentRequirementFields;
   protected final GeneratedComponentModel generatedComponentModel;
-  private final MembersInjectionMethods membersInjectionMethods;
-  protected final List<MethodSpec> interfaceMethods = new ArrayList<>();
   private final ComponentRequirementField.Factory componentRequirementFieldFactory;
   protected final MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE);
   private final OptionalFactories optionalFactories;
@@ -96,8 +96,6 @@
       builderFields = ImmutableMap.of();
     }
     this.componentRequirementFields = componentRequirementFields;
-    // TODO(user): Remove membersInjectionMethods field once we have another way to order methods.
-    this.membersInjectionMethods = bindingExpressions.membersInjectionMethods();
     this.componentRequirementFieldFactory =
         new ComponentRequirementField.Factory(generatedComponentModel, builderFields);
   }
@@ -127,7 +125,7 @@
    */
   final TypeSpec.Builder write() {
     checkState(!done, "ComponentWriter has already been generated.");
-    addSupertype(generatedComponentModel.component, graph.componentType());
+    generatedComponentModel.addSupertype(graph.componentType());
     if (hasBuilder(graph)) {
       addBuilder();
     }
@@ -138,17 +136,15 @@
 
     addFactoryMethods();
     createComponentRequirementFields();
-    implementInterfaceMethods();
+    addInterfaceMethods();
     addSubcomponents();
-    writeInitializeAndInterfaceMethods();
-    generatedComponentModel.addMethods(membersInjectionMethods.getAllMethods());
-    generatedComponentModel.addMethod(constructor.build());
+    addInitializeMethods();
+    generatedComponentModel.addMethod(CONSTRUCTOR, constructor.build());
     if (graph.componentDescriptor().kind().isTopLevel()) {
-      // TODO(user): pass in generatedComponentModel instead of the component.
-      optionalFactories.addMembers(generatedComponentModel.component);
+      optionalFactories.addMembers(generatedComponentModel);
     }
     done = true;
-    return generatedComponentModel.component;
+    return generatedComponentModel.generate();
   }
 
   private static boolean hasBuilder(BindingGraph graph) {
@@ -186,7 +182,7 @@
         .forEach(componentRequirementFields::add);
   }
 
-  private void implementInterfaceMethods() {
+  private void addInterfaceMethods() {
     Set<MethodSignature> interfaceMethodSignatures = Sets.newHashSet();
     DeclaredType componentType = MoreTypes.asDeclared(graph.componentType().asType());
     for (ComponentMethodDescriptor componentMethod :
@@ -204,7 +200,7 @@
           interfaceMethod.addCode(
               bindingExpressions.getComponentMethodImplementation(
                   componentMethod, generatedComponentModel.name()));
-          interfaceMethods.add(interfaceMethod.build());
+          generatedComponentModel.addMethod(COMPONENT_METHOD, interfaceMethod.build());
         }
       }
     }
@@ -212,13 +208,14 @@
 
   private void addSubcomponents() {
     for (BindingGraph subgraph : graph.subgraphs()) {
-      generatedComponentModel.addType(new SubcomponentWriter(this, subgraph).write().build());
+      generatedComponentModel.addType(
+          SUBCOMPONENT, new SubcomponentWriter(this, subgraph).write().build());
     }
   }
 
   private static final int INITIALIZATIONS_PER_INITIALIZE_METHOD = 100;
 
-  private void writeInitializeAndInterfaceMethods() {
+  private void addInitializeMethods() {
     List<List<CodeBlock>> partitions =
         Lists.partition(
             generatedComponentModel.getInitializations(), INITIALIZATIONS_PER_INITIALIZE_METHOD);
@@ -241,9 +238,7 @@
       } else {
         constructor.addStatement("$L()", methodName);
       }
-      generatedComponentModel.addMethod(initializeMethod.build());
+      generatedComponentModel.addMethod(INITIALIZE_METHOD, initializeMethod.build());
     }
-
-    generatedComponentModel.addMethods(interfaceMethods);
   }
 }
diff --git a/java/dagger/internal/codegen/ComponentBindingExpressions.java b/java/dagger/internal/codegen/ComponentBindingExpressions.java
index 0bb4bf7..0360408 100644
--- a/java/dagger/internal/codegen/ComponentBindingExpressions.java
+++ b/java/dagger/internal/codegen/ComponentBindingExpressions.java
@@ -215,12 +215,6 @@
     return bindingExpressionFactory.create(graph.resolvedBindings().get(bindingKey));
   }
 
-  // This is only made visibile to keep the correct order of methods in the generated component.
-  // TODO(user): remove this method after removing the dependency from AbstractComponentWriter.
-  MembersInjectionMethods membersInjectionMethods() {
-    return bindingExpressionFactory.membersInjectionMethods;
-  }
-
   /** Factory for building a {@link BindingExpression}. */
   private static final class BindingExpressionFactory {
     // TODO(user): Consider using PrivateMethodBindingExpression for other/all BEs?
@@ -335,12 +329,10 @@
           FrameworkInstanceBindingExpression.create(
               resolvedBindings, memberSelect, frameworkFieldInitializer, types, elements);
 
-       switch (resolvedBindings.bindingType()) {
+      switch (resolvedBindings.bindingType()) {
         case MEMBERS_INJECTION:
           return new MembersInjectionBindingExpression(
-              frameworkInstanceBindingExpression,
-              generatedComponentModel,
-              membersInjectionMethods);
+              frameworkInstanceBindingExpression, generatedComponentModel, membersInjectionMethods);
         case PROVISION:
           return provisionBindingExpression(frameworkInstanceBindingExpression);
         default:
diff --git a/java/dagger/internal/codegen/ComponentRequirementField.java b/java/dagger/internal/codegen/ComponentRequirementField.java
index 1cb964b..60846c2 100644
--- a/java/dagger/internal/codegen/ComponentRequirementField.java
+++ b/java/dagger/internal/codegen/ComponentRequirementField.java
@@ -17,6 +17,7 @@
 package dagger.internal.codegen;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.COMPONENT_REQUIREMENT_FIELD;
 import static javax.lang.model.element.Modifier.PRIVATE;
 
 import com.google.common.collect.ImmutableMap;
@@ -104,7 +105,7 @@
         FieldSpec componentField =
             FieldSpec.builder(TypeName.get(componentRequirement().type()), fieldName, PRIVATE)
                 .build();
-        generatedComponentModel.addField(componentField);
+        generatedComponentModel.addField(COMPONENT_REQUIREMENT_FIELD, componentField);
         generatedComponentModel.addInitialization(
             CodeBlock.of("this.$N = builder.$N;", componentField, builderField));
         field = MemberSelect.localField(owningComponent, fieldName);
diff --git a/java/dagger/internal/codegen/ComponentWriter.java b/java/dagger/internal/codegen/ComponentWriter.java
index a672f35..49e6c95 100644
--- a/java/dagger/internal/codegen/ComponentWriter.java
+++ b/java/dagger/internal/codegen/ComponentWriter.java
@@ -17,6 +17,8 @@
 package dagger.internal.codegen;
 
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.BUILDER_METHOD;
+import static dagger.internal.codegen.GeneratedComponentModel.TypeSpecKind.COMPONENT_BUILDER;
 import static javax.lang.model.element.Modifier.PUBLIC;
 import static javax.lang.model.element.Modifier.STATIC;
 
@@ -99,12 +101,12 @@
                     : builderName())
             .addStatement("return new $T()", builderName())
             .build();
-    generatedComponentModel.addMethod(builderFactoryMethod);
+    generatedComponentModel.addMethod(BUILDER_METHOD, builderFactoryMethod);
   }
 
   @Override
   protected void addBuilderClass(TypeSpec builder) {
-    generatedComponentModel.addType(builder);
+    generatedComponentModel.addType(COMPONENT_BUILDER, builder);
   }
 
   @Override
@@ -116,6 +118,7 @@
               ? graph.componentDescriptor().builderSpec().get().buildMethod().getSimpleName()
               : "build";
       generatedComponentModel.addMethod(
+          BUILDER_METHOD,
           methodBuilder("create")
               .returns(ClassName.get(graph.componentType()))
               .addModifiers(PUBLIC, STATIC)
diff --git a/java/dagger/internal/codegen/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
index 2eed0a9..807733d 100644
--- a/java/dagger/internal/codegen/FrameworkFieldInitializer.java
+++ b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
@@ -29,6 +29,8 @@
 import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
 import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
 import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.FRAMEWORK_FIELD;
+import static dagger.internal.codegen.GeneratedComponentModel.TypeSpecKind.COMPONENT_PROVISION_FACTORY;
 import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
 import static dagger.internal.codegen.MoreAnnotationMirrors.getTypeValue;
 import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
@@ -167,7 +169,7 @@
           codeBuilder.add(initCode);
         }
         generatedComponentModel.addInitialization(codeBuilder.build());
-        generatedComponentModel.addField(fieldSpec);
+        generatedComponentModel.addField(FRAMEWORK_FIELD, fieldSpec);
 
         fieldInitializationState = InitializationState.INITIALIZED;
         break;
@@ -286,6 +288,7 @@
                 ClassName.get(MoreTypes.asTypeElement(binding.nullableType().get())));
           }
           generatedComponentModel.addType(
+              COMPONENT_PROVISION_FACTORY,
               TypeSpec.classBuilder(factoryName)
                   .addSuperinterface(providerOf(bindingKeyTypeName))
                   .addModifiers(PRIVATE, STATIC)
diff --git a/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
index 78ccd52..0af9914 100644
--- a/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
+++ b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
@@ -81,8 +81,8 @@
   /**
    * The expression for the framework instance for this binding. If the instance comes from a
    * component field, it will be {@link GeneratedComponentModel#addInitialization(CodeBlock)
-   * initialized} and {@link GeneratedComponentModel#addField(FieldSpec) added} to the component the
-   * first time this method is invoked.
+   * initialized} and {@link GeneratedComponentModel#addField(GeneratedComponentModel.FieldSpecKind,
+   * FieldSpec) added} to the component the first time this method is invoked.
    */
   @Override
   Expression getDependencyExpression(
diff --git a/java/dagger/internal/codegen/GeneratedComponentModel.java b/java/dagger/internal/codegen/GeneratedComponentModel.java
index 8d8faa9..66ee297 100644
--- a/java/dagger/internal/codegen/GeneratedComponentModel.java
+++ b/java/dagger/internal/codegen/GeneratedComponentModel.java
@@ -22,24 +22,98 @@
 import static javax.lang.model.element.Modifier.PUBLIC;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.MultimapBuilder;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.TypeSpec;
+import dagger.internal.ReferenceReleasingProviderManager;
 import java.util.ArrayList;
 import java.util.List;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
 
 /** The model of the component being generated. */
 final class GeneratedComponentModel {
+  /** A type of field that this component model can generate. */
+  // TODO(user, dpb): Move component requirements and reference managers to top? The order should
+  // be component requirements, referencemanagers, framework fields, private method fields, ... etc
+  static enum FieldSpecKind {
+    /**
+     * A field for the lock and cached value for {@linkplain PrivateMethodBindingExpression
+     * private-method scoped bindings}.
+     */
+    PRIVATE_METHOD_SCOPED_FIELD,
+
+    /** A field required by the component, e.g. module instances. */
+    COMPONENT_REQUIREMENT_FIELD,
+
+    /** A framework field for type T, e.g. Provider<T>. */
+    FRAMEWORK_FIELD,
+
+    /** A field for a {@link ReferenceReleasingProviderManager}. */
+    REFERENCE_RELEASING_MANAGER_FIELD,
+
+    /** A static field that always returns an absent {@code Optional} value for the binding. */
+    ABSENT_OPTIONAL_FIELD
+  }
+
+  /** A type of method that this component model can generate. */
+  // TODO(user, dpb): Change the oder to constructor, initialize, component, then private
+  // (including MIM and AOM—why treat those separately?).
+  static enum MethodSpecKind {
+    /** The component constructor. */
+    CONSTRUCTOR,
+
+    /** A builder method for the component. (Only used by the root component.) */
+    BUILDER_METHOD,
+
+    /** A private method that wraps depenency expressions. */
+    PRIVATE_METHOD,
+
+    /** An initialization method that initializes component requirements and framework types. */
+    INITIALIZE_METHOD,
+
+    /** An implementation of a component interface method. */
+    COMPONENT_METHOD,
+
+    /** A private method that encapsulates members injection logic for a binding. */
+    MEMBERS_INJECTION_METHOD,
+
+    /** A static method that always returns an absent {@code Optional} value for the binding. */
+    ABSENT_OPTIONAL_METHOD
+  }
+
+  /** A type of nested class that this component model can generate. */
+  static enum TypeSpecKind {
+    /** A factory class for a present optional binding. */
+    PRESENT_FACTORY,
+
+    /** A class for the component builder (Only used by the root component.) */
+    COMPONENT_BUILDER,
+
+    /** A provider class for a component provision. */
+    COMPONENT_PROVISION_FACTORY,
+
+    /** A class for the subcomponent or subcomponent builder. */
+    SUBCOMPONENT
+  }
+
   private final ClassName name;
   // TODO(user): This is only non-private to ease migration with AbstractComponentWriter!
-  final TypeSpec.Builder component;
+  private final TypeSpec.Builder component;
   private final UniqueNameSet componentFieldNames = new UniqueNameSet();
   private final UniqueNameSet componentMethodNames = new UniqueNameSet();
   private final List<CodeBlock> initializations = new ArrayList<>();
+  private final ListMultimap<FieldSpecKind, FieldSpec> fieldSpecsMap =
+      MultimapBuilder.enumKeys(FieldSpecKind.class).arrayListValues().build();
+  private final ListMultimap<MethodSpecKind, MethodSpec> methodSpecsMap =
+      MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build();
+  private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
+      MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
 
   private GeneratedComponentModel(ClassName name, Modifier... modifiers) {
     this.name = name;
@@ -59,21 +133,39 @@
     return name;
   }
 
+  /** Adds the given super type to the component. */
+  void addSupertype(TypeElement supertype) {
+    TypeSpecs.addSupertype(component, supertype);
+  }
+
   /** Adds the given field to the component. */
-  // TODO(user): Add a enum for field order/type so that we can control the order of fields.
-  void addField(FieldSpec fieldSpec) {
-    component.addField(fieldSpec);
+  void addField(FieldSpecKind fieldKind, FieldSpec fieldSpec) {
+    fieldSpecsMap.put(fieldKind, fieldSpec);
+  }
+
+  /** Adds the given fields to the component. */
+  void addFields(FieldSpecKind fieldKind, Iterable<FieldSpec> fieldSpecs) {
+    fieldSpecsMap.putAll(fieldKind, fieldSpecs);
   }
 
   /** Adds the given method to the component. */
-  // TODO(user): Add a enum for method order/type so that we can control the order of methods.
-  void addMethod(MethodSpec methodSpec) {
-    component.addMethod(methodSpec);
+  void addMethod(MethodSpecKind methodKind, MethodSpec methodSpec) {
+    methodSpecsMap.put(methodKind, methodSpec);
   }
 
   /** Adds the given methods to the component. */
-  void addMethods(Iterable<MethodSpec> methodSpecs) {
-    component.addMethods(methodSpecs);
+  void addMethods(MethodSpecKind methodKind, Iterable<MethodSpec> methodSpecs) {
+    methodSpecsMap.putAll(methodKind, methodSpecs);
+  }
+
+  /** Adds the given type to the component. */
+  void addType(TypeSpecKind typeKind, TypeSpec typeSpec) {
+    typeSpecsMap.put(typeKind, typeSpec);
+  }
+
+  /** Adds the given types to the component. */
+  void addTypes(TypeSpecKind typeKind, Iterable<TypeSpec> typeSpecs) {
+    typeSpecsMap.putAll(typeKind, typeSpecs);
   }
 
   /** Adds the given code block to the initialize methods of the component. */
@@ -81,11 +173,6 @@
     initializations.add(codeBlock);
   }
 
-  /** Adds the given type to the component. */
-  void addType(TypeSpec typeSpec) {
-    component.addType(typeSpec);
-  }
-
   /** Returns a new, unique field name for the component based on the given name. */
   String getUniqueFieldName(String name) {
     return componentFieldNames.getUniqueName(name);
@@ -105,4 +192,12 @@
   ImmutableList<CodeBlock> getInitializations() {
     return ImmutableList.copyOf(initializations);
   }
+
+  /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */
+  TypeSpec.Builder generate() {
+    fieldSpecsMap.asMap().values().forEach(component::addFields);
+    methodSpecsMap.asMap().values().forEach(component::addMethods);
+    typeSpecsMap.asMap().values().forEach(component::addTypes);
+    return component;
+  }
 }
diff --git a/java/dagger/internal/codegen/MembersInjectionMethods.java b/java/dagger/internal/codegen/MembersInjectionMethods.java
index 335ac48..9f12e08 100644
--- a/java/dagger/internal/codegen/MembersInjectionMethods.java
+++ b/java/dagger/internal/codegen/MembersInjectionMethods.java
@@ -20,10 +20,10 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.MEMBERS_INJECTION_METHOD;
 import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
 import static javax.lang.model.element.Modifier.PRIVATE;
 
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
@@ -64,18 +64,11 @@
   /**
    * Returns the members injection {@link MethodSpec} for the given {@link Key}, creating it if
    * necessary.
-   *
-   * <p>To get a list of all members injection {@link MethodSpec}s, call {@link #getAllMethods()}
    */
   MethodSpec getOrCreate(Key key) {
     return reentrantComputeIfAbsent(membersInjectionMethods, key, this::membersInjectionMethod);
   }
 
-  /** Returns the list of all members injection {@link MethodSpec}s for this component. */
-  ImmutableList<MethodSpec> getAllMethods() {
-    return ImmutableList.copyOf(membersInjectionMethods.values());
-  }
-
   private MethodSpec membersInjectionMethod(Key key) {
     Binding binding =
         firstNonNull(
@@ -93,7 +86,7 @@
     // simple names Foo.Builder -> injectFooBuilder
     String methodName = generatedComponentModel.getUniqueMethodName("inject" + bindingTypeName);
     ParameterSpec parameter = ParameterSpec.builder(membersInjectedTypeName, "instance").build();
-    MethodSpec.Builder method =
+    MethodSpec.Builder methodBuilder =
         methodBuilder(methodName)
             .addModifiers(PRIVATE)
             .returns(membersInjectedTypeName)
@@ -101,10 +94,10 @@
     TypeElement canIgnoreReturnValue =
         elements.getTypeElement("com.google.errorprone.annotations.CanIgnoreReturnValue");
     if (canIgnoreReturnValue != null) {
-      method.addAnnotation(ClassName.get(canIgnoreReturnValue));
+      methodBuilder.addAnnotation(ClassName.get(canIgnoreReturnValue));
     }
     CodeBlock instance = CodeBlock.of("$N", parameter);
-    method.addCode(
+    methodBuilder.addCode(
         InjectionSiteMethod.invokeAll(
             injectionSites(binding),
             generatedComponentModel.name(),
@@ -115,9 +108,11 @@
                 bindingExpressions
                     .getDependencyArgumentExpression(request, generatedComponentModel.name())
                     .codeBlock()));
-    method.addStatement("return $L", instance);
+    methodBuilder.addStatement("return $L", instance);
 
-    return method.build();
+    MethodSpec method = methodBuilder.build();
+    generatedComponentModel.addMethod(MEMBERS_INJECTION_METHOD, method);
+    return method;
   }
 
   private static ImmutableSet<InjectionSite> injectionSites(Binding binding) {
diff --git a/java/dagger/internal/codegen/OptionalFactories.java b/java/dagger/internal/codegen/OptionalFactories.java
index 49c30ad..cad53d9 100644
--- a/java/dagger/internal/codegen/OptionalFactories.java
+++ b/java/dagger/internal/codegen/OptionalFactories.java
@@ -25,6 +25,9 @@
 import static com.squareup.javapoet.TypeSpec.classBuilder;
 import static dagger.internal.codegen.AnnotationSpecs.Suppression.RAWTYPES;
 import static dagger.internal.codegen.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.ABSENT_OPTIONAL_FIELD;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.ABSENT_OPTIONAL_METHOD;
+import static dagger.internal.codegen.GeneratedComponentModel.TypeSpecKind.PRESENT_FACTORY;
 import static dagger.internal.codegen.TypeNames.PROVIDER;
 import static dagger.internal.codegen.TypeNames.listenableFutureOf;
 import static dagger.internal.codegen.TypeNames.providerOf;
@@ -359,9 +362,10 @@
    * #absentOptionalProvider(ContributionBinding)} and {@link
    * #presentOptionalFactory(ContributionBinding, CodeBlock)} to the top-level {@code component}.
    */
-  void addMembers(TypeSpec.Builder component) {
-    component.addTypes(presentFactoryClasses.values());
-    component.addMethods(absentOptionalProviderMethods.values());
-    component.addFields(absentOptionalProviderFields.values());
+  void addMembers(GeneratedComponentModel generatedComponentModel) {
+    generatedComponentModel.addTypes(PRESENT_FACTORY, presentFactoryClasses.values());
+    generatedComponentModel.addMethods(
+        ABSENT_OPTIONAL_METHOD, absentOptionalProviderMethods.values());
+    generatedComponentModel.addFields(ABSENT_OPTIONAL_FIELD, absentOptionalProviderFields.values());
   }
 }
diff --git a/java/dagger/internal/codegen/PrivateMethodBindingExpression.java b/java/dagger/internal/codegen/PrivateMethodBindingExpression.java
index 4efb8b8..625a82e 100644
--- a/java/dagger/internal/codegen/PrivateMethodBindingExpression.java
+++ b/java/dagger/internal/codegen/PrivateMethodBindingExpression.java
@@ -23,6 +23,8 @@
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
+import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.PRIVATE_METHOD_SCOPED_FIELD;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.PRIVATE_METHOD;
 import static dagger.internal.codegen.Scope.reusableScope;
 import static javax.lang.model.element.Modifier.PRIVATE;
 import static javax.lang.model.element.Modifier.PUBLIC;
@@ -184,6 +186,7 @@
     // TODO(user): Consider when we can make this method static.
     // TODO(user): Fix the order that these generated methods are written to the component.
     generatedComponentModel.addMethod(
+        PRIVATE_METHOD,
         methodBuilder(name)
             .addModifiers(PRIVATE)
             .returns(TypeName.get(returnType(requestKind)))
@@ -271,6 +274,7 @@
     if (!fieldNames.containsKey(requestKind)) {
       String name = generatedComponentModel.getUniqueFieldName(BindingVariableNamer.name(binding));
       generatedComponentModel.addField(
+          PRIVATE_METHOD_SCOPED_FIELD,
           FieldSpec.builder(TypeName.OBJECT, name, PRIVATE, VOLATILE)
               .initializer("new $T()", MemoizedSentinel.class)
               .build());
diff --git a/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java b/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java
index 5f169d8..d5a57c3 100644
--- a/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java
+++ b/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java
@@ -20,6 +20,7 @@
 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.REFERENCE_RELEASING_MANAGER_FIELD;
 import static dagger.internal.codegen.MemberSelect.localField;
 import static dagger.internal.codegen.TypeNames.REFERENCE_RELEASING_PROVIDER_MANAGER;
 import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
@@ -77,7 +78,7 @@
 
   private MemberSelect createReferenceReleasingManagerField(Scope scope) {
     FieldSpec field = referenceReleasingProxyManagerField(scope);
-    generatedComponentModel.addField(field);
+    generatedComponentModel.addField(REFERENCE_RELEASING_MANAGER_FIELD, field);
     return localField(generatedComponentModel.name(), field.name);
   }
 
diff --git a/java/dagger/internal/codegen/SubcomponentWriter.java b/java/dagger/internal/codegen/SubcomponentWriter.java
index 3548e7f..ab6b269 100644
--- a/java/dagger/internal/codegen/SubcomponentWriter.java
+++ b/java/dagger/internal/codegen/SubcomponentWriter.java
@@ -20,6 +20,9 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.COMPONENT_REQUIREMENT_FIELD;
+import static dagger.internal.codegen.GeneratedComponentModel.MethodSpecKind.COMPONENT_METHOD;
+import static dagger.internal.codegen.GeneratedComponentModel.TypeSpecKind.SUBCOMPONENT;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PRIVATE;
 import static javax.lang.model.element.Modifier.PUBLIC;
@@ -97,7 +100,7 @@
 
   @Override
   protected void addBuilderClass(TypeSpec builder) {
-    parent.generatedComponentModel.addType(builder);
+    parent.generatedComponentModel.addType(SUBCOMPONENT, builder);
   }
 
   @Override
@@ -115,7 +118,7 @@
     ExecutableType resolvedMethod = resolvedSubcomponentFactoryMethod();
     componentMethod.returns(ClassName.get(resolvedMethod.getReturnType()));
     writeSubcomponentWithoutBuilder(componentMethod, resolvedMethod);
-    parent.interfaceMethods.add(componentMethod.build());
+    parent.generatedComponentModel.addMethod(COMPONENT_METHOD, componentMethod.build());
   }
 
   private void writeSubcomponentWithoutBuilder(
@@ -138,7 +141,7 @@
             componentField(ClassName.get(moduleTypeElement), preferredModuleName)
                 .addModifiers(PRIVATE, FINAL)
                 .build();
-        generatedComponentModel.addField(contributionField);
+        generatedComponentModel.addField(COMPONENT_REQUIREMENT_FIELD, contributionField);
 
         constructor
             .addParameter(moduleType, contributionField.name)
@@ -167,7 +170,7 @@
           componentField(ClassName.get(moduleType), preferredModuleName)
               .addModifiers(PRIVATE, FINAL)
               .build();
-      generatedComponentModel.addField(contributionField);
+      generatedComponentModel.addField(COMPONENT_REQUIREMENT_FIELD, contributionField);
       constructor.addStatement("this.$N = new $T()", contributionField, ClassName.get(moduleType));
       componentRequirementFields.add(
           ComponentRequirementField.componentField(