From 59f544cb7c5c32a1ad6b317c8b969a24cc767c12 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Mon, 13 Nov 2023 17:52:43 +0100 Subject: [PATCH] [Gradle, Kapt] Don't immediately check if kaptClasspath dependencies are empty Now sub-plugins are applied to compilation before users `afterEvaluate` closure execution, which could lead to unexpected by the user state. For example, when a user adds dependencies to 'kaptClasspath' in 'afterEvaluate'. This fix removes check in Kapt plugin if dependencies are present on 'kaptClasspath' and moves it into KaptTask.onlyIf spec. So the task will still have SKIPPED state if there are no AP provided. ^KT-63366 Fixed --- .../org/jetbrains/kotlin/gradle/Kapt3IT.kt | 27 +++++++++++++++++++ .../org/jetbrains/kotlin/gradle/UpToDateIT.kt | 15 +++++++---- .../kotlin/gradle/android/Kapt3AndroidIT.kt | 4 +++ .../kapt/Kapt3KotlinGradleSubplugin.kt | 12 ++++++--- .../internal/kapt/KaptWithoutKotlincTask.kt | 19 ++++++++----- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt index 1085f767037..04f1fc6c0b2 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt @@ -155,6 +155,33 @@ open class Kapt3IT : Kapt3BaseIT() { project("kaptSkipped".withPrefix, gradleVersion, enableKotlinDaemonMemoryLimitInMb = 2048) { build("build") { assertTasksSkipped(":kaptGenerateStubsKotlin", ":kaptKotlin") + assertOutputContains("No annotation processors provided. Skip KAPT processing.") + } + } + } + + @DisplayName("KT-63366: Adding kapt AP dependency in afterEvaluate for custom SourceSet") + @GradleTest + fun testKaptCustomSourceSetDependencyAfterEvaluate(gradleVersion: GradleVersion) { + project("simple".withPrefix, gradleVersion) { + buildGradle.appendText( + //language=groovy + """ + | + |sourceSets.create("custom") + | + |afterEvaluate { + | configurations.getByName("kaptCustom").dependencies.add( + | dependencies.create("org.jetbrains.kotlin:annotation-processor-example") + | ) + |} + """.trimMargin() + ) + + build(":kaptCustomKotlin", forceOutput = true) { + assertTasksExecuted(":kaptCustomKotlin") + assertOutputDoesNotContain("No annotation processors provided. Skip KAPT processing.") + assertOutputContains("Annotation processors: example.ExampleAnnotationProcessor, example.KotlinFilerGeneratingProcessor") } } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt index 69df1732280..0469b059035 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt @@ -179,11 +179,16 @@ class UpToDateIT : KGPBaseTest() { override fun initProject(project: TestProject) = with(project) { buildGradle.appendText( - "\n" + """ - apply plugin: 'kotlin-kapt' - plugins.apply("org.jetbrains.kotlin.plugin.allopen") - allOpen { annotation("allopen.Foo"); annotation("allopen.Bar") } - """.trimIndent() + """ + | + |apply plugin: 'kotlin-kapt' + |plugins.apply("org.jetbrains.kotlin.plugin.allopen") + |allOpen { annotation("allopen.Foo"); annotation("allopen.Bar") } + | + |dependencies { + | kapt 'org.jetbrains.kotlin:annotation-processor-example' + |} + """.trimMargin() ) } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt index 59113793049..df1e326199a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt @@ -225,6 +225,10 @@ open class Kapt3AndroidIT : Kapt3BaseIT() { android.applicationVariants.all { it.javaCompileOptions.annotationProcessorOptions.compilerArgumentProviders.add(nested) } + + dependencies { + kapt 'org.jetbrains.kotlin:annotation-processor-example' + } """.trimIndent() ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 73d203d5a6c..a78d3a6872e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -277,13 +277,16 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To val kaptExtension = project.extensions.getByType(KaptExtension::class.java) - val nonEmptyKaptConfigurations = kaptConfigurations.filter { it.allDependencies.isNotEmpty() } - val javaCompileOrNull = findJavaTaskForKotlinCompilation(kotlinCompilation) val context = Kapt3SubpluginContext( - project, javaCompileOrNull, - androidVariantData, sourceSetName, kotlinCompilation, kaptExtension, nonEmptyKaptConfigurations + project, + javaCompileOrNull, + androidVariantData, + sourceSetName, + kotlinCompilation, + kaptExtension, + kaptConfigurations, ) val kaptGenerateStubsTaskProvider: TaskProvider = context.createKaptGenerateStubsTask() @@ -369,6 +372,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To .setExtendsFrom(kaptClasspathConfigurations).also { it.isVisible = false it.isCanBeConsumed = false + it.isCanBeResolved = true } taskConfigAction.configureTaskProvider { taskProvider -> taskProvider.dependsOn(generateStubsTask) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt index 840751e097e..d004e820300 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.internal +import org.gradle.api.Task import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileCollection import org.gradle.api.model.ObjectFactory @@ -12,6 +13,7 @@ import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.ProviderFactory +import org.gradle.api.specs.Spec import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal @@ -64,6 +66,17 @@ abstract class KaptWithoutKotlincTask @Inject constructor( @get:Input val kaptProcessJvmArgs: ListProperty = objectFactory.listPropertyWithConvention(emptyList()) + init { + // Skip annotation processing if no annotation processors were provided. + onlyIf { task -> + with(task as KaptWithoutKotlincTask) { + val isRunTask = !(annotationProcessorFqNames.get().isEmpty() && kaptClasspath.isEmpty()) + if (!isRunTask) task.logger.info("No annotation processors provided. Skip KAPT processing.") + isRunTask + } + } + } + private fun getAnnotationProcessorOptions(): Map { val result = mutableMapOf() kaptPluginOptions.toSingleCompilerPluginOptions().subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID]?.forEach { @@ -133,12 +146,6 @@ abstract class KaptWithoutKotlincTask @Inject constructor( disableClassloaderCacheForProcessors ) - // Skip annotation processing if no annotation processors were provided. - if (annotationProcessorFqNames.get().isEmpty() && kaptClasspath.isEmpty()) { - logger.info("No annotation processors provided. Skip KAPT processing.") - return - } - val kaptClasspath = kaptJars val isolationMode = getWorkerIsolationMode() logger.info("Using workers $isolationMode isolation mode to run kapt")