[Ahead-of-time subcomponents] Add support for missing bindings in abstract
subcomponent implementations. Wrap missing bindings in methods and implement
these methods where possible.

RELNOTES=n/a

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=208056862
diff --git a/java/dagger/internal/codegen/BUILD b/java/dagger/internal/codegen/BUILD
index 4a5a6fc..84fd17d 100644
--- a/java/dagger/internal/codegen/BUILD
+++ b/java/dagger/internal/codegen/BUILD
@@ -266,6 +266,7 @@
         "MembersInjectorProviderCreationExpression.java",
         "MethodBindingExpression.java",
         "MissingBindingExpression.java",
+        "MissingBindingMethods.java",
         "MonitoringModuleGenerator.java",
         "MonitoringModuleProcessingStep.java",
         "OptionalBindingExpression.java",
diff --git a/java/dagger/internal/codegen/ComponentBindingExpressions.java b/java/dagger/internal/codegen/ComponentBindingExpressions.java
index 92c0233..8ecf741 100644
--- a/java/dagger/internal/codegen/ComponentBindingExpressions.java
+++ b/java/dagger/internal/codegen/ComponentBindingExpressions.java
@@ -30,6 +30,7 @@
 import static dagger.model.BindingKind.DELEGATE;
 import static dagger.model.BindingKind.MULTIBOUND_MAP;
 import static dagger.model.BindingKind.MULTIBOUND_SET;
+import static javax.lang.model.element.Modifier.PUBLIC;
 
 import com.google.auto.common.MoreTypes;
 import com.google.common.collect.HashBasedTable;
@@ -40,6 +41,7 @@
 import com.squareup.javapoet.MethodSpec;
 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
 import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.MissingBindingMethods.MissingBindingMethod;
 import dagger.model.DependencyRequest;
 import dagger.model.Key;
 import dagger.model.RequestKind;
@@ -248,6 +250,33 @@
         .build();
   }
 
+  /**
+   * Returns the implementation of a method encapsulating a missing binding in a supertype
+   * implementation of this subcomponent. Returns {@link Optional#empty()} when the binding cannot
+   * be satisfied by the current binding graph. This is only relevant for ahead-of-time
+   * subcomponents.
+   */
+  Optional<MethodSpec> getMissingBindingMethodImplementation(MissingBindingMethod missingBinding) {
+    // TODO(b/72748365): investigate beder@'s comment about having intermediate component ancestors
+    // satisfy missing bindings of their children with their own missing binding methods so that
+    // we can minimize the cases where we need to reach into doubly-nested descendant component
+    // implementations
+    if (resolvableBinding(missingBinding.key(), missingBinding.kind())) {
+      Expression bindingExpression =
+          getDependencyExpression(
+              missingBinding.key(), missingBinding.kind(), generatedComponentModel.name());
+      MethodSpec unimplementedMethod = missingBinding.unimplementedMethod();
+      return Optional.of(
+          MethodSpec.methodBuilder(unimplementedMethod.name)
+              .addModifiers(PUBLIC)
+              .returns(unimplementedMethod.returnType)
+              .addAnnotation(Override.class)
+              .addStatement("return $L", bindingExpression.codeBlock())
+              .build());
+    }
+    return Optional.empty();
+  }
+
   private BindingExpression getBindingExpression(Key key, RequestKind requestKind) {
     if (expressions.contains(key, requestKind)) {
       return expressions.get(key, requestKind);
@@ -257,7 +286,8 @@
       ResolvedBindings resolvedBindings = graph.resolvedBindings(requestKind, key);
       expression = Optional.of(createBindingExpression(resolvedBindings, requestKind));
     } else if (!resolvableBinding(key, requestKind) && generatedComponentModel.isAbstract()) {
-      expression = Optional.of(new MissingBindingExpression(key));
+      expression =
+          Optional.of(new MissingBindingExpression(generatedComponentModel, key, requestKind));
     }
     if (expression.isPresent()) {
       expressions.put(key, requestKind, expression.get());
diff --git a/java/dagger/internal/codegen/ComponentModelBuilder.java b/java/dagger/internal/codegen/ComponentModelBuilder.java
index eaeb5b6..4716b3d 100644
--- a/java/dagger/internal/codegen/ComponentModelBuilder.java
+++ b/java/dagger/internal/codegen/ComponentModelBuilder.java
@@ -48,6 +48,7 @@
 import com.squareup.javapoet.ParameterSpec;
 import com.squareup.javapoet.TypeSpec;
 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.MissingBindingMethods.MissingBindingMethod;
 import java.util.List;
 import java.util.Optional;
 import javax.lang.model.element.ExecutableElement;
@@ -533,6 +534,7 @@
   private static final class AbstractSubcomponentModelBuilder extends ComponentModelBuilder {
     private final Optional<ComponentModelBuilder> parent;
     private final GeneratedComponentModel generatedComponentModel;
+    private final ComponentBindingExpressions bindingExpressions;
 
     AbstractSubcomponentModelBuilder(
         Optional<ComponentModelBuilder> parent,
@@ -563,6 +565,7 @@
           compilerOptions);
       this.parent = parent;
       this.generatedComponentModel = generatedComponentModel;
+      this.bindingExpressions = bindingExpressions;
     }
 
     @Override
@@ -582,11 +585,23 @@
 
     @Override
     protected void addInterfaceMethods() {
-      if (!generatedComponentModel.supermodel().isPresent()) {
+      if (generatedComponentModel.supermodel().isPresent()) {
+        // Since we're overriding a subcomponent implementation we add to its implementation given
+        // an expanded binding graph.
+
+        // Implement missing binding methods.
+        for (MissingBindingMethod missingBindingMethod :
+            generatedComponentModel.getMissingBindingMethods()) {
+          bindingExpressions
+              .getMissingBindingMethodImplementation(missingBindingMethod)
+              .ifPresent(
+                  method ->
+                      generatedComponentModel.addImplementedMissingBindingMethod(
+                          missingBindingMethod, method));
+        }
+      } else {
         super.addInterfaceMethods();
       }
-      // TODO(b/72748365): Contribute to modifiable portions of subcomponent implementation for
-      // inner abstract subcomponents.
     }
   }
 
diff --git a/java/dagger/internal/codegen/GeneratedComponentModel.java b/java/dagger/internal/codegen/GeneratedComponentModel.java
index 33f92ac..d0dac71 100644
--- a/java/dagger/internal/codegen/GeneratedComponentModel.java
+++ b/java/dagger/internal/codegen/GeneratedComponentModel.java
@@ -34,6 +34,9 @@
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.TypeSpec;
 import dagger.internal.ReferenceReleasingProviderManager;
+import dagger.internal.codegen.MissingBindingMethods.MissingBindingMethod;
+import dagger.model.Key;
+import dagger.model.RequestKind;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -95,7 +98,13 @@
     MEMBERS_INJECTION_METHOD,
 
     /** A static method that always returns an absent {@code Optional} value for the binding. */
-    ABSENT_OPTIONAL_METHOD
+    ABSENT_OPTIONAL_METHOD,
+
+    /**
+     * A method encapsulating a missing binding to be overridden by a subclass when generating a
+     * component ancestor. Only relevant for ahead-of-time subcomponents.
+     */
+    MISSING_BINDING_METHOD
   }
 
   /** A type of nested class that this component model can generate. */
@@ -129,6 +138,7 @@
   private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
       MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
   private final List<Supplier<TypeSpec>> switchingProviderSupplier = new ArrayList<>();
+  private final MissingBindingMethods missingBindingMethods = new MissingBindingMethods();
 
   private GeneratedComponentModel(
       ClassName name,
@@ -242,6 +252,18 @@
     methodSpecsMap.putAll(methodKind, methodSpecs);
   }
 
+  /** Adds the given (abstract) method representing an encapsulated missing binding. */
+  void addUnimplementedMissingBindingMethod(Key key, RequestKind kind, MethodSpec methodSpec) {
+    missingBindingMethods.addUnimplementedMethod(key, kind, methodSpec);
+    methodSpecsMap.put(MethodSpecKind.MISSING_BINDING_METHOD, methodSpec);
+  }
+
+  /** Adds the implementation for the given {@link MissingBindingMethod}. */
+  void addImplementedMissingBindingMethod(MissingBindingMethod method, MethodSpec methodSpec) {
+    missingBindingMethods.methodImplemented(method);
+    methodSpecsMap.put(MethodSpecKind.MISSING_BINDING_METHOD, methodSpec);
+  }
+
   /** Adds the given type to the component. */
   void addType(TypeSpecKind typeKind, TypeSpec typeSpec) {
     typeSpecsMap.put(typeKind, typeSpec);
@@ -289,6 +311,25 @@
     return ImmutableList.copyOf(initializations);
   }
 
+  /**
+   * Returns the unimplemented {@link MissingBindingMethod}s for this subcomponent implementation
+   * and its superclasses.
+   */
+  ImmutableList<MissingBindingMethod> getMissingBindingMethods() {
+    ImmutableList.Builder<MissingBindingMethod> missingBindingMethodsBuilder =
+        ImmutableList.builder();
+    if (supermodel.isPresent()) {
+      ImmutableList<MissingBindingMethod> bindingsUnsatisfiedBySuperclasses =
+          supermodel.get().getMissingBindingMethods();
+      bindingsUnsatisfiedBySuperclasses
+          .stream()
+          .filter(method -> !missingBindingMethods.isMethodImplemented(method))
+          .forEach(missingBindingMethodsBuilder::add);
+    }
+    missingBindingMethodsBuilder.addAll(missingBindingMethods.getUnimplementedMethods());
+    return missingBindingMethodsBuilder.build();
+  }
+
   /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */
   TypeSpec.Builder generate() {
     fieldSpecsMap.asMap().values().forEach(component::addFields);
diff --git a/java/dagger/internal/codegen/MissingBindingExpression.java b/java/dagger/internal/codegen/MissingBindingExpression.java
index 197c388..65eb5d9 100644
--- a/java/dagger/internal/codegen/MissingBindingExpression.java
+++ b/java/dagger/internal/codegen/MissingBindingExpression.java
@@ -16,9 +16,21 @@
 
 package dagger.internal.codegen;
 
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static dagger.internal.codegen.RequestKinds.requestTypeName;
+import static dagger.internal.codegen.SourceFiles.simpleVariableName;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.google.auto.common.MoreTypes;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
 import dagger.model.Key;
+import dagger.model.RequestKind;
 
 /**
  * A {@link BindingExpression} that invokes a method that encapsulates a binding that is missing
@@ -27,15 +39,44 @@
  * requested. The method is overridden when generating the implementation of an ancestor component.
  */
 final class MissingBindingExpression extends BindingExpression {
+  private final GeneratedComponentModel generatedComponentModel;
   private final Key key;
+  private final RequestKind kind;
+  private String methodName;
 
-  MissingBindingExpression(Key key) {
+  MissingBindingExpression(
+      GeneratedComponentModel generatedComponentModel, Key key, RequestKind kind) {
+    this.generatedComponentModel = generatedComponentModel;
     this.key = key;
+    this.kind = kind;
   }
 
   @Override
   final Expression getDependencyExpression(ClassName requestingClass) {
-    // TODO(b/72748365): Implement method encapsulating binding to invoke in this expression.
-    return Expression.create(key.type(), CodeBlock.of("null"));
+    addUnimplementedMethod();
+    return Expression.create(key.type(), CodeBlock.of("$L()", methodName));
+  }
+
+  private void addUnimplementedMethod() {
+    if (methodName == null) {
+      // Only add the method once in case of repeated references to the missing binding.
+      methodName = chooseMethodName();
+      generatedComponentModel.addUnimplementedMissingBindingMethod(
+          key,
+          kind,
+          MethodSpec.methodBuilder(methodName)
+              .addModifiers(PUBLIC, ABSTRACT)
+              .returns(requestTypeName(kind, TypeName.get(key.type())))
+              .build());
+    }
+  }
+
+  private String chooseMethodName() {
+    return generatedComponentModel.getUniqueMethodName(
+        "get"
+            + LOWER_CAMEL.to(UPPER_CAMEL, simpleVariableName(MoreTypes.asTypeElement(key.type())))
+            + (kind.equals(RequestKind.INSTANCE)
+                ? ""
+                : UPPER_UNDERSCORE.to(UPPER_CAMEL, kind.name())));
   }
 }
diff --git a/java/dagger/internal/codegen/MissingBindingMethods.java b/java/dagger/internal/codegen/MissingBindingMethods.java
new file mode 100644
index 0000000..b5678a3
--- /dev/null
+++ b/java/dagger/internal/codegen/MissingBindingMethods.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.MethodSpec;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A registry for those methods which each wrap a binding that is unsatisfiable by a subcomponent in
+ * isolation, but can be satisfied by an ancestor component. This is useful when generating
+ * ahead-of-time subcomponents: An instance of this class is associated with a single subcomponent
+ * implementation. We generate an implementation of a given subcomponent once for each of it's
+ * ancestor components and for any one implementation the {@link MissingBindingMethod}s of it's
+ * superclasses tell us what missing bindings have yet to be satisfied so we can attempt to satisfy
+ * them.
+ */
+final class MissingBindingMethods {
+  private final Map<KeyAndKind, MissingBindingMethod> missingBindingMethods = Maps.newHashMap();
+  private final Set<KeyAndKind> implementedMissingBindingMethods = Sets.newHashSet();
+
+  /** Record an unimplemented method encapsulating a missing binding. */
+  void addUnimplementedMethod(Key key, RequestKind kind, MethodSpec unimplementedMethod) {
+    KeyAndKind keyAndKind = KeyAndKind.create(key, kind);
+    checkState(
+        !implementedMissingBindingMethods.contains(keyAndKind),
+        "Adding an missing binding method for a method marked as implemented for the current "
+            + "subcomponent implementation. The binding is for a %s-%s.",
+        key,
+        kind);
+    missingBindingMethods.put(
+        keyAndKind, MissingBindingMethod.create(key, kind, unimplementedMethod));
+  }
+
+  /** Returns all unimplemented {@link MissingBindingMethod}s */
+  ImmutableList<MissingBindingMethod> getUnimplementedMethods() {
+    // We will never register a binding as missing and also as implemented for the same instance of
+    // MissingBindingMethods, so there's no need to filter missingBindingMethods.
+    return missingBindingMethods.values().stream().collect(toImmutableList());
+  }
+
+  /** Mark the {@link MissingBindingMethod} as having been implemented. */
+  void methodImplemented(MissingBindingMethod method) {
+    KeyAndKind keyAndKind = KeyAndKind.create(method.key(), method.kind());
+    checkState(
+        !missingBindingMethods.containsKey(keyAndKind),
+        "Indicating a missing binding method as implemented when it was registered as missing for "
+            + "the current subcomponent implementation. The binding is for a %s-%s.",
+        method.key(),
+        method.kind());
+    implementedMissingBindingMethods.add(keyAndKind);
+  }
+
+  /** Whether a given binding has been marked as implemented. */
+  boolean isMethodImplemented(MissingBindingMethod method) {
+    return implementedMissingBindingMethods.contains(
+        KeyAndKind.create(method.key(), method.kind()));
+  }
+
+  @AutoValue
+  abstract static class MissingBindingMethod {
+    private static MissingBindingMethod create(
+        Key key, RequestKind kind, MethodSpec unimplementedMethod) {
+      return new AutoValue_MissingBindingMethods_MissingBindingMethod(
+          key, kind, unimplementedMethod);
+    }
+
+    abstract Key key();
+
+    abstract RequestKind kind();
+
+    abstract MethodSpec unimplementedMethod();
+  }
+
+  @AutoValue
+  abstract static class KeyAndKind {
+    private static KeyAndKind create(Key key, RequestKind kind) {
+      return new AutoValue_MissingBindingMethods_KeyAndKind(key, kind);
+    }
+
+    abstract Key key();
+
+    abstract RequestKind kind();
+  }
+}