From 19708cfa8708bc36da17601f13fe9921d7a380ef Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Wed, 24 Mar 2021 18:20:25 +0000 Subject: [PATCH] KAPT: Avoid evaluating apOptions from AGP too early This is causing issues such as https://issuetracker.google.com/183423660. Annotation processor options that are provided by the Android Gradle plugin may contain references to files and file collections that are safe to evaluate only at execution time. This change avoids eagerly creating compiler plugin options for these options, as they are already a task input. Test: AbstractKotlinAndroidGradleTests.testAgpNestedArgsNotEvaluatedDuringConfiguration ^KT-39715 In Progress --- .../AbstractKotlinAndroidGradleTests.kt | 36 ++++++++++ .../kapt/Kapt3KotlinGradleSubplugin.kt | 72 ++++++++++--------- .../internal/kapt/KaptWithoutKotlincTask.kt | 9 +++ 3 files changed, 85 insertions(+), 32 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt index fc5bd0ef765..82dbae6bc51 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt @@ -521,6 +521,42 @@ open class KotlinAndroid34GradleIT : KotlinAndroid3GradleIT() { } } + @Test + fun testAgpNestedArgsNotEvaluatedDuringConfiguration() = with(Project("AndroidProject")) { + setupWorkingDir() + + gradleBuildScript(subproject = "Android").appendText( + """ + + apply plugin: 'kotlin-kapt' + + class MyNested implements org.gradle.process.CommandLineArgumentProvider { + @Override + Iterable asArguments() { + throw new RuntimeException("This should not be invoked during configuration.") + } + } + + def nested = new MyNested() + + android.applicationVariants.all { + it.javaCompileOptions.annotationProcessorOptions.compilerArgumentProviders.add(nested) + } + """.trimIndent() + ) + + build(":Android:kaptFlavor1DebugKotlin", "--dry-run") { + assertSuccessful() + } + + build( + ":Android:kaptFlavor1DebugKotlin", "--dry-run", + options = defaultBuildOptions().copy(kaptOptions = KaptOptions(verbose = false, useWorkers = false)) + ) { + assertSuccessful() + } + } + @Test fun testOmittedStdlibVersion() = Project("AndroidProject").run { setupWorkingDir() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 18dc98db610..13f6f46881f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -324,13 +324,10 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To pluginOptions += SubpluginOption("processors", annotationProcessors) } - val apOptions = getAPOptions().get() - - pluginOptions += CompositeSubpluginOption( - "apoptions", - lazy { encodeList(apOptions.associate { it.key to it.value }) }, - apOptions - ) + if (aptMode == "apt") { + // apOptions are needed only for "apt" mode + pluginOptions += getAPOptions().get() + } pluginOptions += SubpluginOption("javacArguments", encodeList(javacOptions.get())) @@ -342,35 +339,46 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To } } - private fun Kapt3SubpluginContext.getAPOptions(): Provider> = project.provider { + private fun Kapt3SubpluginContext.getAPOptions(): Provider = project.provider { val androidVariantData = KaptWithAndroid.androidVariantData(this) - val androidPlugin = androidVariantData?.let { + val androidOptions = androidVariantData?.annotationProcessorOptions ?: emptyMap() + val annotationProcessorProviders = androidVariantData?.annotationProcessorOptionProviders + + val subluginOptionsFromProvidedApOptions = lazy { + val apOptionsFromProviders = + annotationProcessorProviders?.flatMap { + (it as CommandLineArgumentProvider).asArguments() + }.orEmpty() + + apOptionsFromProviders.map { + // Use the internal subplugin option type to exclude them from Gradle input/output checks, as their providers are already + // properly registered as a nested input: + + // Pass options as they are in the key-only form (key = 'a=b'), kapt will deal with them: + InternalSubpluginOption(key = it.removePrefix("-A"), value = "") + } + } + + val nonAndroidOptions = androidOptions.toList().map { SubpluginOption(it.first, it.second) } + getKaptApOptions().get() + + CompositeSubpluginOption( + "apoptions", + lazy { encodeList((nonAndroidOptions + subluginOptionsFromProvidedApOptions.value).associate { it.key to it.value }) }, + nonAndroidOptions + ) + } + + private fun Kapt3SubpluginContext.getKaptApOptions(): Provider> = project.provider { + val androidVariantData = KaptWithAndroid.androidVariantData(this) + + val androidExtension = androidVariantData?.let { project.extensions.findByName("android") as? BaseExtension } - val androidOptions = androidVariantData?.annotationProcessorOptions ?: emptyMap() - - val apOptionsFromProviders = - androidVariantData?.annotationProcessorOptionProviders - ?.flatMap { (it as CommandLineArgumentProvider).asArguments() } - .orEmpty() - - val subluginOptionsFromProvidedApOptions = apOptionsFromProviders.map { - // Use the internal subplugin option type to exclude them from Gradle input/output checks, as their providers are already - // properly registered as a nested input: - - // Pass options as they are in the key-only form (key = 'a=b'), kapt will deal with them: - InternalSubpluginOption(key = it.removePrefix("-A"), value = "") - } - - val apOptionsPairsList: List> = - kaptExtension.getAdditionalArguments(project, androidVariantData, androidPlugin).toList() + - androidOptions.toList() - - apOptionsPairsList.map { SubpluginOption(it.first, it.second) } + - FilesSubpluginOption(KAPT_KOTLIN_GENERATED, listOf(kotlinSourcesOutputDir)) + - subluginOptionsFromProvidedApOptions + kaptExtension.getAdditionalArguments(project, androidVariantData, androidExtension).toList() + .map { SubpluginOption(it.first, it.second) } + + FilesSubpluginOption(KAPT_KOTLIN_GENERATED, listOf(kotlinSourcesOutputDir)) } private fun Kapt3SubpluginContext.registerSubpluginOptions( @@ -563,7 +571,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To it.javacOptions = dslJavacOptions.get() } - val subpluginOptions = getAPOptions() + val subpluginOptions = getKaptApOptions() registerSubpluginOptions(kaptTaskProvider, subpluginOptions) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt index 01b9932d0fa..ed4d4923856 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt @@ -11,6 +11,7 @@ import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs +import org.gradle.process.CommandLineArgumentProvider import org.gradle.workers.IsolationMode import org.gradle.workers.WorkAction import org.gradle.workers.WorkParameters @@ -74,6 +75,14 @@ abstract class KaptWithoutKotlincTask @Inject constructor( for (option in options) { result[option.key] = option.value } + annotationProcessorOptionProviders.forEach { + (it as List).forEach { + (it as CommandLineArgumentProvider).asArguments().forEach { + result[it.removePrefix("-A")] = "" + } + } + } + return result }