From d6459e6c49227be11323ce59310407b17005c117 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Fri, 7 Dec 2018 14:42:25 +0300 Subject: [PATCH] Add option to disable AP discovery in compile classpath #KT-24530 Fixed To disable discovery and enable avoidance for kapt tasks, use "kapt.includeCompileClasspath = false" --- .../org/jetbrains/kotlin/gradle/Kapt3IT.kt | 69 +++++++++++++++++++ .../kotlin/gradle/util/stringUtil.kt | 7 +- .../kapt2/kaptAvoidance/app/build.gradle | 13 ++++ .../app/src/main/kotlin/AppClass.kt | 19 +++++ .../kapt2/kaptAvoidance/build.gradle | 17 +++++ .../kapt2/kaptAvoidance/lib/build.gradle | 5 ++ .../lib/src/main/kotlin/LibClass.kt | 11 +++ .../kapt2/kaptAvoidance/settings.gradle | 1 + .../kapt/Kapt3KotlinGradleSubplugin.kt | 4 ++ .../kotlin/gradle/internal/kapt/KaptTask.kt | 31 ++++++++- .../internal/kapt/KaptWithoutKotlincTask.kt | 1 + .../kotlin/gradle/plugin/KaptExtension.kt | 2 + .../kotlin/kapt3/base/KaptOptions.kt | 8 ++- .../kotlin/kapt3/base/ProcessorLoader.kt | 9 ++- plugins/kapt3/kapt3-cli/src/KaptCliOption.kt | 5 ++ .../org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt | 1 + 16 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/src/main/kotlin/AppClass.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/src/main/kotlin/LibClass.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/settings.gradle 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 d7bceddc33c..1173f9cadce 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 @@ -443,6 +443,75 @@ open class Kapt3IT : Kapt3BaseIT() { } } + @Test + fun testDisableDiscoveryInCompileClasspath() = with(Project("kaptAvoidance", directoryPrefix = "kapt2")) { + setupWorkingDir() + val buildGradle = projectDir.resolve("app/build.gradle") + buildGradle.modify { + it.addBeforeSubstring("//", "kapt \"org.jetbrains.kotlin") + } + build("assemble") { + assertSuccessful() + } + + buildGradle.modify { + "$it\n\nkapt.includeCompileClasspath = false" + } + build("assemble") { + assertFailed() + } + } + + + @Test + fun testKaptAvoidance() = with(Project("kaptAvoidance", directoryPrefix = "kapt2")) { + build("assemble") { + assertSuccessful() + assertTasksExecuted( + ":app:kaptGenerateStubsKotlin", + ":app:kaptKotlin", + ":app:compileKotlin", + ":app:compileJava", + ":lib:compileKotlin" + ) + } + + val original = "fun foo() = 0" + val replacement1 = "fun foo() = 1" + val replacement2 = "fun foo() = 2" + val libClassKt = projectDir.getFileByName("LibClass.kt") + libClassKt.modify { it.checkedReplace(original, replacement1) } + + build("assemble") { + assertSuccessful() + assertTasksExecuted( + ":lib:compileKotlin", + ":app:kaptGenerateStubsKotlin", + ":app:kaptKotlin" + ) + } + + // enable discovery + projectDir.resolve("app/build.gradle").modify { + "$it\n\nkapt.includeCompileClasspath = false" + } + build("assemble") { + assertSuccessful() + assertTasksUpToDate(":lib:compileKotlin") + assertTasksExecuted( + ":app:kaptGenerateStubsKotlin", + ":app:kaptKotlin" + ) + } + + libClassKt.modify { it.checkedReplace(replacement1, replacement2) } + build("assemble") { + assertSuccessful() + assertTasksExecuted(":lib:compileKotlin", ":app:kaptGenerateStubsKotlin") + assertTasksUpToDate(":app:kaptKotlin") + } + } + @Test fun testKt19179() { val project = Project("kt19179", directoryPrefix = "kapt2") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/stringUtil.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/stringUtil.kt index 94affd89f0e..dc7f17b456b 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/stringUtil.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/stringUtil.kt @@ -1,4 +1,9 @@ package org.jetbrains.kotlin.gradle.util fun String.addBeforeSubstring(prefix: String, substring: String): String = - replace(substring, prefix + substring) \ No newline at end of file + replace(substring, prefix + substring) + +fun String.checkedReplace(original: String, replacement: String): String { + check(contains(original)) { "Substring '$original' is not found in '$this'" } + return replace(original, replacement) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/build.gradle new file mode 100644 index 00000000000..3bd793424f7 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/build.gradle @@ -0,0 +1,13 @@ +apply plugin: "kotlin" +apply plugin: "kotlin-kapt" + +dependencies { + compile project(":lib") + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + compile "org.jetbrains.kotlin:annotation-processor-example:$kotlin_version" + kapt "org.jetbrains.kotlin:annotation-processor-example:$kotlin_version" + + // actually unused, but kapt skips AP when annotation processing classpath is empty (see checkOptions) + kapt "com.google.auto.service:auto-service:1.0-rc4" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/src/main/kotlin/AppClass.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/src/main/kotlin/AppClass.kt new file mode 100644 index 00000000000..e18b58cd9e5 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/app/src/main/kotlin/AppClass.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package app + +import lib.* + +@example.ExampleAnnotation +class AppClass { + @example.ExampleAnnotation + val testVal: String = "text" + + @example.ExampleAnnotation + fun testFunction(): AppClassGenerated = AppClassGenerated() + + fun useLibClass(libClass: LibClass) = libClass.foo() +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/build.gradle new file mode 100644 index 00000000000..6068289ccdb --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/build.gradle @@ -0,0 +1,17 @@ +buildscript { + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + + +subprojects { + repositories { + mavenLocal() + mavenCentral() + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/build.gradle new file mode 100644 index 00000000000..380c6aac370 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/build.gradle @@ -0,0 +1,5 @@ +apply plugin: "kotlin" + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/src/main/kotlin/LibClass.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/src/main/kotlin/LibClass.kt new file mode 100644 index 00000000000..b793c6c416d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/lib/src/main/kotlin/LibClass.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package lib + +class LibClass { + fun foo() = 0 +} + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/settings.gradle new file mode 100644 index 00000000000..c0b70ce1c99 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kaptAvoidance/settings.gradle @@ -0,0 +1 @@ +include ':app', ':lib' \ No newline at end of file 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 56baa853c67..dfda67feed5 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 @@ -266,6 +266,8 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { pluginOptions += SubpluginOption("javacArguments", encodeList(kaptExtension.getJavacOptions())) + pluginOptions += SubpluginOption("includeCompileClasspath", kaptExtension.includeCompileClasspath.toString()) + addMiscOptions(pluginOptions) return pluginOptions @@ -390,6 +392,8 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { kaptTask.annotationProcessorOptionProviders.add(it) } + kaptTask.includeCompileClasspath = kaptExtension.includeCompileClasspath + if (kaptTask is KaptWithKotlincTask) { buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "apt") } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt index a668cac3f63..54758ac3dcd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt @@ -54,11 +54,35 @@ abstract class KaptTask : ConventionTask() { @get:Nested internal val annotationProcessorOptionProviders: MutableList = mutableListOf() - @get:Classpath - @get:InputFiles + @get:Input + internal var includeCompileClasspath: Boolean = true + + // @Internal because _abiClasspath and _nonAbiClasspath are used for actual checks + @get:Internal val classpath: FileCollection get() = kotlinCompileTask.classpath + @Suppress("unused", "DeprecatedCallableAddReplaceWith") + @Deprecated( + message = "Don't use directly. Used only for up-to-date checks", + level = DeprecationLevel.ERROR + ) + @get:CompileClasspath + @get:InputFiles + internal val internalAbiClasspath: FileCollection + get() = if (includeCompileClasspath) project.files() else kotlinCompileTask.classpath + + + @Suppress("unused", "DeprecatedCallableAddReplaceWith") + @Deprecated( + message = "Don't use directly. Used only for up-to-date checks", + level = DeprecationLevel.ERROR + ) + @get:Classpath + @get:InputFiles + internal val internalNonAbiClasspath: FileCollection + get() = if (includeCompileClasspath) kotlinCompileTask.classpath else project.files() + @get:Internal var useBuildCache: Boolean = false @@ -82,4 +106,7 @@ abstract class KaptTask : ConventionTask() { file.exists() && !FileUtil.isAncestor(destinationDir, file, /* strict = */ false) && !FileUtil.isAncestor(classesDir, file, /* strict = */ false) + + private fun FileCollection?.orEmpty(): FileCollection = + this ?: project.files() } \ No newline at end of file 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 2b3593e700f..caf9f45413d 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 @@ -58,6 +58,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor val kaptFlagsForWorker = mutableSetOf().apply { if (isVerbose) add("VERBOSE") if (mapDiagnosticLocations) add("MAP_DIAGNOSTIC_LOCATIONS") + if (includeCompileClasspath) add("INCLUDE_COMPILE_CLASSPATH") } val optionsForWorker = KaptOptionsForWorker( diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt index e3933dcbf5f..ad32e7c80f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt @@ -37,6 +37,8 @@ open class KaptExtension { open var detectMemoryLeaks: String = "default" + open var includeCompileClasspath: Boolean = true + @Deprecated("Use `annotationProcessor()` and `annotationProcessors()` instead") open var processors: String = "" diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt index 4c35397c6f3..32b7460e3bd 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptOptions.kt @@ -47,7 +47,10 @@ class KaptOptions( val processingOptions: MutableMap = mutableMapOf() val javacOptions: MutableMap = mutableMapOf() - val flags: MutableSet = mutableSetOf(KaptFlag.USE_LIGHT_ANALYSIS) + val flags: MutableSet = mutableSetOf( + KaptFlag.USE_LIGHT_ANALYSIS, + KaptFlag.INCLUDE_COMPILE_CLASSPATH + ) var mode: AptMode = AptMode.WITH_COMPILATION var detectMemoryLeaks: DetectMemoryLeaksMode = DetectMemoryLeaksMode.DEFAULT @@ -88,7 +91,8 @@ enum class KaptFlag(val description: String) { USE_LIGHT_ANALYSIS("Use light analysis"), CORRECT_ERROR_TYPES("Correct error types"), MAP_DIAGNOSTIC_LOCATIONS("Map diagnostic locations"), - STRICT("Strict mode"); + STRICT("Strict mode"), + INCLUDE_COMPILE_CLASSPATH("Detect annotation processors in compile classpath"); } interface KaptSelector { diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt index 4387f601bf4..7a5bea20c65 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/ProcessorLoader.kt @@ -5,10 +5,12 @@ package org.jetbrains.kotlin.kapt3.base +import org.jetbrains.kotlin.base.kapt3.KaptFlag import org.jetbrains.kotlin.base.kapt3.KaptOptions import org.jetbrains.kotlin.kapt3.base.util.KaptLogger import org.jetbrains.kotlin.kapt3.base.util.info import java.io.Closeable +import java.io.File import java.lang.reflect.Field import java.lang.reflect.Modifier import java.net.URLClassLoader @@ -23,7 +25,12 @@ open class ProcessorLoader(private val options: KaptOptions, private val logger: fun loadProcessors(parentClassLoader: ClassLoader = ClassLoader.getSystemClassLoader()): LoadedProcessors { clearJarURLCache() - val classpath = (options.processingClasspath + options.compileClasspath).distinct() + val classpath = LinkedHashSet().apply { + addAll(options.processingClasspath) + if (options[KaptFlag.INCLUDE_COMPILE_CLASSPATH]) { + addAll(options.compileClasspath) + } + } val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), parentClassLoader) this.annotationProcessingClassLoader = classLoader diff --git a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt index 40c2233fcfc..aa1bf735bb4 100644 --- a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt +++ b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt @@ -149,6 +149,11 @@ enum class KaptCliOption( ), DETECT_MEMORY_LEAKS_OPTION("detectMemoryLeaks", "true | false", "Detect memory leaks in annotation processors"), + INCLUDE_COMPILE_CLASSPATH( + "includeCompileClasspath", + "true | false", + "Discover annotation processors in compile classpath" + ), INFO_AS_WARNINGS_OPTION("infoAsWarnings", "true | false", "Show information messages as warnings"), diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt index 72fc58d160c..b4a5372cfb2 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt @@ -109,6 +109,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor { INFO_AS_WARNINGS_OPTION -> setFlag(KaptFlag.INFO_AS_WARNINGS, value) STRICT_MODE_OPTION -> setFlag(KaptFlag.STRICT, value) SHOW_PROCESSOR_TIMINGS -> setFlag(KaptFlag.SHOW_PROCESSOR_TIMINGS, value) + INCLUDE_COMPILE_CLASSPATH -> setFlag(KaptFlag.INCLUDE_COMPILE_CLASSPATH, value) DETECT_MEMORY_LEAKS_OPTION -> setSelector(enumValues(), value) { detectMemoryLeaks = it } APT_MODE_OPTION -> setSelector(enumValues(), value) { mode = it }