diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/KotlinAndroidMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/KotlinAndroidMppIT.kt index 0c218282a70..423a8776d7e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/KotlinAndroidMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/KotlinAndroidMppIT.kt @@ -961,4 +961,58 @@ class KotlinAndroidMppIT : KGPBaseTest() { } } + @DisplayName("KT-63753: K2 File \"does not belong to any module\" when it is generated by `registerJavaGeneratingTask` in AGP") + @GradleAndroidTest + fun sourceGenerationTaskAddedToAndroidVariant( + gradleVersion: GradleVersion, + agpVersion: String, + jdkVersion: JdkVersions.ProvidedJdk + ) { + project( + "new-mpp-android", gradleVersion, + defaultBuildOptions.copy(androidVersion = agpVersion), + buildJdk = jdkVersion.location + ) { + // Hacks for TODO: KT-65426 + val appPath = subProject("app").projectPath + appPath.resolve("src/main/java/app/example/com/app_sample").deleteRecursively() + appPath.resolve("src/commonMain/kotlin/A.kt").replaceText("expect fun f(): Unit", "") + + // Code copied from the reproducer from KT-63753 + subProject("app").buildGradleKts.appendText( + """ + + abstract class FileGeneratingTask : DefaultTask() { + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + @TaskAction + fun taskAction() { + val outputDirFile = outputDir.asFile.get() + outputDirFile.mkdirs() + val file = File(outputDirFile, "Test.kt") + val text = ""${'"'} + val hello = "World!" + ""${'"'} + file.writeText(text) + } + } + + android { + applicationVariants.configureEach { + val variant = this + val outputDir = File(buildDir, "generateExternalFile/${'$'}{variant.dirName}") + val task = project.tasks.register("generateExternalFile${'$'}{variant.name.capitalize()}", FileGeneratingTask::class.java) { + this.outputDir.set(outputDir) + } + variant.registerJavaGeneratingTask(task, outputDir) + } + } + """.trimIndent() + ) + build(":app:compileDebugKotlinAndroidApp") { + assertTasksExecuted(":app:compileDebugKotlinAndroidApp") + } + } + } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt index 4b433e947c9..2e72781f3b8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt @@ -231,10 +231,12 @@ internal class AndroidProjectHandler( val javaTask = variantData.javaCompileProvider @Suppress("UNCHECKED_CAST") val kotlinTask = compilation.compileTaskProvider as TaskProvider compilation.androidVariant.forEachJavaSourceDir { sources -> - kotlinTask.configure { - it.setSource(sources.dir) - it.dependsOn(sources) - } + // It is important to pass exactly `sources.dir` as provider with explicit task dependency + // Because of the following bugs: + // * https://github.com/gradle/gradle/issues/27881 ConfigurableFileTree.from() doesn't preserve Task Dependencies + // * https://github.com/gradle/gradle/issues/27882 SourceDirectorySet doesn't accept ConfigurableFileTree + val sourceDirWithTaskDependencies = project.filesProvider(sources) { sources.dir } + compilation.defaultSourceSet.kotlin.srcDir(sourceDirWithTaskDependencies) } wireKotlinTasks(project, compilation, androidPlugin, androidExt, variantData, javaTask, kotlinTask) }