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 63df267f761..02ef08a541b 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 @@ -121,6 +121,10 @@ open class Kapt3ClassLoadersCacheIT : Kapt3IT() { override fun testMultipleProcessingPasses(gradleVersion: GradleVersion) { } + @Disabled("classloaders cache is leaking file descriptors that prevents cleaning test project") + override fun useK2KaptProperty(gradleVersion: GradleVersion) { + } + override fun testAnnotationProcessorAsFqName(gradleVersion: GradleVersion) { project("annotationProcessorAsFqName".withPrefix, gradleVersion) { //classloaders caching is not compatible with includeCompileClasspath @@ -1268,6 +1272,41 @@ open class Kapt3IT : Kapt3BaseIT() { } } + @DisplayName("K2 Kapt can be enabled via Gradle property kapt.use.k2") + @GradleTest + open fun useK2KaptProperty(gradleVersion: GradleVersion) { + project("simple".withPrefix, gradleVersion) { + buildGradle.appendText( + """ + |tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { + | compilerOptions { + | freeCompilerArgs.addAll([ + | "-Xuse-fir-ic", + | "-Xuse-fir-lt" + | ]) + | } + | kotlinOptions { + | languageVersion = "2.0" + | } + |} + | + |compileKotlin.kotlinOptions.allWarningsAsErrors = false + """.trimMargin() + ) + build("-Pkapt.use.k2=true", "build") { + assertKaptSuccessful() + assertTasksExecuted(":kaptGenerateStubsKotlin", ":kaptKotlin", ":compileKotlin") + assertOutputDoesNotContain("Falling back to 1.9.") + assertOutputContains("Kapt 4 is an experimental feature. Use with caution.") + } + build("-Pkapt.use.k2=true", "cleanCompileKotlin", "compileKotlin") { + assertTasksExecuted(":compileKotlin") + // The warning should not be displayed for the compile task. + assertOutputDoesNotContain("Kapt 4 is an experimental feature. Use with caution.") + } + } + } + @DisplayName("Kapt-generated Kotlin sources can be used in Kotlin") @GradleTest open fun useGeneratedKotlinSource(gradleVersion: GradleVersion) { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt index e6aa8a8d4b0..7013a9fdc6e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt @@ -36,6 +36,9 @@ class Kapt4IT : Kapt3IT() { @Disabled("Doesn't make sense in Kapt 4") override fun fallBackModeWithLanguageVersion2_0(gradleVersion: GradleVersion) {} + @Disabled("Doesn't make sense in Kapt 4") + override fun useK2KaptProperty(gradleVersion: GradleVersion) {} + @Disabled("Doesn't make sense in Kapt 4") override fun testRepeatableAnnotationsWithOldJvmBackend(gradleVersion: GradleVersion) {} 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 854d03fd760..5eee67a75f5 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 @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isInf import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptKeepKdocCommentsInStubs import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptVerbose import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isUseJvmIr +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isUseK2 import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation @@ -109,6 +110,10 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To return getBooleanOptionValue(BooleanOption.KAPT_USE_JVM_IR) } + fun Project.isUseK2(): Boolean { + return getBooleanOptionValue(BooleanOption.KAPT_USE_K2) + } + fun Project.classLoadersCacheSize(): Int = findPropertySafe(CLASSLOADERS_CACHE_SIZE)?.toString()?.toInt() ?: 0 fun Project.disableClassloaderCacheForProcessors(): Set { @@ -203,6 +208,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To KAPT_INCLUDE_COMPILE_CLASSPATH("kapt.include.compile.classpath", true), KAPT_KEEP_KDOC_COMMENTS_IN_STUBS("kapt.keep.kdoc.comments.in.stubs", true), KAPT_USE_JVM_IR("kapt.use.jvm.ir", true), + KAPT_USE_K2("kapt.use.k2", false), } } @@ -546,6 +552,7 @@ internal fun buildKaptSubpluginOptions( pluginOptions += SubpluginOption("showProcessorTimings", "${kaptExtension.showProcessorStats}") pluginOptions += SubpluginOption("detectMemoryLeaks", kaptExtension.detectMemoryLeaks) pluginOptions += SubpluginOption("useJvmIr", "${project.isUseJvmIr()}") + pluginOptions += SubpluginOption("useK2", "${project.isUseK2()}") pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}") pluginOptions += FilesSubpluginOption("stubs", kaptStubsDir) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt index c5165198002..8e60e6d64fc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt @@ -17,9 +17,10 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.Project -import org.gradle.api.file.* -import org.gradle.api.model.ObjectFactory import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.FileCollection +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.work.Incremental @@ -65,6 +66,9 @@ abstract class KaptGenerateStubsTask @Inject constructor( @get:Input abstract val verbose: Property + @get:Input + abstract val useK2Kapt: Property + /** * Changes in this additional sources will trigger stubs regeneration, * but the sources themselves will not be used to find kapt annotations and generate stubs. @@ -125,6 +129,10 @@ abstract class KaptGenerateStubsTask @Inject constructor( args.verbose = verbose.get() args.destinationAsFile = destinationDirectory.get().asFile + + if (useK2Kapt.get()) { + args.freeArgs += "-Xuse-kapt4" + } } pluginClasspath { args -> diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt index e525891fe89..3571ec8e92c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_SUBPLUGIN_ID import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isIncludeCompileClasspath +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isUseK2 import org.jetbrains.kotlin.gradle.plugin.KaptExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo @@ -49,6 +50,7 @@ internal class KaptGenerateStubsConfig : BaseKotlinCompileConfig task.verbose.set(KaptTask.queryKaptVerboseProperty(project)) task.pluginOptions.add(buildOptions(kaptExtension, task)) + task.useK2Kapt.value(project.isUseK2()).finalizeValueOnRead() if (!isIncludeCompileClasspath(kaptExtension)) { task.onlyIf { 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 aee74300072..7d594e30e56 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 @@ -129,7 +129,8 @@ enum class KaptFlag(val description: String, val defaultValue: Boolean = false) INCREMENTAL_APT("Incremental annotation processing (apt mode)"), STRIP_METADATA("Strip @Metadata annotations from stubs"), KEEP_KDOC_COMMENTS_IN_STUBS("Keep KDoc comments in stubs", defaultValue = true), - USE_JVM_IR("Use JVM IR backend", defaultValue = true) + USE_JVM_IR("Use JVM IR backend", defaultValue = true), + USE_K2("Use K2"), ; } diff --git a/plugins/kapt3/kapt3-cli/src/KaptCli.kt b/plugins/kapt3/kapt3-cli/src/KaptCli.kt index f98003bc184..8c8475d374a 100644 --- a/plugins/kapt3/kapt3-cli/src/KaptCli.kt +++ b/plugins/kapt3/kapt3-cli/src/KaptCli.kt @@ -107,6 +107,7 @@ private fun transformKaptToolArgs(args: List, messageCollector: MessageC } KaptCliOption.APT_MODE_OPTION -> aptModePassed = true KaptCliOption.VERBOSE_MODE_OPTION -> kaptVerboseModePassed = true + KaptCliOption.USE_K2 -> transformed.add("-Xuse-kapt4") else -> {} } diff --git a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt index 0ae443685fe..dec365e5e2e 100644 --- a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt +++ b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt @@ -221,6 +221,13 @@ enum class KaptCliOption( cliToolOption = CliToolOption("-Kapt-use-jvm-ir", FLAG) ), + USE_K2( + "useK2", + "true | false", + "Use K2", + cliToolOption = CliToolOption("-Kapt-use-k2", FLAG) + ), + DETECT_MEMORY_LEAKS_OPTION("detectMemoryLeaks", "true | false", "Detect memory leaks in annotation processors"), INCLUDE_COMPILE_CLASSPATH( "includeCompileClasspath", diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kaptUseK2Flag/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kaptUseK2Flag/build.txt new file mode 100644 index 00000000000..14d960b098e --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kaptUseK2Flag/build.txt @@ -0,0 +1,11 @@ +# kapt +-language-version 2.0 +-Xsuppress-version-warnings +-Kapt-use-k2=true +-Kapt-mode=compile +../simple/Test.kt + +# after +Return code: 1 + +error: [kapt] KAPT "compile" mode is not supported in Kotlin 2.x. Run kapt with -Kapt-mode=stubsAndApt and use kotlinc for the final compilation step. diff --git a/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java b/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java index de71457a3b9..a658ded4457 100644 --- a/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java +++ b/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java @@ -48,6 +48,12 @@ public class Kapt4ToolIntegrationTestGenerated extends AbstractKapt4ToolIntegrat runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/"); } + @Test + @TestMetadata("kaptUseK2Flag") + public void testKaptUseK2Flag() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/kaptUseK2Flag/"); + } + @Test @TestMetadata("kotlinFileGeneration") public void testKotlinFileGeneration() throws Exception { 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 7287c64ae49..2a9357edaa9 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 @@ -125,6 +125,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor { STRIP_METADATA_OPTION -> setFlag(KaptFlag.STRIP_METADATA, value) KEEP_KDOC_COMMENTS_IN_STUBS -> setFlag(KaptFlag.KEEP_KDOC_COMMENTS_IN_STUBS, value) USE_JVM_IR -> setFlag(KaptFlag.USE_JVM_IR, value) + USE_K2 -> setFlag(KaptFlag.USE_K2, value) SHOW_PROCESSOR_STATS -> setFlag(KaptFlag.SHOW_PROCESSOR_STATS, value) DUMP_PROCESSOR_STATS -> processorsStatsReportFile = File(value) @@ -171,11 +172,13 @@ class Kapt3ComponentRegistrar : ComponentRegistrar { get() = false override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) { - if (configuration.getBoolean(USE_FIR)) return + val optionsBuilder = (configuration[KAPT_OPTIONS] ?: KaptOptions.Builder()) + if (configuration.getBoolean(USE_FIR) || KaptFlag.USE_K2 in optionsBuilder.flags) return + doOpenInternalPackagesIfRequired() val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList() - val optionsBuilder = (configuration[KAPT_OPTIONS] ?: KaptOptions.Builder()).apply { + optionsBuilder.apply { projectBaseDir = project.basePath?.let(::File) compileClasspath.addAll(contentRoots.filterIsInstance().map { it.file }) javaSourceRoots.addAll(contentRoots.filterIsInstance().map { it.file }) diff --git a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt index a220ae4481d..ec7334e3167 100644 --- a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt +++ b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt @@ -31,8 +31,10 @@ import org.jetbrains.kotlin.psi.KtFile import java.io.File private class Kapt4AnalysisHandlerExtension : FirAnalysisHandlerExtension() { - override fun isApplicable(configuration: CompilerConfiguration): Boolean = - configuration.getBoolean(USE_FIR) && configuration[KAPT_OPTIONS] != null + override fun isApplicable(configuration: CompilerConfiguration): Boolean { + val options = configuration[KAPT_OPTIONS] + return options != null && (configuration.getBoolean(USE_FIR) || KaptFlag.USE_K2 in options.flags) + } @OptIn(KtAnalysisApiInternals::class) override fun doAnalysis(configuration: CompilerConfiguration): Boolean { @@ -187,4 +189,4 @@ class Kapt4CompilerPluginRegistrar : CompilerPluginRegistrar() { FirAnalysisHandlerExtension.registerExtension(Kapt4AnalysisHandlerExtension()) } } -} \ No newline at end of file +}