Internal change

RELNOTES=N/A
PiperOrigin-RevId: 353987663
diff --git a/java/dagger/hilt/GeneratesRootInput.java b/java/dagger/hilt/GeneratesRootInput.java
index 4967c1d..ffd786f 100644
--- a/java/dagger/hilt/GeneratesRootInput.java
+++ b/java/dagger/hilt/GeneratesRootInput.java
@@ -22,7 +22,7 @@
 import java.lang.annotation.Target;
 
 /** For annotating annotations that generate input for the {@link GenerateComponents}. */
-// TODO(user): Rename to GenerateComponentsInput
+// TODO(danysantiago): Rename to GenerateComponentsInput
 @Target(ElementType.ANNOTATION_TYPE)
 @Retention(RetentionPolicy.CLASS)
 public @interface GeneratesRootInput {}
diff --git a/java/dagger/hilt/android/plugin/build.gradle b/java/dagger/hilt/android/plugin/build.gradle
index 8520c77..c52b535 100644
--- a/java/dagger/hilt/android/plugin/build.gradle
+++ b/java/dagger/hilt/android/plugin/build.gradle
@@ -43,7 +43,7 @@
 dependencies {
   implementation gradleApi()
   compileOnly 'com.android.tools.build:gradle:4.2.0-beta01'
-  // TODO(user): Make compileOnly to avoid dep for non-Kotlin projects.
+  // TODO(danysantiago): Make compileOnly to avoid dep for non-Kotlin projects.
   implementation 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.20'
   implementation 'org.javassist:javassist:3.26.0-GA'
   implementation 'org.ow2.asm:asm:9.0'
@@ -90,7 +90,7 @@
   enabled = false
 }
 
-// TODO(user): Use POM template in tools/ to avoid duplicating lines.
+// TODO(danysantiago): Use POM template in tools/ to avoid duplicating lines.
 publishing {
   publications {
     plugin(MavenPublication) {
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
index 203015e..e066f48 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
@@ -116,7 +116,7 @@
       return false
     }
 
-    // TODO(user): Handle classes with '$' in their name if they do become an issue.
+    // TODO(danysantiago): Handle classes with '$' in their name if they do become an issue.
     val superclassName = clazz.classFile.superclass
     val entryPointSuperclassName =
       clazz.packageName + ".Hilt_" + clazz.simpleName.replace("$", "_")
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt
index e4b055d..84b35b1 100644
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt
+++ b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt
@@ -121,7 +121,7 @@
         return
       }
 
-      // TODO(user): Only use project compiled sources as input, and not all dependency jars
+      // TODO(danysantiago): Only use project compiled sources as input, and not all dependency jars
       // Using 'null' key to obtain the full compile classpath since we are not using the
       // registerPreJavacGeneratedBytecode() API that would have otherwise given us a key to get
       // a classpath up to the generated bytecode associated with the key.
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/HiltCompilerOptions.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/HiltCompilerOptions.java
index 70be50b..577410d 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/HiltCompilerOptions.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/HiltCompilerOptions.java
@@ -22,7 +22,7 @@
 import javax.annotation.processing.ProcessingEnvironment;
 
 /** Hilt annotation processor options. */
-// TODO(user): Consider consolidating with Dagger compiler options logic.
+// TODO(danysantiago): Consider consolidating with Dagger compiler options logic.
 // TODO(user): Move this class to dagger/hilt/processor/internal
 public final class HiltCompilerOptions {
 
@@ -52,7 +52,7 @@
       if (value == null) {
         return defaultValue;
       }
-      // TODO(user): Strictly verify input, either 'true' or 'false' and nothing else.
+      // TODO(danysantiago): Strictly verify input, either 'true' or 'false' and nothing else.
       return Boolean.parseBoolean(value);
     }
 
diff --git a/java/dagger/hilt/codegen/package-info.java b/java/dagger/hilt/codegen/package-info.java
index 174dd6e..b6bf709 100644
--- a/java/dagger/hilt/codegen/package-info.java
+++ b/java/dagger/hilt/codegen/package-info.java
@@ -17,5 +17,5 @@
 /**
  * This package contains APIs for code generators that produce code that will be processed by Hilt.
  */
-// TODO(user): Add documentation about other code generators that produce input for Hilt
+// TODO(danysantiago): Add documentation about other code generators that produce input for Hilt
 package dagger.hilt.codegen;
diff --git a/java/dagger/hilt/internal/Preconditions.java b/java/dagger/hilt/internal/Preconditions.java
index 3a824e2..b2a84db 100644
--- a/java/dagger/hilt/internal/Preconditions.java
+++ b/java/dagger/hilt/internal/Preconditions.java
@@ -18,7 +18,7 @@
 
 /**
  * A partial copy of Guava's {@code com.google.common.base.Preconditions} meant to be used by
- * generated code. TODO(user): Consolidate with dagger.internal.Preconditions
+ * generated code. TODO(danysantiago): Consolidate with dagger.internal.Preconditions
  */
 public final class Preconditions {
 
diff --git a/java/dagger/internal/codegen/AssistedProcessingStep.java b/java/dagger/internal/codegen/AssistedProcessingStep.java
index 822e299..8c82750 100644
--- a/java/dagger/internal/codegen/AssistedProcessingStep.java
+++ b/java/dagger/internal/codegen/AssistedProcessingStep.java
@@ -17,12 +17,14 @@
 package dagger.internal.codegen;
 
 import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
 
 import com.google.auto.common.MoreElements;
 import com.google.common.collect.ImmutableSet;
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.InjectionAnnotations;
+import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
 import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
 import dagger.internal.codegen.validation.ValidationReport;
 import java.lang.annotation.Annotation;
@@ -34,12 +36,17 @@
 
 /** An annotation processor for {@link dagger.assisted.Assisted}-annotated types. */
 final class AssistedProcessingStep extends TypeCheckingProcessingStep<VariableElement> {
+  private final KotlinMetadataUtil kotlinMetadataUtil;
   private final InjectionAnnotations injectionAnnotations;
   private final Messager messager;
 
   @Inject
-  AssistedProcessingStep(InjectionAnnotations injectionAnnotations, Messager messager) {
+  AssistedProcessingStep(
+      KotlinMetadataUtil kotlinMetadataUtil,
+      InjectionAnnotations injectionAnnotations,
+      Messager messager) {
     super(MoreElements::asVariable);
+    this.kotlinMetadataUtil = kotlinMetadataUtil;
     this.injectionAnnotations = injectionAnnotations;
     this.messager = messager;
   }
@@ -59,9 +66,11 @@
     ValidationReport<VariableElement> validate(VariableElement assisted) {
       ValidationReport.Builder<VariableElement> report = ValidationReport.about(assisted);
 
-      Element assistedConstructor = assisted.getEnclosingElement();
-      if (!isAnnotationPresent(assistedConstructor, AssistedInject.class)
-          || assistedConstructor.getKind() != ElementKind.CONSTRUCTOR) {
+      Element enclosingElement = assisted.getEnclosingElement();
+      if (!isAssistedInjectConstructor(enclosingElement)
+              // The generated java stubs for kotlin data classes contain a "copy" method that has
+              // the same parameters (and annotations) as the constructor, so just ignore it.
+              && !isKotlinDataClassCopyMethod(enclosingElement)) {
         report.addError(
             "@Assisted parameters can only be used within an @AssistedInject-annotated "
                 + "constructor.",
@@ -78,4 +87,20 @@
       return report.build();
     }
   }
+
+  private boolean isAssistedInjectConstructor(Element element) {
+    return element.getKind() == ElementKind.CONSTRUCTOR
+        && isAnnotationPresent(element, AssistedInject.class);
+  }
+
+  private boolean isKotlinDataClassCopyMethod(Element element) {
+    // Note: This is a best effort. Technically, we could check the return type and parameters of
+    // the copy method to verify it's the one associated with the constructor, but I'd rather keep
+    // this simple to avoid encoding too many details of kapt's stubs. At worst, we'll be allowing
+    // an @Assisted annotation that has no affect, which is already true for many of Dagger's other
+    // annotations.
+    return element.getKind() == ElementKind.METHOD
+        && element.getSimpleName().contentEquals("copy")
+        && kotlinMetadataUtil.isDataClass(closestEnclosingTypeElement(element));
+  }
 }
diff --git a/java/dagger/internal/codegen/ModuleProcessingStep.java b/java/dagger/internal/codegen/ModuleProcessingStep.java
index d0373b5..2bf3354 100644
--- a/java/dagger/internal/codegen/ModuleProcessingStep.java
+++ b/java/dagger/internal/codegen/ModuleProcessingStep.java
@@ -114,7 +114,7 @@
     // though it's no longer required. However, we skip processing the companion object itself
     // because it will now be processed when processing the companion object's enclosing class.
     if (metadataUtil.isCompanionObjectClass(module)) {
-      // TODO(user): Be strict about annotating companion objects with @Module,
+      // TODO(danysantiago): Be strict about annotating companion objects with @Module,
       //  i.e. tell user to annotate parent instead.
       return;
     }
diff --git a/java/dagger/internal/codegen/binding/InjectionAnnotations.java b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
index 01bfc49..748755e 100644
--- a/java/dagger/internal/codegen/binding/InjectionAnnotations.java
+++ b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
@@ -126,7 +126,7 @@
               membersInjectorNameForType(asType(fieldElement.getEnclosingElement())));
       if (membersInjector != null) {
         String memberInjectedFieldSignature = memberInjectedFieldSignatureForVariable(fieldElement);
-        // TODO(user): We have to iterate over all the injection methods for every qualifier
+        // TODO(danysantiago): We have to iterate over all the injection methods for every qualifier
         //  look up. Making this N^2 when looking through all the injected fields. :(
         return ElementFilter.methodsIn(membersInjector.getEnclosedElements()).stream()
             .filter(
diff --git a/java/dagger/internal/codegen/binding/ModuleDescriptor.java b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
index fea7cec..c471f94 100644
--- a/java/dagger/internal/codegen/binding/ModuleDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
@@ -196,7 +196,7 @@
           // Fallback strategy for de-duping contributing bindings in the companion module with
           // @JvmStatic by comparing descriptors. Contributing bindings are the only valid bindings
           // a companion module can declare. See: https://youtrack.jetbrains.com/issue/KT-35104
-          // TODO(user): Checks qualifiers too.
+          // TODO(danysantiago): Checks qualifiers too.
           .filter(method -> !bindingElementDescriptors.contains(getMethodDescriptor(method)))
           .forEach(
               method -> {
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
index c9bb6c6..296da44 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
@@ -207,7 +207,7 @@
           "Unsupported metadata version. Check that your Kotlin version is >= 1.0");
     }
     if (metadata instanceof KotlinClassMetadata.Class) {
-      // TODO(user): If when we need other types of metadata then move to right method.
+      // TODO(danysantiago): If when we need other types of metadata then move to right method.
       return (KotlinClassMetadata.Class) metadata;
     } else {
       throw new IllegalStateException("Unsupported metadata type: " + metadata);
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
index e82c9f9..76d28f0 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
@@ -20,6 +20,7 @@
 import static com.google.auto.common.MoreElements.isAnnotationPresent;
 import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
 import static kotlinx.metadata.Flag.Class.IS_COMPANION_OBJECT;
+import static kotlinx.metadata.Flag.Class.IS_DATA;
 import static kotlinx.metadata.Flag.Class.IS_OBJECT;
 import static kotlinx.metadata.Flag.IS_PRIVATE;
 
@@ -87,6 +88,12 @@
         && metadataFactory.create(typeElement).classMetadata().flags(IS_OBJECT);
   }
 
+  /** Returns {@code true} if this type element is a Kotlin data class. */
+  public boolean isDataClass(TypeElement typeElement) {
+    return hasMetadata(typeElement)
+        && metadataFactory.create(typeElement).classMetadata().flags(IS_DATA);
+  }
+
   /* Returns {@code true} if this type element is a Kotlin Companion Object. */
   public boolean isCompanionObjectClass(TypeElement typeElement) {
     return hasMetadata(typeElement)
diff --git a/java/dagger/internal/codegen/validation/ModuleValidator.java b/java/dagger/internal/codegen/validation/ModuleValidator.java
index 61f0d0a..02ac06a 100644
--- a/java/dagger/internal/codegen/validation/ModuleValidator.java
+++ b/java/dagger/internal/codegen/validation/ModuleValidator.java
@@ -666,7 +666,7 @@
             companionModuleMethod);
       }
 
-      // TODO(user): Be strict about the usage of @JvmStatic, i.e. tell user to remove it.
+      // TODO(danysantiago): Be strict about the usage of @JvmStatic, i.e. tell user to remove it.
     }
 
     ImmutableListMultimap<Name, ExecutableElement> bindingMethodsByName =
diff --git a/javatests/dagger/functional/assisted/kotlin/BUILD b/javatests/dagger/functional/assisted/kotlin/BUILD
new file mode 100644
index 0000000..3c3421d
--- /dev/null
+++ b/javatests/dagger/functional/assisted/kotlin/BUILD
@@ -0,0 +1,49 @@
+# Copyright (C) 2021 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.
+# Description:
+#   Tests for internal code for implementing Hilt processors.
+
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "SOURCE_7_TARGET_7")
+load("//:test_defs.bzl", "GenJavaTests")
+
+package(default_visibility = ["//:src"])
+
+kt_jvm_library(
+    name = "KotlinAssistedInjectionClasses",
+    srcs = ["KotlinAssistedInjectionClasses.kt"],
+    deps = [
+        "//:dagger_with_compiler",
+    ],
+)
+
+GenJavaTests(
+    name = "kotlin",
+    srcs = glob(
+        ["*.java"],
+        exclude = ["*.kt"],
+    ),
+    javacopts = DOCLINT_HTML_AND_SYNTAX,
+    lib_javacopts = SOURCE_7_TARGET_7,
+    test_only_deps = [
+        "//:dagger_with_compiler",
+        "@google_bazel_common//third_party/java/junit",
+        "@google_bazel_common//third_party/java/truth",
+    ],
+    # NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
+    # used without Guava and jsr305 deps.
+    deps = [
+        ":KotlinAssistedInjectionClasses",
+    ],
+)
diff --git a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt
new file mode 100644
index 0000000..e78873d
--- /dev/null
+++ b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.functional.assisted.kotlin
+
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import javax.inject.Inject
+
+class Dep @Inject constructor()
+
+class AssistedDep
+
+/** Assisted injection for a kotlin class. */
+class Foo @AssistedInject constructor(val dep: Dep, @Assisted val assistedDep: AssistedDep)
+
+/** Assisted injection for a kotlin data class. */
+data class FooData @AssistedInject constructor(val dep: Dep, @Assisted val assistedDep: AssistedDep)
+
+/** Assisted factory for a kotlin class */
+@AssistedFactory
+interface FooFactory {
+  fun create(assistedDep: AssistedDep): Foo
+}
+
+/** Assisted factory for a kotlin data class */
+@AssistedFactory
+interface FooDataFactory {
+  fun create(assistedDep: AssistedDep): FooData
+}
diff --git a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java
new file mode 100644
index 0000000..7c597f8
--- /dev/null
+++ b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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.functional.assisted.kotlin;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Component;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+// This is a regression test for https://github.com/google/dagger/issues/2299
+@RunWith(JUnit4.class)
+public final class KotlinAssistedInjectionTest {
+  @Component
+  interface TestComponent {
+    FooFactory fooFactory();
+
+    FooDataFactory fooDataFactory();
+  }
+
+  @Test
+  public void testFooFactory() {
+    FooFactory fooFactory = DaggerKotlinAssistedInjectionTest_TestComponent.create().fooFactory();
+    AssistedDep assistedDep = new AssistedDep();
+    Foo foo = fooFactory.create(assistedDep);
+    assertThat(foo.getAssistedDep()).isEqualTo(assistedDep);
+  }
+
+  @Test
+  public void testFooDataFactory() {
+    FooDataFactory fooDataFactory =
+        DaggerKotlinAssistedInjectionTest_TestComponent.create().fooDataFactory();
+    AssistedDep assistedDep = new AssistedDep();
+    FooData fooData = fooDataFactory.create(assistedDep);
+    assertThat(fooData.getAssistedDep()).isEqualTo(assistedDep);
+  }
+}
diff --git a/javatests/dagger/functional/kotlin/BUILD b/javatests/dagger/functional/kotlin/BUILD
index c91c962..529eb69 100644
--- a/javatests/dagger/functional/kotlin/BUILD
+++ b/javatests/dagger/functional/kotlin/BUILD
@@ -34,7 +34,7 @@
             "FooWithInjectedQualifier.kt",
         ],
     ),
-    # TODO(user): Remove 'plugins' once kt_jvm_library supports 'exported_plugins'.
+    # TODO(danysantiago): Remove 'plugins' once kt_jvm_library supports 'exported_plugins'.
     plugins = ["//javatests/dagger/functional/kotlin/processor:plugin"],
     deps = [
         ":foo_with_injected_qualifier",
diff --git a/util/run-local-emulator-tests.sh b/util/run-local-emulator-tests.sh
index e0643d0..3842154 100755
--- a/util/run-local-emulator-tests.sh
+++ b/util/run-local-emulator-tests.sh
@@ -64,7 +64,7 @@
 done
 
 # Run emulator tests in a project with configuration cache enabled
-# TODO(user): Once AGP 4.2.0 is stable, remove these project and enable
+# TODO(danysantiago): Once AGP 4.2.0 is stable, remove these project and enable
 # config cache in the other test projects.
 readonly CONFIG_CACHE_PROJECT="javatests/artifacts/hilt-android/gradleConfigCache"
 ./$CONFIG_CACHE_PROJECT/gradlew -p $CONFIG_CACHE_PROJECT connectedAndroidTest --no-daemon --stacktrace --configuration-cache
diff --git a/util/run-local-gradle-android-tests.sh b/util/run-local-gradle-android-tests.sh
index a9cd0f3..ba51078 100755
--- a/util/run-local-gradle-android-tests.sh
+++ b/util/run-local-gradle-android-tests.sh
@@ -16,7 +16,7 @@
 done
 
 # Run gradle tests in a project with configuration cache enabled
-# TODO(user): Once AGP 4.2.0 is stable, remove these project and enable
+# TODO(danysantiago): Once AGP 4.2.0 is stable, remove these project and enable
 # config cache in the other test projects.
 readonly CONFIG_CACHE_PROJECT="javatests/artifacts/hilt-android/gradleConfigCache"
 ./$CONFIG_CACHE_PROJECT/gradlew -p $CONFIG_CACHE_PROJECT assembleDebug --no-daemon --stacktrace --configuration-cache