From 7e9d7c895a482a502e75cff63956396d67d1cf24 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 31 May 2022 14:39:44 +0200 Subject: [PATCH] Kapt: add flag kapt.use.jvm.ir for enabling JVM IR support #KT-49682 --- .../kotlin/config/JVMConfigurationKeys.java | 5 -- .../kotlin/backend/jvm/JvmIrCodegenFactory.kt | 5 +- .../kotlin/codegen/GenerationUtils.kt | 3 +- .../kapt/Kapt3KotlinGradleSubplugin.kt | 9 ++- .../kotlin/kapt3/base/KaptOptions.kt | 1 + plugins/kapt3/kapt3-cli/src/KaptCliOption.kt | 7 ++ .../jetbrains/kotlin/kapt3/Kapt3Extension.kt | 19 +++-- .../org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt | 2 + .../AbstractKotlinKapt3IntegrationTest.kt | 2 +- .../kapt3/test/AbstractKotlinKapt3Test.kt | 20 +---- .../test/IrKotlinKapt3IntegrationTests.kt | 1 - .../kotlin/kapt3/test/KotlinKapt3TestBase.kt | 30 +++++++- .../testData/kotlinRunner/Simple.it_ir.txt | 73 +++++++++++++++++++ 13 files changed, 133 insertions(+), 44 deletions(-) create mode 100644 plugins/kapt3/kapt3-compiler/testData/kotlinRunner/Simple.it_ir.txt diff --git a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index 7e6831de92d..e6a5dd6e627 100644 --- a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -85,11 +85,6 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey IR = CompilerConfigurationKey.create("IR"); - // Temporary option to make it possible to test kapt with JVM IR. As soon as all tests start to pass, it can be removed, - // and the backend (old or IR) will be deduced from the compiler arguments provided by the user. - public static final CompilerConfigurationKey USE_KAPT_WITH_JVM_IR = - CompilerConfigurationKey.create("Enable JVM IR for kapt"); - public static final CompilerConfigurationKey USE_PSI_CLASS_FILES_READING = CompilerConfigurationKey.create("use a slower (PSI-based) class files reading implementation"); diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt index 49b9579f6fd..5c4ffb6ef93 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt @@ -203,10 +203,7 @@ open class JvmIrCodegenFactory( // We need to compile all files we reference in Klibs irModuleFragment.files.addAll(dependencies.flatMap { it.files }) - if (!input.configuration.getBoolean(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT) && !input.configuration.getBoolean( - JVMConfigurationKeys.USE_KAPT_WITH_JVM_IR - ) - ) { + if (!input.configuration.getBoolean(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT)) { val originalBindingContext = input.bindingContext as? CleanableBindingContext ?: error("BindingContext should be cleanable in JVM IR to avoid leaking memory: ${input.bindingContext}") originalBindingContext.clear() diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt index 55997ad6507..9c5485780ae 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt @@ -187,8 +187,7 @@ object GenerationUtils { configureGenerationState: GenerationState.Builder.() -> Unit = {}, ): GenerationState { val isIrBackend = - (classBuilderFactory.classBuilderMode == ClassBuilderMode.FULL && configuration.getBoolean(JVMConfigurationKeys.IR)) || - configuration.getBoolean(JVMConfigurationKeys.USE_KAPT_WITH_JVM_IR) + configuration.getBoolean(JVMConfigurationKeys.IR) val generationState = GenerationState.Builder( project, classBuilderFactory, analysisResult.moduleDescriptor, analysisResult.bindingContext, configuration 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 d0aecf4554d..0a1c4ee9048 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 @@ -24,6 +24,7 @@ import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isInfoAsWarnings 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.model.builder.KaptModelBuilder import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation @@ -119,6 +120,10 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To return getBooleanOptionValue(BooleanOption.KAPT_KEEP_KDOC_COMMENTS_IN_STUBS) } + fun Project.isUseJvmIr(): Boolean { + return getBooleanOptionValue(BooleanOption.KAPT_USE_JVM_IR) + } + fun Project.classLoadersCacheSize(): Int = findPropertySafe(CLASSLOADERS_CACHE_SIZE)?.toString()?.toInt() ?: 0 fun Project.disableClassloaderCacheForProcessors(): Set { @@ -219,7 +224,8 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To ), KAPT_INFO_AS_WARNINGS("kapt.info.as.warnings", false), KAPT_INCLUDE_COMPILE_CLASSPATH("kapt.include.compile.classpath", true), - KAPT_KEEP_KDOC_COMMENTS_IN_STUBS("kapt.keep.kdoc.comments.in.stubs", true) + KAPT_KEEP_KDOC_COMMENTS_IN_STUBS("kapt.keep.kdoc.comments.in.stubs", true), + KAPT_USE_JVM_IR("kapt.use.jvm.ir", false), } } @@ -573,6 +579,7 @@ internal fun buildKaptSubpluginOptions( pluginOptions += SubpluginOption("keepKdocCommentsInStubs", "${project.isKaptKeepKdocCommentsInStubs()}") pluginOptions += SubpluginOption("showProcessorTimings", "${kaptExtension.showProcessorStats}") pluginOptions += SubpluginOption("detectMemoryLeaks", kaptExtension.detectMemoryLeaks) + pluginOptions += SubpluginOption("useJvmIr", "${project.isUseJvmIr()}") pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}") pluginOptions += FilesSubpluginOption("stubs", kaptStubsDir) 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 d0943c139c3..b460230f0e7 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 @@ -126,6 +126,7 @@ 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") ; } diff --git a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt index bb5b7326900..140ef755f94 100644 --- a/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt +++ b/plugins/kapt3/kapt3-cli/src/KaptCliOption.kt @@ -207,6 +207,13 @@ enum class KaptCliOption( "Keep KDoc comments in stubs" ), + USE_JVM_IR( + "useJvmIr", + "true | false", + "Use JVM IR backend", + cliToolOption = CliToolOption("-Kapt-use-jvm-ir", FLAG) + ), + DETECT_MEMORY_LEAKS_OPTION("detectMemoryLeaks", "true | false", "Detect memory leaks in annotation processors"), INCLUDE_COMPILE_CLASSPATH( "includeCompileClasspath", diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index 2c467db9df9..c52f8c37aa4 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -262,19 +262,18 @@ abstract class AbstractKapt3Extension( ): KaptContextForStubGeneration { val builderFactory = OriginCollectingClassBuilderFactory(ClassBuilderMode.KAPT3) + val configuration = compilerConfiguration.copy().apply { + put(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT, true) + } + val targetId = TargetId( - name = compilerConfiguration[CommonConfigurationKeys.MODULE_NAME] ?: module.name.asString(), + name = configuration[CommonConfigurationKeys.MODULE_NAME] ?: module.name.asString(), type = "java-production" ) - val isIrBackend = compilerConfiguration.getBoolean(JVMConfigurationKeys.USE_KAPT_WITH_JVM_IR) - val generationState = GenerationState.Builder( - project, - builderFactory, - module, - bindingContext, - compilerConfiguration - ).targetId(targetId) + val isIrBackend = options.flags[KaptFlag.USE_JVM_IR] + val generationState = GenerationState.Builder(project, builderFactory, module, bindingContext, configuration) + .targetId(targetId) .isIrBackend(isIrBackend) .build() @@ -283,7 +282,7 @@ abstract class AbstractKapt3Extension( files, generationState, if (isIrBackend) - JvmIrCodegenFactory(compilerConfiguration, compilerConfiguration.get(CLIConfigurationKeys.PHASE_CONFIG)) + JvmIrCodegenFactory(configuration, configuration[CLIConfigurationKeys.PHASE_CONFIG]) else DefaultCodegenFactory ) } 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 8ed59c72a4e..c6258f966fc 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 @@ -127,6 +127,8 @@ class Kapt3CommandLineProcessor : CommandLineProcessor { STRICT_MODE_OPTION -> setFlag(KaptFlag.STRICT, value) 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) + SHOW_PROCESSOR_STATS -> setFlag(KaptFlag.SHOW_PROCESSOR_STATS, value) DUMP_PROCESSOR_STATS -> processorsStatsReportFile = File(value) INCLUDE_COMPILE_CLASSPATH -> setFlag(KaptFlag.INCLUDE_COMPILE_CLASSPATH, value) diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt index aa5d30c3cb5..4c8cb1fd8e4 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt @@ -176,7 +176,7 @@ abstract class AbstractKotlinKapt3IntegrationTest : KotlinKapt3TestBase() { .trimTrailingWhitespacesAndAddNewlineAtEOF() .let { AbstractClassFileToSourceStubConverterTest.removeMetadataAnnotationContents(it) } - KotlinTestUtils.assertEqualsToFile(txtFile, actual) + checkTxtAccordingToBackend(txtFile, actual) } finally { options.sourcesOutputDir.deleteRecursively() options.incrementalDataOutputDir?.deleteRecursively() diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index 6bda5bdb9ff..d5d5d5ba0c6 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -37,8 +37,6 @@ import org.jetbrains.kotlin.codegen.ClassBuilderMode import org.jetbrains.kotlin.codegen.CodegenTestFiles import org.jetbrains.kotlin.codegen.GenerationUtils import org.jetbrains.kotlin.codegen.OriginCollectingClassBuilderFactory -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.kapt.base.test.JavaKaptContextTest import org.jetbrains.kotlin.kapt3.Kapt3ComponentRegistrar.KaptComponentContributor @@ -170,14 +168,6 @@ abstract class AbstractKotlinKapt3Test : KotlinKapt3TestBase() { } } - override fun updateConfiguration(configuration: CompilerConfiguration) { - super.updateConfiguration(configuration) - - if (backend.isIR) { - configuration.put(JVMConfigurationKeys.USE_KAPT_WITH_JVM_IR, true) - } - } - protected fun convert( kaptContext: KaptContextForStubGeneration, javaFiles: List, @@ -333,15 +323,7 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test( } } - val irTxtFile = File(txtFile.parentFile, txtFile.nameWithoutExtension + "_ir.txt") - val expectedFile = - if (backend.isIR && irTxtFile.exists()) irTxtFile - else txtFile - KotlinTestUtils.assertEqualsToFile(expectedFile, actual) - - if (backend.isIR && txtFile.exists() && irTxtFile.exists() && txtFile.readText() == irTxtFile.readText()) { - fail("JVM and JVM_IR golden files are identical. Remove $irTxtFile.") - } + checkTxtAccordingToBackend(txtFile, actual) } } diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrKotlinKapt3IntegrationTests.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrKotlinKapt3IntegrationTests.kt index ab701a10b5f..37adedc3016 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrKotlinKapt3IntegrationTests.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrKotlinKapt3IntegrationTests.kt @@ -10,7 +10,6 @@ import javax.annotation.processing.ProcessingEnvironment import javax.annotation.processing.RoundEnvironment import javax.lang.model.element.TypeElement -// For now, just run one simple test to make sure Kapt launches at all with IR switched on. class IrKotlinKapt3IntegrationTests : AbstractIrKotlinKapt3IntegrationTest(), CustomJdkTestLauncher { override fun test( name: String, diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt index 7fceef30668..40b13d233db 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3TestBase.kt @@ -7,6 +7,9 @@ package org.jetbrains.kotlin.kapt3.test import org.jetbrains.kotlin.base.kapt3.KaptFlag import org.jetbrains.kotlin.codegen.CodegenTestCase +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.util.KtTestUtil import java.io.File @@ -48,6 +51,27 @@ abstract class KotlinKapt3TestBase : CodegenTestCase() { return KtTestUtil.tmpDir(name).also(directoriesToCleanup::add) } + protected fun checkTxtAccordingToBackend(txtFile: File, actual: String) { + val irTxtFile = File(txtFile.parentFile, txtFile.nameWithoutExtension + "_ir.txt") + val expectedFile = + if (backend.isIR && irTxtFile.exists()) irTxtFile + else txtFile + KotlinTestUtils.assertEqualsToFile(expectedFile, actual) + + if (backend.isIR && txtFile.exists() && irTxtFile.exists() && txtFile.readText() == irTxtFile.readText()) { + fail("JVM and JVM_IR golden files are identical. Remove $irTxtFile.") + } + } + + override fun updateConfiguration(configuration: CompilerConfiguration) { + super.updateConfiguration(configuration) + + if (backend.isIR) { + configuration.put(JVMConfigurationKeys.IR, true) + configuration.put(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT, true) + } + } + override fun doTest(filePath: String) { val testFile = File(filePath) @@ -57,6 +81,10 @@ abstract class KotlinKapt3TestBase : CodegenTestCase() { addOrRemoveFlag(KaptFlag.STRICT, testFile) addOrRemoveFlag(KaptFlag.DUMP_DEFAULT_PARAMETER_VALUES, testFile) + if (backend.isIR) { + kaptFlagsToAdd.add(KaptFlag.USE_JVM_IR) + } + super.doTest(filePath) } -} \ No newline at end of file +} diff --git a/plugins/kapt3/kapt3-compiler/testData/kotlinRunner/Simple.it_ir.txt b/plugins/kapt3/kapt3-compiler/testData/kotlinRunner/Simple.it_ir.txt new file mode 100644 index 00000000000..7ff32081aef --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/kotlinRunner/Simple.it_ir.txt @@ -0,0 +1,73 @@ +package error; + +public final class NonExistentClass { +} + +//////////////////// + +package test; + +import java.lang.System; + +/** + * KDoc comment. + */ +@kotlin.Suppress(names = {"UNRESOLVED_REFERENCE"}) +@kotlin.Metadata() +public final class Simple { + + public Simple() { + super(); + } + + @MyAnnotation() + public final void myMethod() { + } + + public final int heavyMethod() { + return 0; + } +} + +//////////////////// + +package test; + +import java.lang.System; + +@kotlin.Metadata() +public enum EnumClass { + /*public static final*/ BLACK /* = new BLACK() */, + /*public static final*/ WHITE /* = new WHITE() */; + + EnumClass() { + } +} + +//////////////////// + +package test; + +import java.lang.System; + +@kotlin.Metadata() +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +public abstract @interface MyAnnotation { +} + +//////////////////// + +package test; + +import java.lang.System; + +@kotlin.Metadata() +public enum EnumClass2 { + /*public static final*/ WHITE /* = new WHITE(null) */, + /*public static final*/ RED /* = new RED(null) */; + @org.jetbrains.annotations.NotNull() + private final java.lang.String blah = null; + + EnumClass2(java.lang.String blah) { + } +}