Roll forward with fix of 'Support Kotlin val properties with @BindValue.'

Two additional changes compared to the original CL:
* When matching javax.lang elements with Kotlin metadata we rely on descriptors. When generating the descriptor of an element whose type is an error (type is not yet resolved, probably a generated type) a fully modeled type is not needed and instead the ErrorType can be treated as a DeclaredType, using its reference names to generate a descriptor containing the class name in its internal form. The fix here is to do just that instead of defaulting to throwing an error when visiting an ErrorType while generating a descriptor.
* When inspecting fields to match them against their Kotlin property metadata we rely on the JVM descriptors. However, for generated type the descriptors is incorrect due to https://youtrack.jetbrains.com/issue/KT-35124, for such cases we rely on matching the Kotlin metadata property with the field element by name. Matching by name must also take into account the field suffixes used by kotlinc, specifically delegate properties end up creating a field whose name is that of the property plus '$delegate'. This consideration must now be done since KotlinMetadata will now contain a map of all fields matched with their Kotlin metadata property where as before only @Inject annotated fields were mapped. Since @Inject can't be placed in a property with delegate this was not an issue before.

PiperOrigin-RevId: 333817683
diff --git a/WORKSPACE b/WORKSPACE
index 2392684..7e42b29 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -104,17 +104,14 @@
     ],
 )
 
-# TODO(user): Remove once Google publishes internal Kotlin rules.
-RULES_KOTLIN_VERSION = "186c1e1e27d699a8953b75461f2de7c295987cfb"
+RULES_KOTLIN_VERSION = "legacy-1.4.0-rc3"
 
-RULES_KOTLIN_SHA = "ef2f9cfb724b1f1eaf0ede2636515969eb4c6e10b75a71d1850f6e692a7d5f06"
+RULES_KOTLIN_SHA = "da0e6e1543fcc79e93d4d93c3333378f3bd5d29e82c1bc2518de0dbe048e6598"
 
 http_archive(
     name = "io_bazel_rules_kotlin",
     sha256 = RULES_KOTLIN_SHA,
-    strip_prefix = "rules_kotlin-%s" % RULES_KOTLIN_VERSION,
-    type = "zip",
-    urls = ["https://github.com/bazelbuild/rules_kotlin/archive/%s.zip" % RULES_KOTLIN_VERSION],
+    urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/%s/rules_kotlin_release.tgz" % RULES_KOTLIN_VERSION],
 )
 
 load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories", "kt_register_toolchains")
diff --git a/java/dagger/hilt/android/processor/BUILD b/java/dagger/hilt/android/processor/BUILD
index 5be8dbd..95ccb17 100644
--- a/java/dagger/hilt/android/processor/BUILD
+++ b/java/dagger/hilt/android/processor/BUILD
@@ -51,6 +51,7 @@
         "//java/dagger/hilt/processor/internal:component_descriptor",
         "//java/dagger/hilt/processor/internal:component_names",
         "//java/dagger/hilt/processor/internal:components",
+        "//java/dagger/hilt/processor/internal:kotlin",
         "//java/dagger/hilt/processor/internal:processor_errors",
         "//java/dagger/hilt/processor/internal:processors",
         "//java/dagger/hilt/processor/internal/aggregateddeps:annotation",
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
index 77bac27..f538448 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
@@ -35,9 +35,10 @@
 import dagger.hilt.processor.internal.BadInputException;
 import dagger.hilt.processor.internal.ClassNames;
 import dagger.hilt.processor.internal.Components;
-import dagger.hilt.processor.internal.KotlinMetadata;
+import dagger.hilt.processor.internal.KotlinMetadataUtils;
 import dagger.hilt.processor.internal.ProcessorErrors;
 import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
 import java.util.LinkedHashSet;
 import java.util.Optional;
 import java.util.stream.Collectors;
@@ -251,11 +252,10 @@
       // If this AndroidEntryPoint is a Kotlin class and its base type is also Kotlin and has
       // default values declared in its constructor then error out because for the short-form
       // usage of @AndroidEntryPoint the bytecode transformation will be done incorrectly.
+      KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
       ProcessorErrors.checkState(
-          !KotlinMetadata.of(androidEntryPointElement).isPresent()
-              || !KotlinMetadata.of(baseElement)
-                  .map(KotlinMetadata::containsConstructorWithDefaultParam)
-                  .orElse(false),
+          !metadataUtil.hasMetadata(androidEntryPointElement)
+              || !metadataUtil.containsConstructorWithDefaultParam(baseElement),
           baseElement,
           "The base class, '%s', of the @AndroidEntryPoint, '%s', contains a constructor with "
               + "default parameters. This is currently not supported by the Gradle plugin. Either "
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
index ff96498..55e9ddc 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
@@ -85,9 +85,11 @@
         "//java/dagger/hilt/android/processor/internal:android_classnames",
         "//java/dagger/hilt/processor/internal:classnames",
         "//java/dagger/hilt/processor/internal:components",
+        "//java/dagger/hilt/processor/internal:kotlin",
         "//java/dagger/hilt/processor/internal:processor_errors",
         "//java/dagger/hilt/processor/internal:processors",
         "//java/dagger/internal/codegen/extension",
+        "//java/dagger/internal/codegen/kotlin",
         "//java/dagger/internal/guava:base",
         "//java/dagger/internal/guava:collect",
         "@google_bazel_common//third_party/java/auto:value",
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
index 092fe0b..cbc51b3 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
@@ -37,9 +37,11 @@
         "//java/dagger/hilt/processor/internal:base_processor",
         "//java/dagger/hilt/processor/internal:classnames",
         "//java/dagger/hilt/processor/internal:components",
+        "//java/dagger/hilt/processor/internal:kotlin",
         "//java/dagger/hilt/processor/internal:processor_errors",
         "//java/dagger/hilt/processor/internal:processors",
         "//java/dagger/internal/codegen/extension",
+        "//java/dagger/internal/codegen/kotlin",
         "//java/dagger/internal/guava:base",
         "//java/dagger/internal/guava:collect",
         "@google_bazel_common//third_party/java/auto:service",
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
index 39005b7..d18e7c4 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.JavaFile;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.ParameterSpec;
@@ -137,7 +138,11 @@
     } else {
       builder
           .addParameter(testClassName, "test")
-          .addStatement("return test.$L", bindValue.variableElement().getSimpleName());
+          .addStatement(
+              "return $L",
+              bindValue.getterElement().isPresent()
+                  ? CodeBlock.of("test.$L()", bindValue.getterElement().get().getSimpleName())
+                  : CodeBlock.of("test.$L", bindValue.variableElement().getSimpleName()));
     }
 
     ClassName annotationClassName = bindValue.annotationName();
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
index a592429..bf50288 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
@@ -18,19 +18,23 @@
 
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
 
+import com.google.auto.common.MoreElements;
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.ClassName;
 import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.KotlinMetadataUtils;
 import dagger.hilt.processor.internal.ProcessorErrors;
 import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
 import java.util.Collection;
 import java.util.Optional;
 import javax.inject.Inject;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
@@ -80,6 +84,8 @@
 
     abstract Optional<AnnotationMirror> mapKey();
 
+    abstract Optional<ExecutableElement> getterElement();
+
     static BindValueElement create(Element element) {
       ImmutableList<ClassName> bindValues = BindValueProcessor.getBindValueAnnotations(element);
       ProcessorErrors.checkState(
@@ -97,12 +103,26 @@
           annotationClassName.simpleName(),
           element);
 
-      ProcessorErrors.checkState(
-          !element.getModifiers().contains(Modifier.PRIVATE),
-          element,
-          "@%s fields cannot be private. Found: %s",
-          annotationClassName.simpleName(),
-          element);
+      KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
+      Optional<ExecutableElement> propertyGetter =
+          metadataUtil.hasMetadata(element)
+              ? metadataUtil.getPropertyGetter(MoreElements.asVariable(element))
+              : Optional.empty();
+      if (propertyGetter.isPresent()) {
+        ProcessorErrors.checkState(
+            !propertyGetter.get().getModifiers().contains(Modifier.PRIVATE),
+            element,
+            "@%s field getter cannot be private. Found: %s",
+            annotationClassName.simpleName(),
+            element);
+      } else {
+        ProcessorErrors.checkState(
+            !element.getModifiers().contains(Modifier.PRIVATE),
+            element,
+            "@%s fields cannot be private. Found: %s",
+            annotationClassName.simpleName(),
+            element);
+      }
 
       ProcessorErrors.checkState(
           !Processors.hasAnnotation(element, Inject.class),
@@ -151,7 +171,8 @@
           qualifiers.isEmpty()
               ? Optional.<AnnotationMirror>empty()
               : Optional.<AnnotationMirror>of(qualifiers.get(0)),
-          optionalMapKeys);
+          optionalMapKeys,
+          propertyGetter);
     }
   }
 }
diff --git a/java/dagger/hilt/processor/BUILD b/java/dagger/hilt/processor/BUILD
index c04d0bc..b772e9d 100644
--- a/java/dagger/hilt/processor/BUILD
+++ b/java/dagger/hilt/processor/BUILD
@@ -69,6 +69,7 @@
         "//java/dagger/hilt/processor/internal:component_descriptor",
         "//java/dagger/hilt/processor/internal:component_names",
         "//java/dagger/hilt/processor/internal:components",
+        "//java/dagger/hilt/processor/internal:kotlin",
         "//java/dagger/hilt/processor/internal:processor_errors",
         "//java/dagger/hilt/processor/internal:processors",
         "//java/dagger/hilt/processor/internal/aggregateddeps:annotation",
diff --git a/java/dagger/hilt/processor/internal/BUILD b/java/dagger/hilt/processor/internal/BUILD
index 9c9eb9f..ac57c70 100644
--- a/java/dagger/hilt/processor/internal/BUILD
+++ b/java/dagger/hilt/processor/internal/BUILD
@@ -54,16 +54,20 @@
     name = "processors",
     srcs = [
         "AnnotationValues.java",
-        "KotlinMetadata.java",
         "Processors.java",
     ],
     deps = [
         ":classnames",
+        ":kotlin",
         ":processor_errors",
         "//java/dagger/internal/codegen/extension",
+        "//java/dagger/internal/codegen/kotlin",
+        "//java/dagger/internal/codegen/langmodel",
         "//java/dagger/internal/guava:base",
         "//java/dagger/internal/guava:collect",
         "@google_bazel_common//third_party/java/javapoet",
+        "@google_bazel_common//third_party/java/jsr305_annotations",
+        "@google_bazel_common//third_party/java/jsr330_inject",
         "@maven//:com_google_auto_auto_common",
         "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
         "@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
@@ -128,6 +132,15 @@
     ],
 )
 
+java_library(
+    name = "kotlin",
+    srcs = ["KotlinMetadataUtils.java"],
+    deps = [
+        "//:dagger_with_compiler",
+        "//java/dagger/internal/codegen/kotlin",
+    ],
+)
+
 filegroup(
     name = "srcs_filegroup",
     srcs = glob(["*"]),
diff --git a/java/dagger/hilt/processor/internal/KotlinMetadata.java b/java/dagger/hilt/processor/internal/KotlinMetadata.java
deleted file mode 100644
index 2fe6321..0000000
--- a/java/dagger/hilt/processor/internal/KotlinMetadata.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2020 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.hilt.processor.internal;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.hilt.processor.internal.AnnotationValues.getIntArrayValue;
-import static dagger.hilt.processor.internal.AnnotationValues.getIntValue;
-import static dagger.hilt.processor.internal.AnnotationValues.getOptionalIntValue;
-import static dagger.hilt.processor.internal.AnnotationValues.getOptionalStringValue;
-import static dagger.hilt.processor.internal.AnnotationValues.getStringArrayValue;
-import static dagger.hilt.processor.internal.AnnotationValues.getStringValue;
-
-import com.google.auto.common.MoreElements;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.TypeElement;
-import kotlin.Metadata;
-import kotlinx.metadata.Flag;
-import kotlinx.metadata.Flag.ValueParameter;
-import kotlinx.metadata.KmClassVisitor;
-import kotlinx.metadata.KmConstructorVisitor;
-import kotlinx.metadata.KmValueParameterVisitor;
-import kotlinx.metadata.jvm.KotlinClassHeader;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
-
-/** Data class of a TypeElement and its Kotlin metadata. */
-public final class KotlinMetadata {
-
-  private final KotlinClassMetadata.Class metadata;
-  private final TypeElement typeElement;
-
-  /**
-   * Kotlin metadata flag for this class.
-   *
-   * <p>Use {@link Flag.Class} to apply the right mask and obtain a specific value.
-   */
-  private final int flags;
-
-  private KotlinMetadata(KotlinClassMetadata.Class metadata, TypeElement typeElement, int flags) {
-    this.metadata = metadata;
-    this.typeElement = typeElement;
-    this.flags = flags;
-  }
-
-  /** Returns true if the type element of this metadata is a Kotlin object. */
-  public boolean isObjectClass() {
-    return Flag.Class.IS_OBJECT.invoke(flags);
-  }
-
-  /** Returns true if the type element of this metadata is a Kotlin companion object. */
-  public boolean isCompanionObjectClass() {
-    return Flag.Class.IS_COMPANION_OBJECT.invoke(flags);
-  }
-
-  /**
-   * Returns true if the type element of this metadata contains a constructor with declared default
-   * values.
-   */
-  public boolean containsConstructorWithDefaultParam() {
-    final boolean[] containsDefaultParam = { false };
-    metadata.accept(
-        new KmClassVisitor() {
-          private final KmConstructorVisitor constructorVisitor =
-              new KmConstructorVisitor() {
-                @Override
-                public KmValueParameterVisitor visitValueParameter(int flags, String name) {
-                  containsDefaultParam[0] |= ValueParameter.DECLARES_DEFAULT_VALUE.invoke(flags);
-                  return super.visitValueParameter(flags, name);
-                }
-              };
-
-          @Override
-          public KmConstructorVisitor visitConstructor(int flags) {
-            return constructorVisitor;
-          }
-        });
-    return containsDefaultParam[0];
-  }
-
-  /** Returns the Kotlin Metadata of a given type element. */
-  public static Optional<KotlinMetadata> of(TypeElement typeElement) {
-    if (!isAnnotationPresent(typeElement, Metadata.class)) {
-      return Optional.empty();
-    }
-
-    KotlinClassMetadata.Class metadata = metadataOf(typeElement);
-    MetadataVisitor visitor = new MetadataVisitor();
-    metadata.accept(visitor);
-    return Optional.of(new KotlinMetadata(metadata, typeElement, visitor.classFlags));
-  }
-
-  private static KotlinClassMetadata.Class metadataOf(TypeElement typeElement) {
-    AnnotationMirror metadataAnnotation =
-        MoreElements.getAnnotationMirror(typeElement, Metadata.class).get();
-    KotlinClassHeader header =
-        new KotlinClassHeader(
-            getIntValue(metadataAnnotation, "k"),
-            getIntArrayValue(metadataAnnotation, "mv"),
-            getIntArrayValue(metadataAnnotation, "bv"),
-            getStringArrayValue(metadataAnnotation, "d1"),
-            getStringArrayValue(metadataAnnotation, "d2"),
-            getStringValue(metadataAnnotation, "xs"),
-            getOptionalStringValue(metadataAnnotation, "pn").orElse(null),
-            getOptionalIntValue(metadataAnnotation, "xi").orElse(null));
-    KotlinClassMetadata metadata = KotlinClassMetadata.read(header);
-    if (metadata == null) {
-      // Should only happen on Kotlin < 1.0 (i.e. metadata version < 1.1)
-      throw new IllegalStateException(
-          "Unsupported metadata version. Check that your Kotlin version is >= 1.0");
-    }
-    if (metadata instanceof KotlinClassMetadata.Class) {
-      return (KotlinClassMetadata.Class) metadata;
-    } else {
-      throw new IllegalStateException("Unsupported metadata type: " + metadata);
-    }
-  }
-
-  private static final class MetadataVisitor extends KmClassVisitor {
-    int classFlags;
-
-    @Override
-    public void visit(int flags, String s) {
-      this.classFlags = flags;
-    }
-  }
-}
diff --git a/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java b/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java
new file mode 100644
index 0000000..ec5ddf8
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.hilt.processor.internal;
+
+import dagger.Component;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
+import javax.inject.Singleton;
+
+/** A single-use provider of {@link KotlinMetadataUtil}. */
+// TODO(erichang):  Revert this, should be wrapped with a Dagger module.
+public final class KotlinMetadataUtils {
+
+  @Singleton
+  @Component
+  interface MetadataComponent {
+    KotlinMetadataUtil get();
+  }
+
+  /** Gets the metadata util. */
+  public static KotlinMetadataUtil getMetadataUtil() {
+    return DaggerKotlinMetadataUtils_MetadataComponent.create().get();
+  }
+
+  private KotlinMetadataUtils() {}
+}
diff --git a/java/dagger/hilt/processor/internal/Processors.java b/java/dagger/hilt/processor/internal/Processors.java
index b387caf..eaac736 100644
--- a/java/dagger/hilt/processor/internal/Processors.java
+++ b/java/dagger/hilt/processor/internal/Processors.java
@@ -17,15 +17,18 @@
 package dagger.hilt.processor.internal;
 
 import static com.google.auto.common.MoreElements.asPackage;
+import static com.google.auto.common.MoreElements.asVariable;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
 import static javax.lang.model.element.Modifier.ABSTRACT;
 import static javax.lang.model.element.Modifier.STATIC;
 
+import com.google.auto.common.AnnotationMirrors;
 import com.google.auto.common.GeneratedAnnotations;
 import com.google.auto.common.MoreElements;
 import com.google.auto.common.MoreTypes;
 import com.google.common.base.CaseFormat;
+import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.FluentIterable;
@@ -43,6 +46,8 @@
 import com.squareup.javapoet.ParameterizedTypeName;
 import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.extension.DaggerStreams;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
 import java.lang.annotation.Annotation;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -50,8 +55,10 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.annotation.processing.RoundEnvironment;
+import javax.inject.Qualifier;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
@@ -726,7 +733,26 @@
 
   /** Returns Qualifier annotated annotations found on an element. */
   public static ImmutableList<AnnotationMirror> getQualifierAnnotations(Element element) {
-    return getAnnotationsAnnotatedWith(element, ClassNames.QUALIFIER);
+    // TODO(bcorso): Consolidate this logic with InjectionAnnotations in Dagger
+    ImmutableSet<? extends AnnotationMirror> qualifiers =
+        AnnotationMirrors.getAnnotatedAnnotations(element, Qualifier.class);
+    KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
+    if (element.getKind() == ElementKind.FIELD && metadataUtil.hasMetadata(element)) {
+      VariableElement fieldElement = asVariable(element);
+      return Stream.concat(
+              qualifiers.stream(),
+              metadataUtil.isMissingSyntheticPropertyForAnnotations(fieldElement)
+                  ? Stream.empty()
+                  : metadataUtil
+                      .getSyntheticPropertyAnnotations(fieldElement, Qualifier.class)
+                      .stream())
+          .map(AnnotationMirrors.equivalence()::wrap)
+          .distinct()
+          .map(Wrapper::get)
+          .collect(DaggerStreams.toImmutableList());
+    } else {
+      return ImmutableList.copyOf(qualifiers);
+    }
   }
 
   /** Returns Scope annotated annotations found on an element. */
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
index 7d04be5..d07e773 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
@@ -37,9 +37,10 @@
 import dagger.hilt.processor.internal.BaseProcessor;
 import dagger.hilt.processor.internal.ClassNames;
 import dagger.hilt.processor.internal.Components;
-import dagger.hilt.processor.internal.KotlinMetadata;
+import dagger.hilt.processor.internal.KotlinMetadataUtils;
 import dagger.hilt.processor.internal.ProcessorErrors;
 import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
@@ -290,10 +291,8 @@
   }
 
   private static boolean isKotlinObject(TypeElement type) {
-    Optional<KotlinMetadata> kotlinMetadata = KotlinMetadata.of(type);
-    return kotlinMetadata
-        .map(metadata -> metadata.isObjectClass() || metadata.isCompanionObjectClass())
-        .orElse(false);
+    KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
+    return metadataUtil.isObjectClass(type) || metadataUtil.isCompanionObjectClass(type);
   }
 
   private static boolean hasOnlyStaticProvides(TypeElement module) {
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
index f18f7d3..1eb8d36 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
@@ -48,9 +48,11 @@
         "//java/dagger/hilt/processor/internal:base_processor",
         "//java/dagger/hilt/processor/internal:classnames",
         "//java/dagger/hilt/processor/internal:components",
+        "//java/dagger/hilt/processor/internal:kotlin",
         "//java/dagger/hilt/processor/internal:processor_errors",
         "//java/dagger/hilt/processor/internal:processors",
         "//java/dagger/internal/codegen/extension",
+        "//java/dagger/internal/codegen/kotlin",
         "//java/dagger/internal/guava:collect",
         "@google_bazel_common//third_party/java/auto:service",
         "@google_bazel_common//third_party/java/auto:value",
diff --git a/java/dagger/hilt/processor/internal/root/BUILD b/java/dagger/hilt/processor/internal/root/BUILD
index 3a0d0ac..923a79e 100644
--- a/java/dagger/hilt/processor/internal/root/BUILD
+++ b/java/dagger/hilt/processor/internal/root/BUILD
@@ -69,11 +69,13 @@
         ":root_type",
         "//java/dagger/hilt/processor/internal:classnames",
         "//java/dagger/hilt/processor/internal:component_descriptor",
+        "//java/dagger/hilt/processor/internal:kotlin",
         "//java/dagger/hilt/processor/internal:processor_errors",
         "//java/dagger/hilt/processor/internal:processors",
         "//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
         "//java/dagger/hilt/processor/internal/aliasof:alias_ofs",
         "//java/dagger/internal/codegen/extension",
+        "//java/dagger/internal/codegen/kotlin",
         "//java/dagger/internal/guava:base",
         "//java/dagger/internal/guava:collect",
         "@google_bazel_common//third_party/java/auto:value",
diff --git a/java/dagger/hilt/processor/internal/root/RootMetadata.java b/java/dagger/hilt/processor/internal/root/RootMetadata.java
index 59a3348..d712341 100644
--- a/java/dagger/hilt/processor/internal/root/RootMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/RootMetadata.java
@@ -30,12 +30,12 @@
 import dagger.hilt.processor.internal.ClassNames;
 import dagger.hilt.processor.internal.ComponentDescriptor;
 import dagger.hilt.processor.internal.ComponentTree;
-import dagger.hilt.processor.internal.KotlinMetadata;
+import dagger.hilt.processor.internal.KotlinMetadataUtils;
 import dagger.hilt.processor.internal.Processors;
 import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
 import dagger.hilt.processor.internal.aliasof.AliasOfs;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
 import java.util.List;
-import java.util.Optional;
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
@@ -194,11 +194,9 @@
   }
 
   private static boolean daggerCanConstruct(TypeElement type) {
-    Optional<KotlinMetadata> kotlinMetadata = KotlinMetadata.of(type);
+    KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
     boolean isKotlinObject =
-        kotlinMetadata
-            .map(metadata -> metadata.isObjectClass() || metadata.isCompanionObjectClass())
-            .orElse(false);
+        metadataUtil.isObjectClass(type) || metadataUtil.isCompanionObjectClass(type);
     if (isKotlinObject) {
       // Treat Kotlin object modules as if Dagger can construct them (it technically can't, but it
       // doesn't need to as it can use them since all their provision methods are static).
diff --git a/java/dagger/internal/codegen/BUILD b/java/dagger/internal/codegen/BUILD
index e64b99b..323e9ca 100644
--- a/java/dagger/internal/codegen/BUILD
+++ b/java/dagger/internal/codegen/BUILD
@@ -79,6 +79,7 @@
     artifact_target_libs = [
         ":package_info",
         "//java/dagger/internal/codegen/base",
+        "//java/dagger/internal/codegen/base:shared",
         "//java/dagger/internal/codegen/binding",
         "//java/dagger/internal/codegen/bindinggraphvalidation",
         "//java/dagger/internal/codegen/compileroption",
diff --git a/java/dagger/internal/codegen/base/BUILD b/java/dagger/internal/codegen/base/BUILD
index 71a5f29..0bcbb12 100644
--- a/java/dagger/internal/codegen/base/BUILD
+++ b/java/dagger/internal/codegen/base/BUILD
@@ -19,12 +19,23 @@
 
 package(default_visibility = ["//:src"])
 
+SHARED_SOURCES = [
+    "ClearableCache.java",
+    "MoreAnnotationMirrors.java",
+    "MoreAnnotationValues.java",
+]
+
 java_library(
     name = "base",
-    srcs = glob(["*.java"]),
+    srcs = glob(
+        ["*.java"],
+        exclude = SHARED_SOURCES,
+    ),
     plugins = ["//java/dagger/internal/codegen/bootstrap"],
     tags = ["maven:merged"],
+    exports = [":shared"],
     deps = [
+        ":shared",
         "//java/dagger:core",
         "//java/dagger/internal/codegen/extension",
         "//java/dagger/internal/codegen/javapoet",
@@ -40,3 +51,16 @@
         "@maven//:com_google_auto_auto_common",
     ],
 )
+
+# TODO(bcorso): Remove this target but first remove spi and producers from :base
+java_library(
+    name = "shared",
+    srcs = SHARED_SOURCES,
+    tags = ["maven:merged"],
+    deps = [
+        "//java/dagger/internal/codegen/extension",
+        "//java/dagger/internal/guava:base",
+        "//java/dagger/internal/guava:collect",
+        "@maven//:com_google_auto_auto_common",
+    ],
+)
diff --git a/java/dagger/internal/codegen/kotlin/BUILD b/java/dagger/internal/codegen/kotlin/BUILD
index b41dfb5..f919ef9 100644
--- a/java/dagger/internal/codegen/kotlin/BUILD
+++ b/java/dagger/internal/codegen/kotlin/BUILD
@@ -25,7 +25,8 @@
     plugins = ["//java/dagger/internal/codegen/bootstrap"],
     tags = ["maven:merged"],
     deps = [
-        "//java/dagger/internal/codegen/base",
+        "//java/dagger:core",
+        "//java/dagger/internal/codegen/base:shared",
         "//java/dagger/internal/codegen/extension",
         "//java/dagger/internal/codegen/langmodel",
         "//java/dagger/internal/guava:base",
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
index c65f5e1..1f07279 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
@@ -16,7 +16,6 @@
 
 package dagger.internal.codegen.kotlin;
 
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
 import static com.google.common.base.Preconditions.checkArgument;
 import static dagger.internal.codegen.base.MoreAnnotationValues.getIntArrayValue;
 import static dagger.internal.codegen.base.MoreAnnotationValues.getIntValue;
@@ -39,18 +38,21 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
-import javax.inject.Inject;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.util.ElementFilter;
 import kotlin.Metadata;
 import kotlinx.metadata.Flag;
+import kotlinx.metadata.Flag.ValueParameter;
 import kotlinx.metadata.KmClassVisitor;
+import kotlinx.metadata.KmConstructorVisitor;
 import kotlinx.metadata.KmExtensionType;
 import kotlinx.metadata.KmPropertyExtensionVisitor;
 import kotlinx.metadata.KmPropertyVisitor;
+import kotlinx.metadata.KmValueParameterVisitor;
 import kotlinx.metadata.jvm.JvmFieldSignature;
 import kotlinx.metadata.jvm.JvmMethodSignature;
 import kotlinx.metadata.jvm.JvmPropertyExtensionVisitor;
@@ -60,51 +62,163 @@
 /** Data class of a TypeElement and its Kotlin metadata. */
 final class KotlinMetadata {
 
+  // Kotlin suffix for fields that are for a delegated property.
+  // See:
+  // https://github.com/JetBrains/kotlin/blob/master/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.kt#L32
+  private static final String DELEGATED_PROPERTY_NAME_SUFFIX = "$delegate";
+
   private final TypeElement typeElement;
 
+  private final KotlinClassMetadata.Class data;
+
   /**
    * Kotlin metadata flag for this class.
    *
    * <p>Use {@link Flag.Class} to apply the right mask and obtain a specific value.
    */
-  private final int flags;
+  private final Supplier<Integer> flags;
 
-  private final Optional<String> companionObjectName;
+  private final Supplier<Optional<String>> companionObjectName;
 
-  // Map that associates @Inject field elements with its Kotlin synthetic method for annotations.
+  private final Supplier<List<Property>> properties;
+
+  private final Supplier<Map<String, Property>> propertyDescriptors;
+
+  private final Supplier<Map<String, ExecutableElement>> methodDescriptors;
+
+  // Map that associates field elements with its Kotlin synthetic method for annotations.
   private final Supplier<Map<VariableElement, Optional<MethodForAnnotations>>>
       elementFieldAnnotationMethodMap;
 
-  private KotlinMetadata(
-      TypeElement typeElement,
-      int flags,
-      Optional<String> companionObjectName,
-      List<Property> properties) {
+  // Map that associates field elements with its Kotlin getter method.
+  private final Supplier<Map<VariableElement, Optional<ExecutableElement>>>
+      elementFieldGetterMethodMap;
+
+  private final Supplier<Boolean> containsConstructorWithDefaultParam;
+
+  private KotlinMetadata(TypeElement typeElement, KotlinClassMetadata.Class data) {
     this.typeElement = typeElement;
-    this.flags = flags;
-    this.companionObjectName = companionObjectName;
+    this.data = data;
+    this.flags = Suppliers.memoize(this::retrieveFlags);
+    this.companionObjectName = Suppliers.memoize(this::retrieveCompanionObjectName);
+    this.properties = Suppliers.memoize(this::retrieveProperties);
+    this.propertyDescriptors =
+        Suppliers.memoize(
+            () ->
+                properties.get().stream()
+                    .filter(property -> property.getFieldSignature().isPresent())
+                    .collect(
+                        Collectors.toMap(
+                            property -> property.getFieldSignature().get(), Function.identity())));
+    this.methodDescriptors =
+        Suppliers.memoize(
+            () ->
+                ElementFilter.methodsIn(typeElement.getEnclosedElements()).stream()
+                    .collect(
+                        Collectors.toMap(
+                            DaggerElements::getMethodDescriptor, Function.identity())));
     this.elementFieldAnnotationMethodMap =
         Suppliers.memoize(
-            () -> {
-              Map<String, Property> propertyDescriptors =
-                  properties.stream()
-                      .filter(property -> property.getFieldSignature().isPresent())
-                      .collect(
-                          Collectors.toMap(
-                              property -> property.getFieldSignature().get(), Function.identity()));
-              Map<String, ExecutableElement> methodDescriptors =
-                  ElementFilter.methodsIn(typeElement.getEnclosedElements()).stream()
-                      .collect(
-                          Collectors.toMap(
-                              DaggerElements::getMethodDescriptor, Function.identity()));
-              return mapFieldToAnnotationMethod(propertyDescriptors, methodDescriptors);
-            });
+            () -> mapFieldToAnnotationMethod(propertyDescriptors.get(), methodDescriptors.get()));
+    this.elementFieldGetterMethodMap =
+        Suppliers.memoize(
+            () -> mapFieldToGetterMethod(propertyDescriptors.get(), methodDescriptors.get()));
+    this.containsConstructorWithDefaultParam =
+        Suppliers.memoize(this::checkConstructorForDefaultParam);
+  }
+
+  private int retrieveFlags() {
+    FlagsVisitor visitor = new FlagsVisitor();
+    data.accept(visitor);
+    return visitor.flags;
+  }
+
+  private static final class FlagsVisitor extends KmClassVisitor {
+
+    int flags;
+
+    @Override
+    public void visit(int flags, String name) {
+      this.flags = flags;
+    }
+  }
+
+  private Optional<String> retrieveCompanionObjectName() {
+    CompanionObjectNameVisitor visitor = new CompanionObjectNameVisitor();
+    data.accept(visitor);
+    return visitor.name;
+  }
+
+  private static final class CompanionObjectNameVisitor extends KmClassVisitor {
+
+    Optional<String> name = Optional.empty();
+
+    @Override
+    public void visitCompanionObject(String name) {
+      this.name = Optional.of(name);
+    }
+  }
+
+  private List<Property> retrieveProperties() {
+    PropertiesVisitor visitor = new PropertiesVisitor();
+    data.accept(visitor);
+    return visitor.properties;
+  }
+
+  private static final class PropertiesVisitor extends KmClassVisitor {
+
+    List<Property> properties = new ArrayList<>();
+
+    @Override
+    public KmPropertyVisitor visitProperty(
+        int flags, String name, int getterFlags, int setterFlags) {
+      return new KmPropertyVisitor() {
+        Optional<String> fieldSignature;
+        Optional<String> getterSignature = Optional.empty();
+        Optional<String> methodForAnnotationsSignature = Optional.empty();
+
+        @Override
+        public KmPropertyExtensionVisitor visitExtensions(KmExtensionType kmExtensionType) {
+          if (!kmExtensionType.equals(JvmPropertyExtensionVisitor.TYPE)) {
+            return null;
+          }
+
+          return new JvmPropertyExtensionVisitor() {
+            @Override
+            public void visit(
+                int jvmFlags,
+                @Nullable JvmFieldSignature jvmFieldSignature,
+                @Nullable JvmMethodSignature jvmGetterSignature,
+                @Nullable JvmMethodSignature jvmSetterSignature) {
+              fieldSignature =
+                  Optional.ofNullable(jvmFieldSignature).map(JvmFieldSignature::asString);
+              getterSignature =
+                  Optional.ofNullable(jvmGetterSignature).map(JvmMethodSignature::asString);
+            }
+
+            @Override
+            public void visitSyntheticMethodForAnnotations(
+                @Nullable JvmMethodSignature methodSignature) {
+              methodForAnnotationsSignature =
+                  Optional.ofNullable(methodSignature).map(JvmMethodSignature::asString);
+            }
+          };
+        }
+
+        @Override
+        public void visitEnd() {
+          properties.add(
+              new Property(
+                  name, flags, fieldSignature, getterSignature, methodForAnnotationsSignature));
+        }
+      };
+    }
   }
 
   private Map<VariableElement, Optional<MethodForAnnotations>> mapFieldToAnnotationMethod(
       Map<String, Property> propertyDescriptors, Map<String, ExecutableElement> methodDescriptors) {
     return ElementFilter.fieldsIn(typeElement.getEnclosedElements()).stream()
-        .filter(field -> isAnnotationPresent(field, Inject.class))
+        .filter(field -> !field.getModifiers().contains(Modifier.STATIC))
         .collect(
             Collectors.toMap(
                 Function.identity(),
@@ -120,23 +234,70 @@
                                     .orElse(MethodForAnnotations.MISSING))));
   }
 
+  private Map<VariableElement, Optional<ExecutableElement>> mapFieldToGetterMethod(
+      Map<String, Property> propertyDescriptors, Map<String, ExecutableElement> methodDescriptors) {
+    return ElementFilter.fieldsIn(typeElement.getEnclosedElements()).stream()
+        .filter(field -> !field.getModifiers().contains(Modifier.STATIC))
+        .collect(
+            Collectors.toMap(
+                Function.identity(),
+                field ->
+                    findProperty(field, propertyDescriptors)
+                        .getGetterMethodSignature()
+                        .flatMap(
+                            signature -> Optional.ofNullable(methodDescriptors.get(signature)))));
+  }
+
   private Property findProperty(VariableElement field, Map<String, Property> propertyDescriptors) {
     String fieldDescriptor = getFieldDescriptor(field);
     if (propertyDescriptors.containsKey(fieldDescriptor)) {
       return propertyDescriptors.get(fieldDescriptor);
     } else {
       // Fallback to finding property by name, see: https://youtrack.jetbrains.com/issue/KT-35124
+      final String propertyName = getPropertyNameFromField(field);
       return propertyDescriptors.values().stream()
-          .filter(property -> field.getSimpleName().contentEquals(property.name))
+          .filter(property -> propertyName.contentEquals(property.name))
           .collect(DaggerCollectors.onlyElement());
     }
   }
 
+  private static String getPropertyNameFromField(VariableElement field) {
+    String name = field.getSimpleName().toString();
+    if (name.endsWith(DELEGATED_PROPERTY_NAME_SUFFIX)) {
+      return name.substring(0, name.length() - DELEGATED_PROPERTY_NAME_SUFFIX.length());
+    } else {
+      return name;
+    }
+  }
+
+  private boolean checkConstructorForDefaultParam() {
+    ConstructorWithDefaultParamVisitor visitor = new ConstructorWithDefaultParamVisitor();
+    data.accept(visitor);
+    return visitor.containsConstructorWithDefaultParam;
+  }
+
+  private static final class ConstructorWithDefaultParamVisitor extends KmClassVisitor {
+
+    boolean containsConstructorWithDefaultParam;
+
+    @Override
+    public KmConstructorVisitor visitConstructor(int flags) {
+      return new KmConstructorVisitor() {
+        @Override
+        public KmValueParameterVisitor visitValueParameter(int flags, String name) {
+          containsConstructorWithDefaultParam |=
+              ValueParameter.DECLARES_DEFAULT_VALUE.invoke(flags);
+          return super.visitValueParameter(flags, name);
+        }
+      };
+    }
+  }
+
   TypeElement getTypeElement() {
     return typeElement;
   }
 
-  /** Gets the synthetic method for annotations of a given @Inject annotated field element. */
+  /** Gets the synthetic method for annotations of a given field element. */
   Optional<ExecutableElement> getSyntheticAnnotationMethod(VariableElement fieldElement) {
     checkArgument(elementFieldAnnotationMethodMap.get().containsKey(fieldElement));
     return elementFieldAnnotationMethodMap
@@ -169,12 +330,12 @@
   }
 
   boolean isObjectClass() {
-    return Flag.Class.IS_OBJECT.invoke(flags);
+    return Flag.Class.IS_OBJECT.invoke(flags.get());
   }
 
   /** Returns true if the type element of this metadata is a Kotlin companion object. */
   boolean isCompanionObjectClass() {
-    return Flag.Class.IS_COMPANION_OBJECT.invoke(flags);
+    return Flag.Class.IS_COMPANION_OBJECT.invoke(flags.get());
   }
 
   /**
@@ -183,19 +344,27 @@
    * returns an empty optional.
    */
   Optional<String> getCompanionObjectName() {
-    return companionObjectName;
+    return companionObjectName.get();
   }
 
   boolean isPrivate() {
-    return Flag.IS_PRIVATE.invoke(flags);
+    return Flag.IS_PRIVATE.invoke(flags.get());
+  }
+
+  /** Gets the getter method of a given field element corresponding to a property. */
+  Optional<ExecutableElement> getPropertyGetter(VariableElement fieldElement) {
+    checkArgument(elementFieldGetterMethodMap.get().containsKey(fieldElement));
+    return elementFieldGetterMethodMap.get().get(fieldElement);
+  }
+
+  /** Returns true if any constructor of the defined a default parameter. */
+  public boolean containsConstructorWithDefaultParam() {
+    return containsConstructorWithDefaultParam.get();
   }
 
   /** Parse Kotlin class metadata from a given type element * */
   static KotlinMetadata from(TypeElement typeElement) {
-    MetadataVisitor visitor = new MetadataVisitor();
-    metadataOf(typeElement).accept(visitor);
-    return new KotlinMetadata(
-        typeElement, visitor.classFlags, visitor.companionObjectName, visitor.classProperties);
+    return new KotlinMetadata(typeElement, metadataOf(typeElement));
   }
 
   private static KotlinClassMetadata.Class metadataOf(TypeElement typeElement) {
@@ -226,80 +395,25 @@
     }
   }
 
-  private static final class MetadataVisitor extends KmClassVisitor {
-
-    int classFlags;
-    Optional<String> companionObjectName = Optional.empty();
-    List<Property> classProperties = new ArrayList<>();
-
-    @Override
-    public void visit(int flags, String s) {
-      this.classFlags = flags;
-    }
-
-    @Override
-    public void visitCompanionObject(@Nullable String companionObjectName) {
-      this.companionObjectName = Optional.ofNullable(companionObjectName);
-    }
-
-    @Override
-    public KmPropertyVisitor visitProperty(
-        int flags, String name, int getterFlags, int setterFlags) {
-      return new KmPropertyVisitor() {
-        Optional<String> fieldSignature;
-        Optional<String> methodForAnnotationsSignature = Optional.empty();
-
-        @Override
-        public KmPropertyExtensionVisitor visitExtensions(KmExtensionType kmExtensionType) {
-          if (!kmExtensionType.equals(JvmPropertyExtensionVisitor.TYPE)) {
-            return null;
-          }
-
-          return new JvmPropertyExtensionVisitor() {
-            @Override
-            public void visit(
-                int jvmFlags,
-                @Nullable JvmFieldSignature jvmFieldSignature,
-                @Nullable JvmMethodSignature getterSignature,
-                @Nullable JvmMethodSignature setterSignature) {
-              fieldSignature =
-                  Optional.ofNullable(jvmFieldSignature).map(JvmFieldSignature::asString);
-            }
-
-            @Override
-            public void visitSyntheticMethodForAnnotations(
-                @Nullable JvmMethodSignature methodSignature) {
-              methodForAnnotationsSignature =
-                  Optional.ofNullable(methodSignature).map(JvmMethodSignature::asString);
-            }
-          };
-        }
-
-        @Override
-        public void visitEnd() {
-          classProperties.add(
-              new Property(name, flags, fieldSignature, methodForAnnotationsSignature));
-        }
-      };
-    }
-  }
-
   /* Data class representing Kotlin Property Metadata */
   private static final class Property {
 
     private final String name;
     private final int flags;
     private final Optional<String> fieldSignature;
+    private final Optional<String> getterSignature;
     private final Optional<String> methodForAnnotationsSignature;
 
     Property(
         String name,
         int flags,
         Optional<String> fieldSignature,
+        Optional<String> getterSignature,
         Optional<String> methodForAnnotationsSignature) {
       this.name = name;
       this.flags = flags;
       this.fieldSignature = fieldSignature;
+      this.getterSignature = getterSignature;
       this.methodForAnnotationsSignature = methodForAnnotationsSignature;
     }
 
@@ -322,6 +436,10 @@
       return fieldSignature;
     }
 
+    Optional<String> getGetterMethodSignature() {
+      return getterSignature;
+    }
+
     /** Returns JVM method descriptor of the synthetic method for property annotations. */
     Optional<String> getMethodForAnnotationsSignature() {
       return methodForAnnotationsSignature;
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
index 1d49254..13c7cf2 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
@@ -24,6 +24,7 @@
 import com.google.common.collect.ImmutableList;
 import dagger.internal.codegen.extension.DaggerCollectors;
 import java.lang.annotation.Annotation;
+import java.util.Optional;
 import javax.inject.Inject;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
@@ -114,6 +115,15 @@
     return hasMetadata(typeElement) && metadataFactory.create(typeElement).isPrivate();
   }
 
+  public Optional<ExecutableElement> getPropertyGetter(VariableElement fieldElement) {
+    return metadataFactory.create(fieldElement).getPropertyGetter(fieldElement);
+  }
+
+  public boolean containsConstructorWithDefaultParam(TypeElement typeElement) {
+    return hasMetadata(typeElement)
+        && metadataFactory.create(typeElement).containsConstructorWithDefaultParam();
+  }
+
   /**
    * Returns {@code true} if the <code>@JvmStatic</code> annotation is present in the given element.
    */
diff --git a/java/dagger/internal/codegen/langmodel/DaggerElements.java b/java/dagger/internal/codegen/langmodel/DaggerElements.java
index 63c5e1d..12cec31 100644
--- a/java/dagger/internal/codegen/langmodel/DaggerElements.java
+++ b/java/dagger/internal/codegen/langmodel/DaggerElements.java
@@ -291,7 +291,9 @@
 
         @Override
         public String visitError(ErrorType errorType, Void v) {
-          return visitUnknown(errorType, null);
+          // For descriptor generating purposes we don't need a fully modeled type since we are
+          // only interested in obtaining the class name in its "internal form".
+          return visitDeclared(errorType, v);
         }
 
         @Override
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/java/dagger/hilt/android/simpleKotlin/SimpleTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/java/dagger/hilt/android/simpleKotlin/SimpleTest.kt
index 95b1417..b3a6be4 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/java/dagger/hilt/android/simpleKotlin/SimpleTest.kt
+++ b/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/java/dagger/hilt/android/simpleKotlin/SimpleTest.kt
@@ -44,9 +44,10 @@
 class SimpleTest {
   @get:Rule val rule = HiltAndroidRule(this)
 
-  @BindValue @JvmField val bindStr = "STRING_BINDING"
+  @BindValue val bindStr = "STRING_BINDING"
 
-  @Inject @JvmField var str: String? = null
+  @Inject @JvmField
+  var str: String? = null
 
   @AndroidEntryPoint
   class TestActivity : AppCompatActivity()
diff --git a/javatests/dagger/functional/kotlin/BUILD b/javatests/dagger/functional/kotlin/BUILD
index 8c886de..c91c962 100644
--- a/javatests/dagger/functional/kotlin/BUILD
+++ b/javatests/dagger/functional/kotlin/BUILD
@@ -34,10 +34,13 @@
             "FooWithInjectedQualifier.kt",
         ],
     ),
+    # TODO(user): Remove 'plugins' once kt_jvm_library supports 'exported_plugins'.
+    plugins = ["//javatests/dagger/functional/kotlin/processor:plugin"],
     deps = [
         ":foo_with_injected_qualifier",
         ":java_qualifier",
         "//:dagger_with_compiler",
+        "//javatests/dagger/functional/kotlin/processor:annotation",
     ],
 )
 
diff --git a/javatests/dagger/functional/kotlin/TestComponentWithQualifier.kt b/javatests/dagger/functional/kotlin/TestComponentWithQualifier.kt
index 15856f7..9aeb2d8 100644
--- a/javatests/dagger/functional/kotlin/TestComponentWithQualifier.kt
+++ b/javatests/dagger/functional/kotlin/TestComponentWithQualifier.kt
@@ -19,6 +19,7 @@
 import dagger.Component
 import dagger.Module
 import dagger.Provides
+import dagger.functional.kotlin.processor.TriggerGeneratedTypeProcessor
 import javax.inject.Inject
 
 @Component(modules = [TestKotlinModuleWithQualifier::class])
@@ -54,6 +55,7 @@
   @JavaTestQualifier val data: TestDataA
 )
 
+@TriggerGeneratedTypeProcessor
 class TestMemberInjectedClassWithQualifier {
   @Inject
   @JavaTestQualifier
@@ -76,4 +78,10 @@
 
   val noBackingFieldProperty: Int
     get() = 0
+
+  val delegatedProperty by lazy { "" }
+
+  val generatedTypeProperty = dagger.functional.kotlin.GeneratedType()
+
+  val generatedTypeDelegatedProperty by lazy { dagger.functional.kotlin.GeneratedType() }
 }
diff --git a/javatests/dagger/functional/kotlin/processor/BUILD b/javatests/dagger/functional/kotlin/processor/BUILD
new file mode 100644
index 0000000..31a45c7
--- /dev/null
+++ b/javatests/dagger/functional/kotlin/processor/BUILD
@@ -0,0 +1,37 @@
+# Copyright (C) 2019 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.
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+
+package(default_visibility = ["//:src"])
+
+java_plugin(
+    name = "plugin",
+    generates_api = 1,
+    processor_class = "dagger.functional.kotlin.processor.TestGeneratedTypeProcessor",
+    deps = [":processor"],
+)
+
+kt_jvm_library(
+    name = "processor",
+    srcs = ["TestGeneratedTypeProcessor.kt"],
+    deps = [
+        "@google_bazel_common//third_party/java/auto:service",
+        "@google_bazel_common//third_party/java/javapoet",
+    ],
+)
+
+kt_jvm_library(
+    name = "annotation",
+    srcs = ["TriggerGeneratedTypeProcessor.kt"],
+)
diff --git a/javatests/dagger/functional/kotlin/processor/TestGeneratedTypeProcessor.kt b/javatests/dagger/functional/kotlin/processor/TestGeneratedTypeProcessor.kt
new file mode 100644
index 0000000..4a1d6e2
--- /dev/null
+++ b/javatests/dagger/functional/kotlin/processor/TestGeneratedTypeProcessor.kt
@@ -0,0 +1,48 @@
+package dagger.functional.kotlin.processor
+
+import com.google.auto.service.AutoService
+import com.squareup.javapoet.JavaFile
+import com.squareup.javapoet.TypeSpec
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.Processor
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.Modifier
+import javax.lang.model.element.TypeElement
+
+/**
+ * A processor to be used in functional tests that will generate a simple class with fqname
+ * 'dagger.functional.kotlin.GeneratedType'. This processor is useful for testing situations
+ * with KAPT where a type is not resolvable and for which KAPT will generate stubs containing
+ * the 'error.NonExistentClass' type.
+ */
+@AutoService(Processor::class)
+class TestGeneratedTypeProcessor : AbstractProcessor() {
+
+  private var isSourceGenerated = false
+
+  override fun getSupportedAnnotationTypes() =
+    mutableSetOf("dagger.functional.kotlin.processor.TriggerGeneratedTypeProcessor")
+
+  override fun getSupportedSourceVersion() = SourceVersion.latestSupported()
+
+  override fun process(
+    annotations: MutableSet<out TypeElement>,
+    roundEnv: RoundEnvironment
+  ): Boolean {
+    if (isSourceGenerated) {
+      return false
+    }
+
+    JavaFile.builder(
+      "dagger.functional.kotlin",
+      TypeSpec.classBuilder("GeneratedType")
+        .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+        .build()
+    ).build().writeTo(processingEnv.filer)
+
+    isSourceGenerated = true
+
+    return false
+  }
+}
diff --git a/javatests/dagger/functional/kotlin/processor/TriggerGeneratedTypeProcessor.kt b/javatests/dagger/functional/kotlin/processor/TriggerGeneratedTypeProcessor.kt
new file mode 100644
index 0000000..c240fd3
--- /dev/null
+++ b/javatests/dagger/functional/kotlin/processor/TriggerGeneratedTypeProcessor.kt
@@ -0,0 +1,4 @@
+package dagger.functional.kotlin.processor
+
+@Retention(AnnotationRetention.BINARY)
+annotation class TriggerGeneratedTypeProcessor