diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/arguments.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/arguments.kt index a2a42d07866..abbcd3de348 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/arguments.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/arguments.kt @@ -77,7 +77,10 @@ private fun switchToFallbackModeIfNecessary(arguments: CommonCompilerArguments, arguments.skipPrereleaseCheck = true arguments.allowUnstableDependencies = true } - arguments.useKapt4 && !isK2 -> warn("-Xuse-kapt4 flag can be only used with language version 2.0+.") + arguments.useKapt4 -> warn( + if (isK2) "Kapt 4 is an experimental feature. Use with caution." + else "-Xuse-kapt4 flag can be only used with language version 2.0+." + ) } } diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 5dbb01daa5b..3d61e062585 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.jvm.abi.AbstractCompareJvmAbiTest import org.jetbrains.kotlin.jvm.abi.AbstractCompileAgainstJvmAbiTest import org.jetbrains.kotlin.jvm.abi.AbstractJvmAbiContentTest import org.jetbrains.kotlin.kapt.cli.test.AbstractArgumentParsingTest +import org.jetbrains.kotlin.kapt.cli.test.AbstractKapt4ToolIntegrationTest import org.jetbrains.kotlin.kapt.cli.test.AbstractKaptToolIntegrationTest import org.jetbrains.kotlin.kapt3.test.runners.AbstractClassFileToSourceStubConverterTest import org.jetbrains.kotlin.kapt3.test.runners.AbstractIrClassFileToSourceStubConverterTest @@ -371,10 +372,12 @@ fun main(args: Array) { testClass { model("argumentParsing", extension = "txt") } - testClass { model("integration", recursive = false, extension = null) } + testClass { + model("integration-kapt4", recursive = false, extension = null) + } } testGroup("plugins/kapt3/kapt3-compiler/tests-gen", "plugins/kapt3/kapt3-compiler/testData") { 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 c09959984c9..828218a6b77 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 @@ -36,7 +36,8 @@ import kotlin.io.path.deleteExisting import kotlin.io.path.outputStream import kotlin.test.assertEquals -abstract class Kapt3BaseIT(val languageVersion: String = "1.9") : KGPBaseTest() { +abstract class Kapt3BaseIT : KGPBaseTest() { + companion object { private const val KAPT_SUCCESSFUL_MESSAGE = "Annotation processing complete, errors: 0" } @@ -44,8 +45,7 @@ abstract class Kapt3BaseIT(val languageVersion: String = "1.9") : KGPBaseTest() override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions .copy( kaptOptions = this.kaptOptions(), - languageVersion = languageVersion, - ) + ).copyEnsuringK1() protected open fun kaptOptions(): BuildOptions.KaptOptions = BuildOptions.KaptOptions( verbose = true, @@ -74,8 +74,8 @@ abstract class Kapt3BaseIT(val languageVersion: String = "1.9") : KGPBaseTest() * * then override and disable the test here via `@Disabled`. */ -@DisplayName("Kapt with classloaders cache") -class Kapt3ClassLoadersCacheIT : Kapt3IT() { +@DisplayName("Kapt 3 with classloaders cache") +open class Kapt3ClassLoadersCacheIT : Kapt3IT() { override fun kaptOptions(): BuildOptions.KaptOptions = super.kaptOptions().copy( classLoadersCacheSize = 10, includeCompileClasspath = false @@ -138,7 +138,7 @@ class Kapt3ClassLoadersCacheIT : Kapt3IT() { } } -@DisplayName("Kapt base checks") +@DisplayName("Kapt 3 base checks") @OtherGradlePluginTests open class Kapt3IT : Kapt3BaseIT() { @DisplayName("Kapt is skipped when no annotation processors are added") @@ -486,7 +486,7 @@ open class Kapt3IT : Kapt3BaseIT() { @DisplayName("Should incrementally rebuild on classpath change") @GradleTest - fun testChangeClasspathICRebuild(gradleVersion: GradleVersion) { + open fun testChangeClasspathICRebuild(gradleVersion: GradleVersion) { testICRebuild(gradleVersion) { project -> project.buildGradle.modify { "$it\ndependencies { implementation 'org.jetbrains.kotlin:kotlin-reflect:' + kotlin_version }" @@ -944,7 +944,7 @@ open class Kapt3IT : Kapt3BaseIT() { @DisplayName("kapt works with old MPP") @GradleTest - fun testMPPKaptPresence(gradleVersion: GradleVersion) { + open fun testMPPKaptPresence(gradleVersion: GradleVersion) { project("mpp-kapt-presence".withPrefix, gradleVersion) { build("build") { @@ -1051,7 +1051,7 @@ open class Kapt3IT : Kapt3BaseIT() { @DisplayName("KT-46651: kapt is tracking source files properly with configuration cache enabled") @GradleTest - fun kaptGenerateStubsShouldNotCaptureSourcesStateInConfigurationCache(gradleVersion: GradleVersion) { + open fun kaptGenerateStubsShouldNotCaptureSourcesStateInConfigurationCache(gradleVersion: GradleVersion) { project( "incrementalRebuild".withPrefix, gradleVersion, @@ -1208,7 +1208,7 @@ open class Kapt3IT : Kapt3BaseIT() { @DisplayName("Kapt runs in fallback mode with useK2 = true") @GradleTest - internal fun fallBackModeWithUseK2(gradleVersion: GradleVersion) { + open fun fallBackModeWithUseK2(gradleVersion: GradleVersion) { project("simple".withPrefix, gradleVersion) { buildGradle.appendText( """ @@ -1237,7 +1237,7 @@ open class Kapt3IT : Kapt3BaseIT() { @DisplayName("Kapt runs in fallback mode with languageVersion = 2.0") @GradleTest - internal fun fallBackModeWithLanguageVersion2_0(gradleVersion: GradleVersion) { + open fun fallBackModeWithLanguageVersion2_0(gradleVersion: GradleVersion) { project("simple".withPrefix, gradleVersion) { buildGradle.appendText( """ @@ -1347,4 +1347,19 @@ open class Kapt3IT : Kapt3BaseIT() { } } } + + @DisplayName("Application of annotation processors is repeated as long as new source files are generated") + @GradleTest + open fun testMultipleProcessingPasses(gradleVersion: GradleVersion) { + project("multipass".withPrefix, gradleVersion) { + build("build") { + assertKaptSuccessful() + assertOutputContains("No elements for AnnotationProcessor3") + assertOutputContains("No elements for AnnotationProcessor2") + assertFileInProjectExists("example/build/generated/source/kapt/main/generated/TestClass1.java") + assertFileInProjectExists("example/build/generated/source/kapt/main/generated/TestClass12.java") + assertFileInProjectExists("example/build/generated/source/kapt/main/generated/TestClass123.java") + } + } + } } 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 new file mode 100644 index 00000000000..e6aa8a8d4b0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle + +import org.gradle.util.GradleVersion +import org.jetbrains.kotlin.gradle.testbase.TestProject +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.DisplayName +import kotlin.io.path.appendText +import kotlin.io.path.name +import kotlin.io.path.walk + +@DisplayName("Kapt 4 base checks") +class Kapt4IT : Kapt3IT() { + override val defaultBuildOptions = super.defaultBuildOptions.copyEnsuringK2() + + override fun TestProject.customizeProject() { + forceKapt4() + } + + @Disabled("Currently failing. See KT-60950") + override fun kaptGenerateStubsShouldNotCaptureSourcesStateInConfigurationCache(gradleVersion: GradleVersion) {} + + @Disabled("Currently failing. See KT-60951") + override fun testChangeClasspathICRebuild(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't make sense in Kapt 4") + override fun useGeneratedKotlinSourceK2(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't make sense in Kapt 4") + override fun fallBackModeWithUseK2(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't make sense in Kapt 4") + override fun fallBackModeWithLanguageVersion2_0(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't make sense in Kapt 4") + override fun testRepeatableAnnotationsWithOldJvmBackend(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't work in 2.0. Neither with Kapt 3 nor with Kapt 4") + override fun testMPPKaptPresence(gradleVersion: GradleVersion) {} +} + +@DisplayName("Kapt 4 with classloaders cache") +class Kapt4ClassLoadersCacheIT : Kapt3ClassLoadersCacheIT() { + override val defaultBuildOptions = super.defaultBuildOptions.copyEnsuringK2() + + override fun TestProject.customizeProject() { + forceKapt4() + } + + @Disabled("Doesn't make sense in Kapt 4") + override fun useGeneratedKotlinSourceK2(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't make sense in Kapt 4") + override fun fallBackModeWithUseK2(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't make sense in Kapt 4") + override fun fallBackModeWithLanguageVersion2_0(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't make sense in Kapt 4") + override fun testRepeatableAnnotationsWithOldJvmBackend(gradleVersion: GradleVersion) {} + + @Disabled("Doesn't work in 2.0. Neither with Kapt 3 nor with Kapt 4") + override fun testMPPKaptPresence(gradleVersion: GradleVersion) {} + + @Disabled("Currently failing. See KT-60950") + override fun kaptGenerateStubsShouldNotCaptureSourcesStateInConfigurationCache(gradleVersion: GradleVersion) {} + + @Disabled("Currently failing. See KT-60951") + override fun testChangeClasspathICRebuild(gradleVersion: GradleVersion) {} +} + +fun TestProject.forceKapt4() { + projectPath.walk().forEach { + when (it.fileName.name) { + "build.gradle" -> it.appendText( + """ + + pluginManager.withPlugin('kotlin') { + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { + compilerOptions.freeCompilerArgs.addAll(['-Xuse-kapt4', '-Xsuppress-version-warnings']) + } + } + + """.trimIndent() + ) + "build.gradle.kts" -> it.appendText( + """ + + pluginManager.withPlugin("kotlin") { + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile::class.java).configureEach { + compilerOptions.freeCompilerArgs.addAll(listOf("-Xuse-kapt4", "-Xsuppress-version-warnings")) + } + } + + """.trimIndent() + ) + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidExternalIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidExternalIT.kt index 4e6d2e9ff2a..e652d117494 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidExternalIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidExternalIT.kt @@ -15,7 +15,7 @@ import kotlin.io.path.appendText @DisplayName("android with kapt3 external dependencies tests") @AndroidGradlePluginTests -class Kapt3AndroidExternalIT : Kapt3BaseIT() { +open class Kapt3AndroidExternalIT : Kapt3BaseIT() { // Deprecated and doesn't work with Gradle 8 + AGP 8, so keeping max Gradle version as 7.6 // For example: https://github.com/JakeWharton/butterknife/issues/1686 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 800a08e138a..59113793049 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 @@ -15,7 +15,7 @@ import kotlin.io.path.writeText @DisplayName("android with kapt3 tests") @AndroidGradlePluginTests -class Kapt3AndroidIT : Kapt3BaseIT() { +open class Kapt3AndroidIT : Kapt3BaseIT() { @DisplayName("KT-15001") @GradleAndroidTest fun testKt15001( diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIncrementalIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIncrementalIT.kt index 46c31bfa3a4..707b2fc1224 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIncrementalIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIncrementalIT.kt @@ -78,7 +78,7 @@ open class Kapt3AndroidIncrementalIT : Kapt3BaseIT() { @DisplayName("incremental compilation works with dagger") @GradleAndroidTest - fun testAndroidDaggerIC( + open fun testAndroidDaggerIC( gradleVersion: GradleVersion, agpVersion: String, jdkVersion: JdkVersions.ProvidedJdk, @@ -205,6 +205,6 @@ open class Kapt3AndroidIncrementalIT : Kapt3BaseIT() { } @DisplayName("android with kapt3 incremental build tests with precise compilation outputs backup") -class Kapt3AndroidIncrementalWithPreciseBackupIT : Kapt3AndroidIncrementalIT() { +open class Kapt3AndroidIncrementalWithPreciseBackupIT : Kapt3AndroidIncrementalIT() { override val defaultBuildOptions = super.defaultBuildOptions.copy(usePreciseOutputsBackup = true, keepIncrementalCompilationCachesInMemory = true) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidExternalIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidExternalIT.kt new file mode 100644 index 00000000000..1112473cdef --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidExternalIT.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.android + +import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.gradle.forceKapt4 +import org.jetbrains.kotlin.gradle.testbase.TestProject +import org.junit.jupiter.api.DisplayName + +@DisplayName("android with kapt4 external dependencies tests") +class Kapt4AndroidExternalIT : Kapt3AndroidExternalIT() { + override val defaultBuildOptions = super.defaultBuildOptions.copyEnsuringK2() + + override fun TestProject.customizeProject() { + forceKapt4() + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidIT.kt new file mode 100644 index 00000000000..3b8f5924585 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidIT.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.android + +import org.jetbrains.kotlin.gradle.forceKapt4 +import org.jetbrains.kotlin.gradle.testbase.TestProject +import org.junit.jupiter.api.DisplayName + +@DisplayName("android with kapt4 tests") +class Kapt4AndroidIT : Kapt3AndroidIT() { + override val defaultBuildOptions = super.defaultBuildOptions.copyEnsuringK2() + + override fun TestProject.customizeProject() { + forceKapt4() + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidIncrementalIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidIncrementalIT.kt new file mode 100644 index 00000000000..19f2d587bb1 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt4AndroidIncrementalIT.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.android + +import org.gradle.util.GradleVersion +import org.jetbrains.kotlin.gradle.forceKapt4 +import org.jetbrains.kotlin.gradle.testbase.JdkVersions +import org.jetbrains.kotlin.gradle.testbase.TestProject +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.DisplayName + +@DisplayName("android with kapt4 incremental build tests") +class Kapt4AndroidIncrementalIT : Kapt3AndroidIncrementalIT() { + override val defaultBuildOptions = super.defaultBuildOptions.copyEnsuringK2() + + override fun TestProject.customizeProject() { + forceKapt4() + } + + @Disabled("See KT-61628") + override fun testAndroidDaggerIC(gradleVersion: GradleVersion, agpVersion: String, jdkVersion: JdkVersions.ProvidedJdk) {} +} + +@DisplayName("android with kapt4 incremental build tests with precise compilation outputs backup") +class Kapt4AndroidIncrementalWithPreciseBackupIT : Kapt3AndroidIncrementalWithPreciseBackupIT() { + override val defaultBuildOptions = super.defaultBuildOptions.copyEnsuringK2() + + override fun TestProject.customizeProject() { + forceKapt4() + } + + @Disabled("See KT-61628") + override fun testAndroidDaggerIC(gradleVersion: GradleVersion, agpVersion: String, jdkVersion: JdkVersions.ProvidedJdk) {} +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/KGPBaseTest.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/KGPBaseTest.kt index 6fb92e88b5e..5fbd856c7f1 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/KGPBaseTest.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/KGPBaseTest.kt @@ -35,4 +35,6 @@ abstract class KGPBaseTest { @TempDir lateinit var workingDir: Path + + internal open fun TestProject.customizeProject() {} } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt index 5e7367c9702..1103fad518e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt @@ -82,6 +82,8 @@ fun KGPBaseTest.project( localRepoDir?.let { testProject.configureLocalRepository(localRepoDir) } if (buildJdk != null) testProject.setupNonDefaultJdk(buildJdk) + testProject.customizeProject() + val result = runCatching { testProject.test() } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/annotation-processors/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/annotation-processors/build.gradle new file mode 100644 index 00000000000..104106a8991 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/annotation-processors/build.gradle @@ -0,0 +1,7 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' +} + +dependencies { + implementation "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/multipass/annotation-processors/src/main/java/processors.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/annotation-processors/src/main/java/processors.kt new file mode 100644 index 00000000000..3918f31149e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/annotation-processors/src/main/java/processors.kt @@ -0,0 +1,77 @@ +package processors + +import javax.annotation.processing.* +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement +import javax.tools.Diagnostic + + +annotation class Annotation1 +annotation class Annotation2 +annotation class Annotation3 + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("processors.Annotation1") +class AnnotationProcessor1 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation1::class.java) + if (elements.isEmpty()) { + processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "No elements for ${this::class.java.simpleName}") + } + for (element in elements) { + val generatedSimpleName = "${element.simpleName}1" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\n@processors.Annotation2\npublic class $generatedSimpleName {}") + } + } + + return true + } +} + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("processors.Annotation2") +class AnnotationProcessor2 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation2::class.java) + if (elements.isEmpty()) { + processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "No elements for ${this::class.java.simpleName}") + } + for (element in elements) { + val generatedSimpleName = "${element.simpleName}2" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\n@processors.Annotation3\npublic class $generatedSimpleName {}") + } + } + + return true + } +} + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("processors.Annotation3") +class AnnotationProcessor3 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation3::class.java) + if (elements.isEmpty()) { + processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "No elements for ${this::class.java.simpleName}") + } + for (element in elements) { + val generatedSimpleName = "${element.simpleName}3" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\npublic class $generatedSimpleName {}") + } + } + + return true + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/build.gradle new file mode 100644 index 00000000000..5948671485a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/build.gradle @@ -0,0 +1,6 @@ +allprojects { + repositories { + mavenLocal() + mavenCentral() + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/build.gradle new file mode 100644 index 00000000000..716672a284b --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' + id 'org.jetbrains.kotlin.kapt' + id 'idea' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + implementation project(":annotation-processors") + kapt project(":annotation-processors") + + testImplementation'junit:junit:4.13.2' +} + +idea { + module { + sourceDirs += files('build/generated/source/kapt/main', 'build/generated/source/kaptKotlin/main') + generatedSourceDirs += files('build/generated/source/kapt/main', 'build/generated/source/kaptKotlin/main') + } +} + +kapt { + // The "reverse" order requires three passes + annotationProcessors("processors.AnnotationProcessor3", "processors.AnnotationProcessor2", "processors.AnnotationProcessor1") +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/src/main/kotlin/TestClass.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/src/main/kotlin/TestClass.kt new file mode 100644 index 00000000000..cb01a2f5f30 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/src/main/kotlin/TestClass.kt @@ -0,0 +1,6 @@ +package example + +import processors.Annotation1 + +@Annotation1 +class TestClass diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/src/test/kotlin/test.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/src/test/kotlin/test.kt new file mode 100644 index 00000000000..aaa2f28e109 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/example/src/test/kotlin/test.kt @@ -0,0 +1,11 @@ +package example + +import org.junit.Test +import org.junit.Assert.* +import generated.TestClass123 + +class AnnotationTest { + @Test fun testSimple() { + assertEquals("TestClass123", TestClass123::class.java.simpleName) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/settings.gradle new file mode 100644 index 00000000000..108a8ce19c5 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/multipass/settings.gradle @@ -0,0 +1 @@ +include ':annotation-processors', ':example' \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKapt4ToolIntegrationTest.kt b/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKapt4ToolIntegrationTest.kt new file mode 100644 index 00000000000..98f99257a5d --- /dev/null +++ b/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKapt4ToolIntegrationTest.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.kapt.cli.test + +abstract class AbstractKapt4ToolIntegrationTest : AbstractKaptToolIntegrationTest() diff --git a/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt b/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt index 93dff460a2c..a816c3b267c 100644 --- a/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt +++ b/plugins/kapt3/kapt3-cli/test/org/jetbrains/kotlin/kapt/cli/test/AbstractKaptToolIntegrationTest.kt @@ -9,7 +9,6 @@ import com.intellij.openapi.util.SystemInfo import org.jetbrains.kotlin.cli.common.arguments.readArgumentsFromArgFile import org.jetbrains.kotlin.test.services.JUnit5Assertions import org.jetbrains.kotlin.test.util.KtTestUtil -import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInfo import java.io.File @@ -88,7 +87,7 @@ abstract class AbstractKaptToolIntegrationTest { private fun runJavac(args: List) { val executableName = if (SystemInfo.isWindows) "javac.exe" else "javac" - val executablePath = File(getJdk8Home(), "bin/" + executableName).absolutePath + val executablePath = File(KtTestUtil.getJdk8Home(), "bin/" + executableName).absolutePath runProcess(executablePath, args) } @@ -96,7 +95,7 @@ abstract class AbstractKaptToolIntegrationTest { val outputFile = File(tmpdir, "javaOutput.txt") val executableName = if (SystemInfo.isWindows) "java.exe" else "java" - val executablePath = File(getJdk8Home(), "bin/" + executableName).absolutePath + val executablePath = File(KtTestUtil.getJdk8Home(), "bin/" + executableName).absolutePath runProcess(executablePath, args, outputFile) throw GotResult(outputFile.takeIf { it.isFile }?.readText() ?: "") @@ -126,18 +125,13 @@ abstract class AbstractKaptToolIntegrationTest { private fun transformArguments(args: List): List { return args.map { val arg = it.replace("%KOTLIN_STDLIB%", File("dist/kotlinc/lib/kotlin-stdlib.jar").absolutePath) - if (SystemInfo.isWindows && (arg.contains("=") || arg.contains(":"))) { + if (SystemInfo.isWindows && (arg.contains("=") || arg.contains(":") || arg.contains(";"))) { "\"" + arg + "\"" } else { arg } } } - - private fun getJdk8Home(): File { - val homePath = System.getenv()["JDK_1_8"] ?: System.getenv()["JDK_18"] ?: error("Can't find JDK 1.8 home, please define JDK_1_8 variable") - return File(homePath) - } } private val Section.args get() = readArgumentsFromArgFile(preprocessPathSeparators(content)) diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/apKotlincArgs.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/apKotlincArgs.txt new file mode 100644 index 00000000000..b909ccfe95a --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/apKotlincArgs.txt @@ -0,0 +1,3 @@ +-language-version 2.0 +-d output/ap +ap/Processor.kt \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/build.txt new file mode 100644 index 00000000000..50c6e89e0b7 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/build.txt @@ -0,0 +1,36 @@ +# copy +../simple/ap +ap + +# copy +../simple/Test.kt +Test.kt + +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +@apKotlincArgs.txt + +# kapt +@kaptArgs.txt + +# javac +@javacArgs.txt + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:output/classes:output/javaClasses +Test.kt + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/javacArgs.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/javacArgs.txt new file mode 100644 index 00000000000..626b0cbaccf --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/javacArgs.txt @@ -0,0 +1,6 @@ +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Function.java +output/sources/generated/Property.java +output/sources/generated/Test.java \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/kaptArgs.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/kaptArgs.txt new file mode 100644 index 00000000000..5f6166ce3ca --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/kaptArgs.txt @@ -0,0 +1,11 @@ +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubsAndApt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-processors=apt.SampleApt +-d output/classes +-cp output/ap +Test.kt \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/compileModeUnsupported/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/compileModeUnsupported/build.txt new file mode 100644 index 00000000000..8d6c0d7151a --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/compileModeUnsupported/build.txt @@ -0,0 +1,11 @@ +# kapt +-language-version 2.0 +-Xsuppress-version-warnings +-Xuse-kapt4 +-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/testData/integration-kapt4/correctErrorTypesOn/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/Test.kt new file mode 100644 index 00000000000..0dca3a7104c --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/Test.kt @@ -0,0 +1,14 @@ +package test + +import apt.Anno +import generated.Property + +object Test { + @field:Anno + lateinit var property: Property + + @JvmStatic + fun main(args: Array) { + print(javaClass.getDeclaredField("property").type.toGenericString()) + } +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/ap/Processor.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/ap/Processor.kt new file mode 100644 index 00000000000..720015f97d6 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/ap/Processor.kt @@ -0,0 +1,31 @@ +package apt + +import javax.annotation.processing.* +import javax.lang.model.SourceVersion +import javax.lang.model.element.* +import javax.lang.model.type.DeclaredType +import javax.tools.Diagnostic.Kind.* + +annotation class Anno + +class SampleApt : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + for (element in roundEnv.getElementsAnnotatedWith(Anno::class.java).filterIsInstance()) { + val type = element.asType() as? DeclaredType ?: continue + if (type.toString() == "error.NonExistentClass") { + processingEnv.messager.printMessage(ERROR, "NonExistentClass type occurred") + } + + val generatedSimpleName = element.simpleName.toString().capitalize() + processingEnv.filer.createSourceFile("generated.$generatedSimpleName").openWriter().use { + it.write("package generated;\npublic class $generatedSimpleName {}") + } + } + + return true + } + + override fun getSupportedOptions() = emptySet() + override fun getSupportedSourceVersion() = SourceVersion.RELEASE_8 + override fun getSupportedAnnotationTypes() = setOf("apt.Anno") +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/build.txt new file mode 100644 index 00000000000..97db889ce40 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/build.txt @@ -0,0 +1,44 @@ +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-processors=apt.SampleApt +-Kapt-correct-error-types=true +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# javac +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Property.java + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:output/classes:%KOTLIN_STDLIB% +Test.kt +output/sources + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.Test + +# after +public class generated.Property \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/RootClass.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/RootClass.kt new file mode 100644 index 00000000000..568ed8a64f4 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/RootClass.kt @@ -0,0 +1 @@ +class RootClass diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/Usage.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/Usage.kt new file mode 100644 index 00000000000..d6e1e0c3cec --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/Usage.kt @@ -0,0 +1,7 @@ +package test + +import RootClass + +interface Usage { + fun test(): RootClass +} diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/build.txt new file mode 100644 index 00000000000..cad0d62fe1a --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/build.txt @@ -0,0 +1,47 @@ +# copy +../simple/ap +ap + +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubsAndApt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-processors=apt.SampleApt +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +RootClass.kt +Usage.kt + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:output/classes:output/sources:%KOTLIN_STDLIB% +RootClass.kt +Usage.kt + +# after +Return code: 1 + +warning: [kapt] test.Usage: Can't reference type 'RootClass' from default package in Java stub. +error: output/stubs/test/Usage.java:9: error: cannot find symbol + public abstract RootClass test(); + ^ + symbol: class RootClass + location: interface Usage diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/Test.kt new file mode 100644 index 00000000000..a23c6701f3b --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/Test.kt @@ -0,0 +1,19 @@ +package test + +import apt.Anno +import generated.Test as TestGenerated + +@Anno +class Test { + @field:Anno + val property: String = "" + + @Anno + fun function() { + + } +} + +fun main() { + println("Generated class: " + TestGenerated::class.java.name) +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/ap/META-INF/services/javax.annotation.processing.Processor b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/ap/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000000..078558ee7db --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/ap/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +apt.SampleApt \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/ap/Processor.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/ap/Processor.kt new file mode 100644 index 00000000000..697fe0a5db2 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/ap/Processor.kt @@ -0,0 +1,37 @@ +package apt + +import java.io.File +import javax.annotation.processing.* +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement +import javax.tools.Diagnostic.Kind.* + +annotation class Anno + +class SampleApt : AbstractProcessor() { + private companion object { + const val KAPT_KOTLIN_GENERATED_OPTION_NAME = "kapt.kotlin.generated" + } + + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val kaptKotlinGeneratedDir = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME] ?: run { + processingEnv.messager.printMessage(ERROR, "Can't find the target directory for generated Kotlin files.") + return false + } + + val baseDir = File(kaptKotlinGeneratedDir, "generated") + baseDir.mkdirs() + + for (element in roundEnv.getElementsAnnotatedWith(Anno::class.java)) { + val generatedSimpleName = element.simpleName.toString().capitalize() + val file = File(baseDir, "$generatedSimpleName.kt") + file.writeText("package generated\n@apt.Anno\nclass $generatedSimpleName") + } + + return true + } + + override fun getSupportedOptions() = emptySet() + override fun getSupportedSourceVersion() = SourceVersion.RELEASE_8 + override fun getSupportedAnnotationTypes() = setOf("apt.Anno") +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/build.txt new file mode 100644 index 00000000000..8daf7725503 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/build.txt @@ -0,0 +1,43 @@ +# mkdir +output/ap +output/stubs +output/classes +output/sources +output/kotlin-sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# copy +ap/META-INF/services/javax.annotation.processing.Processor +output/ap/META-INF/services/javax.annotation.processing.Processor + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubsAndApt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-option:kapt.kotlin.generated=output/kotlin-sources +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt +output/kotlin-sources + +# java +-cp output/classes:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGenerationDefaultOutput/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGenerationDefaultOutput/build.txt new file mode 100644 index 00000000000..aecd3640da2 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGenerationDefaultOutput/build.txt @@ -0,0 +1,48 @@ +# copy +../simple/ap +ap + +# copy +../simple/Test.kt +Test.kt + +# mkdir +output/ap +output/stubs +output/classes +output/sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubsAndApt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-processors=apt.SampleApt +-Kapt-option:kapt.test.writeKotlinFiles=true +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# kotlinc +-language-version 2.0 +-Xuse-kapt4 +-d output/classes +-cp output/classes:output/ap:%KOTLIN_STDLIB% +Test.kt +output/sources + +# java +-cp output/classes:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kt33800/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kt33800/Test.kt new file mode 100644 index 00000000000..e40827f392b --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kt33800/Test.kt @@ -0,0 +1,19 @@ +package test + +import apt.Anno +import generated.Example as ExampleGenerated + +@Anno +class Example() { + private val callback = object : Any() { + val obj = Object() + } + + fun call() { + callback.obj + } +} + +fun main() { + println("Generated class: " + ExampleGenerated::class.java.name) +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kt33800/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kt33800/build.txt new file mode 100644 index 00000000000..4ac429b34ab --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/kt33800/build.txt @@ -0,0 +1,52 @@ +# copy +../simple/ap +ap + +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# copy +../simple/ap/META-INF/services/javax.annotation.processing.Processor +output/ap/META-INF/services/javax.annotation.processing.Processor + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubsAndApt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:output/classes:%KOTLIN_STDLIB% +Test.kt +output/sources + +# javac +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Example.java + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Example \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/Test.kt new file mode 100644 index 00000000000..83734475d6e --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/Test.kt @@ -0,0 +1,11 @@ +package test + +import apt.Annotation1 +import generated.Test123 + +@Annotation1 +class Test + +fun main() { + println("Generated class: " + Test123::class.java.name) +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/ap/processors.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/ap/processors.kt new file mode 100644 index 00000000000..16bc7f0fcdb --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/ap/processors.kt @@ -0,0 +1,68 @@ +package apt + +import javax.annotation.processing.* +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement +import javax.tools.Diagnostic + + +annotation class Annotation1 +annotation class Annotation2 +annotation class Annotation3 + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("apt.Annotation1") +class AnnotationProcessor1 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation1::class.java) + for (element in elements) { + val generatedSimpleName = "${element.simpleName}1" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\n@apt.Annotation2\npublic class $generatedSimpleName {}") + } + } + + return true + } +} + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("apt.Annotation2") +class AnnotationProcessor2 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation2::class.java) + for (element in elements) { + val generatedSimpleName = "${element.simpleName}2" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\n@apt.Annotation3\npublic class $generatedSimpleName {}") + } + } + + return true + } +} + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("apt.Annotation3") +class AnnotationProcessor3 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation3::class.java) + for (element in elements) { + val generatedSimpleName = "${element.simpleName}3" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\npublic class $generatedSimpleName {}") + } + } + + return true + } +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/build.txt new file mode 100644 index 00000000000..77963179bce --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/build.txt @@ -0,0 +1,48 @@ +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/processors.kt + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubsAndApt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-processors=apt.AnnotationProcessor3 +-Kapt-processors=apt.AnnotationProcessor2 +-Kapt-processors=apt.AnnotationProcessor1 +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# javac +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Test1.java +output/sources/generated/Test12.java +output/sources/generated/Test123.java + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:output/javaClasses:output/classes:%KOTLIN_STDLIB% +Test.kt + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test123 \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/separateStubAptCompilation/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/separateStubAptCompilation/build.txt new file mode 100644 index 00000000000..300ddcbc7f5 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/separateStubAptCompilation/build.txt @@ -0,0 +1,67 @@ +# copy +../simple/ap +ap + +# copy +../simple/Test.kt +Test.kt + +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-mode=stubs +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-mode=apt +-Kapt-processors=apt.SampleApt +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +output/sources +Test.kt + +# javac +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Function.java +output/sources/generated/Property.java +output/sources/generated/Test.java + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/Test.kt new file mode 100644 index 00000000000..a23c6701f3b --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/Test.kt @@ -0,0 +1,19 @@ +package test + +import apt.Anno +import generated.Test as TestGenerated + +@Anno +class Test { + @field:Anno + val property: String = "" + + @Anno + fun function() { + + } +} + +fun main() { + println("Generated class: " + TestGenerated::class.java.name) +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/ap/META-INF/services/javax.annotation.processing.Processor b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/ap/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000000..078558ee7db --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/ap/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +apt.SampleApt \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/ap/Processor.kt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/ap/Processor.kt new file mode 100644 index 00000000000..22afdb91cc7 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/ap/Processor.kt @@ -0,0 +1,34 @@ +package apt + +import javax.annotation.processing.* +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement +import javax.tools.Diagnostic.Kind.* +import javax.tools.StandardLocation + +annotation class Anno + +class SampleApt : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val writeKotlinFiles = processingEnv.options["kapt.test.writeKotlinFiles"] == "true" + + for (element in roundEnv.getElementsAnnotatedWith(Anno::class.java)) { + val generatedSimpleName = element.simpleName.toString().capitalize() + + val file = when (writeKotlinFiles) { + true -> processingEnv.filer.createResource(StandardLocation.SOURCE_OUTPUT, "generated", "$generatedSimpleName.kt") + false -> processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + } + + file.openWriter().use { + it.write("package generated;\npublic class $generatedSimpleName {}") + } + } + + return true + } + + override fun getSupportedOptions() = setOf("kapt.test.writeKotlinFiles") + override fun getSupportedSourceVersion() = SourceVersion.RELEASE_8 + override fun getSupportedAnnotationTypes() = setOf("apt.Anno") +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/build.txt new file mode 100644 index 00000000000..f6de1d6e276 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/build.txt @@ -0,0 +1,49 @@ +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# copy +ap/META-INF/services/javax.annotation.processing.Processor +output/ap/META-INF/services/javax.annotation.processing.Processor + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-mode=stubsAndApt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# javac +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Function.java +output/sources/generated/Property.java +output/sources/generated/Test.java + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:output/javaClasses:output/classes:%KOTLIN_STDLIB% +Test.kt + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration-kapt4/withoutService/build.txt b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/withoutService/build.txt new file mode 100644 index 00000000000..e3076182cdb --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration-kapt4/withoutService/build.txt @@ -0,0 +1,54 @@ +# copy +../simple/ap +ap + +# copy +../simple/Test.kt +Test.kt + +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-language-version 2.0 +-cp %KOTLIN_STDLIB% +-d output/ap +ap/Processor.kt + +# kapt +-language-version 2.0 +-Xuse-kapt4 +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-processors=apt.SampleApt +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# kotlinc +-language-version 2.0 +-d output/classes +-cp output/ap:output/classes:%KOTLIN_STDLIB% +Test.kt +output/sources + +# javac +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Function.java +output/sources/generated/Property.java +output/sources/generated/Test.java + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration/multipass/Test.kt b/plugins/kapt3/kapt3-cli/testData/integration/multipass/Test.kt new file mode 100644 index 00000000000..83734475d6e --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration/multipass/Test.kt @@ -0,0 +1,11 @@ +package test + +import apt.Annotation1 +import generated.Test123 + +@Annotation1 +class Test + +fun main() { + println("Generated class: " + Test123::class.java.name) +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration/multipass/ap/processors.kt b/plugins/kapt3/kapt3-cli/testData/integration/multipass/ap/processors.kt new file mode 100644 index 00000000000..16bc7f0fcdb --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration/multipass/ap/processors.kt @@ -0,0 +1,68 @@ +package apt + +import javax.annotation.processing.* +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement +import javax.tools.Diagnostic + + +annotation class Annotation1 +annotation class Annotation2 +annotation class Annotation3 + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("apt.Annotation1") +class AnnotationProcessor1 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation1::class.java) + for (element in elements) { + val generatedSimpleName = "${element.simpleName}1" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\n@apt.Annotation2\npublic class $generatedSimpleName {}") + } + } + + return true + } +} + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("apt.Annotation2") +class AnnotationProcessor2 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation2::class.java) + for (element in elements) { + val generatedSimpleName = "${element.simpleName}2" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\n@apt.Annotation3\npublic class $generatedSimpleName {}") + } + } + + return true + } +} + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("apt.Annotation3") +class AnnotationProcessor3 : AbstractProcessor() { + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + val elements = roundEnv.getElementsAnnotatedWith(Annotation3::class.java) + for (element in elements) { + val generatedSimpleName = "${element.simpleName}3" + + val file = processingEnv.filer.createSourceFile("generated.$generatedSimpleName") + + file.openWriter().use { + it.write("package generated;\npublic class $generatedSimpleName {}") + } + } + + return true + } +} \ No newline at end of file diff --git a/plugins/kapt3/kapt3-cli/testData/integration/multipass/build.txt b/plugins/kapt3/kapt3-cli/testData/integration/multipass/build.txt new file mode 100644 index 00000000000..9cb0559d41d --- /dev/null +++ b/plugins/kapt3/kapt3-cli/testData/integration/multipass/build.txt @@ -0,0 +1,38 @@ +# mkdir +output/ap +output/stubs +output/classes +output/javaClasses +output/sources + +# kotlinc +-cp %KOTLIN_STDLIB% +-d output/ap +ap/processors.kt + +# kapt +-Kapt-stubs=output/stubs +-Kapt-classes=output/classes +-Kapt-sources=output/sources +-Kapt-classpath=output/ap +-Kapt-processors=apt.AnnotationProcessor3 +-Kapt-processors=apt.AnnotationProcessor2 +-Kapt-processors=apt.AnnotationProcessor1 +-d output/classes +-cp output/ap:%KOTLIN_STDLIB% +Test.kt + +# javac +-cp output/ap +-d output/javaClasses +-proc:none +output/sources/generated/Test1.java +output/sources/generated/Test12.java +output/sources/generated/Test123.java + +# java +-cp output/classes:output/javaClasses:output/ap:%KOTLIN_STDLIB% +test.TestKt + +# after +Generated class: generated.Test123 \ No newline at end of file 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 new file mode 100644 index 00000000000..de71457a3b9 --- /dev/null +++ b/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/Kapt4ToolIntegrationTestGenerated.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.kapt.cli.test; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/kapt3/kapt3-cli/testData/integration-kapt4") +@TestDataPath("$PROJECT_ROOT") +public class Kapt4ToolIntegrationTestGenerated extends AbstractKapt4ToolIntegrationTest { + @Test + public void testAllFilesPresentInIntegration_kapt4() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kapt3/kapt3-cli/testData/integration-kapt4"), Pattern.compile("^([^\\.]+)$"), null, false); + } + + @Test + @TestMetadata("argfile") + public void testArgfile() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/argfile/"); + } + + @Test + @TestMetadata("compileModeUnsupported") + public void testCompileModeUnsupported() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/compileModeUnsupported/"); + } + + @Test + @TestMetadata("correctErrorTypesOn") + public void testCorrectErrorTypesOn() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/correctErrorTypesOn/"); + } + + @Test + @TestMetadata("defaultPackage") + public void testDefaultPackage() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/defaultPackage/"); + } + + @Test + @TestMetadata("kotlinFileGeneration") + public void testKotlinFileGeneration() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGeneration/"); + } + + @Test + @TestMetadata("kotlinFileGenerationDefaultOutput") + public void testKotlinFileGenerationDefaultOutput() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/kotlinFileGenerationDefaultOutput/"); + } + + @Test + @TestMetadata("kt33800") + public void testKt33800() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/kt33800/"); + } + + @Test + @TestMetadata("multipass") + public void testMultipass() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/multipass/"); + } + + @Test + @TestMetadata("separateStubAptCompilation") + public void testSeparateStubAptCompilation() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/separateStubAptCompilation/"); + } + + @Test + @TestMetadata("simple") + public void testSimple() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/simple/"); + } + + @Test + @TestMetadata("withoutService") + public void testWithoutService() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration-kapt4/withoutService/"); + } +} diff --git a/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/KaptToolIntegrationTestGenerated.java b/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/KaptToolIntegrationTestGenerated.java index 462d4c06dd0..26dd5c0761d 100644 --- a/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/KaptToolIntegrationTestGenerated.java +++ b/plugins/kapt3/kapt3-cli/tests-gen/org/jetbrains/kotlin/kapt/cli/test/KaptToolIntegrationTestGenerated.java @@ -78,6 +78,12 @@ public class KaptToolIntegrationTestGenerated extends AbstractKaptToolIntegratio runTest("plugins/kapt3/kapt3-cli/testData/integration/kt33800/"); } + @Test + @TestMetadata("multipass") + public void testMultipass() throws Exception { + runTest("plugins/kapt3/kapt3-cli/testData/integration/multipass/"); + } + @Test @TestMetadata("separateStubAptCompilation") public void testSeparateStubAptCompilation() throws Exception { diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/EfficientProcessorLoader.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/EfficientProcessorLoader.kt new file mode 100644 index 00000000000..5ccc34a11d7 --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/EfficientProcessorLoader.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.kapt3 + +import org.jetbrains.kotlin.base.kapt3.KaptOptions +import org.jetbrains.kotlin.kapt3.base.ProcessorLoader +import org.jetbrains.kotlin.kapt3.base.util.KaptLogger +import org.jetbrains.kotlin.util.ServiceLoaderLite +import java.io.File +import java.net.URLClassLoader +import javax.annotation.processing.Processor + +class EfficientProcessorLoader(options: KaptOptions, logger: KaptLogger) : ProcessorLoader(options, logger) { + override fun doLoadProcessors(classpath: LinkedHashSet, classLoader: ClassLoader): List = + when (classLoader) { + is URLClassLoader -> ServiceLoaderLite.loadImplementations(Processor::class.java, classLoader) + else -> super.doLoadProcessors(classpath, classLoader) + } +} \ No newline at end of file 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 163eba755d1..0df8c47ab7c 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 @@ -59,11 +59,8 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension -import org.jetbrains.kotlin.util.ServiceLoaderLite import org.jetbrains.kotlin.utils.kapt.MemoryLeakDetector import java.io.File -import java.net.URLClassLoader -import javax.annotation.processing.Processor class ClasspathBasedKapt3Extension( options: KaptOptions, @@ -76,16 +73,8 @@ class ClasspathBasedKapt3Extension( private var processorLoader: ProcessorLoader? = null override fun loadProcessors(): LoadedProcessors { - val efficientProcessorLoader = object : ProcessorLoader(options, logger) { - override fun doLoadProcessors(classpath: LinkedHashSet, classLoader: ClassLoader): List = - when (classLoader) { - is URLClassLoader -> ServiceLoaderLite.loadImplementations(Processor::class.java, classLoader) - else -> super.doLoadProcessors(classpath, classLoader) - } - } - - this.processorLoader = efficientProcessorLoader - return efficientProcessorLoader.loadProcessors() + this.processorLoader = EfficientProcessorLoader(options, logger) + return processorLoader!!.loadProcessors() } override fun analysisCompleted( diff --git a/plugins/kapt4/build.gradle.kts b/plugins/kapt4/build.gradle.kts index dba7de9b86c..f6ed61caa90 100644 --- a/plugins/kapt4/build.gradle.kts +++ b/plugins/kapt4/build.gradle.kts @@ -11,6 +11,7 @@ dependencies { compileOnly(project(":compiler:frontend.java")) compileOnly(project(":compiler:plugin-api")) implementation(project(":kotlin-annotation-processing-compiler")) + compileOnly(project(":kotlin-annotation-processing-base")) compileOnly(project(":analysis:analysis-api-standalone")) compileOnly(toolsJarApi()) diff --git a/plugins/kapt4/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar b/plugins/kapt4/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar index 4cf7239748d..cb8a541436a 100644 --- a/plugins/kapt4/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar +++ b/plugins/kapt4/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar @@ -1,6 +1 @@ -# -# Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. -# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. -# - org.jetbrains.kotlin.kapt4.Kapt4CompilerPluginRegistrar diff --git a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt index 7b2fc068bdf..a220ae4481d 100644 --- a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt +++ b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4AnalysisHandlerExtension.kt @@ -5,19 +5,171 @@ package org.jetbrains.kotlin.kapt4 +import com.sun.tools.javac.tree.JCTree +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider +import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider +import org.jetbrains.kotlin.analysis.api.standalone.KtAlwaysAccessibleLifetimeTokenProvider +import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession +import org.jetbrains.kotlin.base.kapt3.* +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.config.CommonConfigurationKeys.USE_FIR import org.jetbrains.kotlin.fir.extensions.FirAnalysisHandlerExtension +import org.jetbrains.kotlin.kapt3.EfficientProcessorLoader import org.jetbrains.kotlin.kapt3.KAPT_OPTIONS +import org.jetbrains.kotlin.kapt3.base.Kapt +import org.jetbrains.kotlin.kapt3.base.doAnnotationProcessing +import org.jetbrains.kotlin.kapt3.base.util.KaptLogger +import org.jetbrains.kotlin.kapt3.base.util.getPackageNameJava9Aware +import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedKaptLogger +import org.jetbrains.kotlin.kapt3.util.prettyPrint +import org.jetbrains.kotlin.psi.KtFile +import java.io.File - -class Kapt4AnalysisHandlerExtension : FirAnalysisHandlerExtension() { +private class Kapt4AnalysisHandlerExtension : FirAnalysisHandlerExtension() { override fun isApplicable(configuration: CompilerConfiguration): Boolean = - configuration.getBoolean(CommonConfigurationKeys.USE_FIR) && configuration[KAPT_OPTIONS] != null + configuration.getBoolean(USE_FIR) && configuration[KAPT_OPTIONS] != null + @OptIn(KtAnalysisApiInternals::class) override fun doAnalysis(configuration: CompilerConfiguration): Boolean { - TODO("Not yet implemented") + val optionsBuilder = configuration[KAPT_OPTIONS]!! + val logger = MessageCollectorBackedKaptLogger( + KaptFlag.VERBOSE in optionsBuilder.flags, + KaptFlag.INFO_AS_WARNINGS in optionsBuilder.flags, + configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)!! + ) + + if (optionsBuilder.mode == AptMode.WITH_COMPILATION) { + logger.error("KAPT \"compile\" mode is not supported in Kotlin 2.x. Run kapt with -Kapt-mode=stubsAndApt and use kotlinc for the final compilation step.") + return false + } + + val oldLanguageVersionSettings = configuration.languageVersionSettings + val updatedConfiguration = configuration.copy().apply { + languageVersionSettings = object : LanguageVersionSettings by oldLanguageVersionSettings { + @Suppress("UNCHECKED_CAST") + override fun getFlag(flag: AnalysisFlag): T = + when (flag) { + JvmAnalysisFlags.generatePropertyAnnotationsMethods -> true as T + else -> oldLanguageVersionSettings.getFlag(flag) + } + } + } + + val standaloneAnalysisAPISession = + buildStandaloneAnalysisAPISession(classLoader = Kapt4AnalysisHandlerExtension::class.java.classLoader) { + @Suppress("DEPRECATION") // TODO: KT-61319 Kapt: remove usages of deprecated buildKtModuleProviderByCompilerConfiguration + buildKtModuleProviderByCompilerConfiguration(updatedConfiguration) + + registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) + } + + val (module, psiFiles) = standaloneAnalysisAPISession.modulesWithFiles.entries.single() + + optionsBuilder.apply { + projectBaseDir = projectBaseDir ?: module.project.basePath?.let(::File) + val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList() + compileClasspath.addAll(contentRoots.filterIsInstance().map { it.file }) + javaSourceRoots.addAll(contentRoots.filterIsInstance().map { it.file }) + classesOutputDir = classesOutputDir ?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY) + } + + if (!optionsBuilder.checkOptions(logger, configuration)) return false + val options = optionsBuilder.build() + if (options[KaptFlag.VERBOSE]) { + logger.info(options.logString()) + } + + var context: Kapt4ContextForStubGeneration? = null + return try { + KtAnalysisSessionProvider.getInstance(module.project).analyze(module) { + context = Kapt4ContextForStubGeneration(options, withJdk = false, logger, this, psiFiles.filterIsInstance()) + + if (options.mode.generateStubs) + generateStubs(context!!) + + if (options.mode.runAnnotationProcessing) + runProcessors(context!!, options, logger) + true + } + } catch (e: Exception) { + logger.exception(e) + false + } finally { + context?.close() + } + } + + private fun generateStubs(context: Kapt4ContextForStubGeneration) { + val generator = with(context) { Kapt4StubGenerator() } + val stubs = generator.generateStubs().values.filterNotNull().toList() + for (kaptStub in stubs) { + val stub = kaptStub.file + val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString() + + val packageName = stub.getPackageNameJava9Aware()?.toString() ?: "" + val stubsOutputDir = context.options.stubsOutputDir + val packageDir = if (packageName.isEmpty()) stubsOutputDir else File(stubsOutputDir, packageName.replace('.', '/')) + packageDir.mkdirs() + + val sourceFile = File(packageDir, "$className.java") + sourceFile.writeText(stub.prettyPrint(context.context)) + + kaptStub.writeMetadataIfNeeded(forSource = sourceFile) + } + File(context.options.stubsOutputDir, "error").apply { mkdirs() }.resolve("NonExistentClass.java") + .writeText("package error;\npublic class NonExistentClass {}\n") + } + + private fun runProcessors( + context: Kapt4ContextForStubGeneration, + options: KaptOptions, + logger: KaptLogger, + ) { + val sources = options.collectJavaSourceFiles(context.sourcesToReprocess) + if (sources.isEmpty()) return + EfficientProcessorLoader(options, logger).use { + context.doAnnotationProcessing(sources, it.loadProcessors().processors) + } + } + + private fun KaptOptions.Builder.checkOptions(logger: KaptLogger, configuration: CompilerConfiguration): Boolean { + if (classesOutputDir == null && configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) { + logger.error("Kapt does not support specifying JAR file outputs. Please specify the classes output directory explicitly.") + return false + } + + if (processingClasspath.isEmpty()) { + // Skip annotation processing if no annotation processors were provided + logger.info("No annotation processors provided. Skip KAPT processing.") + return false + } + + if (sourcesOutputDir == null || classesOutputDir == null || stubsOutputDir == null) { + if (mode != AptMode.WITH_COMPILATION) { + val nonExistentOptionName = when { + sourcesOutputDir == null -> "Sources output directory" + classesOutputDir == null -> "Classes output directory" + stubsOutputDir == null -> "Stubs output directory" + else -> throw IllegalStateException() + } + val moduleName = configuration.get(CommonConfigurationKeys.MODULE_NAME) + ?: configuration.get(JVMConfigurationKeys.MODULES).orEmpty().joinToString() + + logger.warn("$nonExistentOptionName is not specified for $moduleName, skipping annotation processing") + } + return false + } + + if (!Kapt.checkJavacComponentsAccess(logger)) { + return false + } + + return true } } diff --git a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4ContextForStubGeneration.kt b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4ContextForStubGeneration.kt index c5d6a2278ea..8692240707c 100644 --- a/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4ContextForStubGeneration.kt +++ b/plugins/kapt4/src/org/jetbrains/kotlin/kapt4/Kapt4ContextForStubGeneration.kt @@ -9,20 +9,33 @@ import com.sun.tools.javac.tree.TreeMaker import com.sun.tools.javac.util.Context import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.findFacadeClass +import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.base.kapt3.KaptOptions import org.jetbrains.kotlin.kapt3.base.KaptContext import org.jetbrains.kotlin.kapt3.base.util.KaptLogger +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile internal class Kapt4ContextForStubGeneration( options: KaptOptions, withJdk: Boolean, logger: KaptLogger, val analysisSession: KtAnalysisSession, - val classes: Iterable + val files: List, ) : KaptContext(options, withJdk, logger) { + val classes: Iterable = buildSet { + files.flatMapTo(this) { file -> + file.children.filterIsInstance().mapNotNull { + it.toLightClass() + } + } + files.mapNotNullTo(this) { ktFile -> ktFile.findFacadeClass() }.distinct() + } + internal val treeMaker = TreeMaker.instance(context) as Kapt4TreeMaker override fun preregisterTreeMaker(context: Context) { Kapt4TreeMaker.preRegister(context) } -} \ No newline at end of file +} diff --git a/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt b/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt index a1a5aa35280..d61cdd22b9d 100644 --- a/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt +++ b/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt @@ -13,16 +13,12 @@ import org.jetbrains.kotlin.analysis.api.lifetime.KtReadActionConfinementLifetim import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession import org.jetbrains.kotlin.asJava.classes.KtLightClass -import org.jetbrains.kotlin.asJava.findFacadeClass -import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.base.kapt3.KaptOptions import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots -import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger import org.jetbrains.kotlin.kapt3.test.KaptMessageCollectorProvider import org.jetbrains.kotlin.kapt3.test.kaptOptionsProvider -import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.model.* import org.jetbrains.kotlin.test.services.* @@ -78,16 +74,6 @@ private fun run( buildKtModuleProviderByCompilerConfiguration(configuration) } val (module, psiFiles) = standaloneAnalysisAPISession.modulesWithFiles.entries.single() - val ktFiles = psiFiles.filterIsInstance() - - val lightClasses = buildSet { - ktFiles.flatMapTo(this) { file -> - file.children.filterIsInstance().mapNotNull { - it.toLightClass() - } - } - ktFiles.mapNotNullTo(this) { ktFile -> ktFile.findFacadeClass() }.distinct() - } return KtAnalysisSessionProvider.getInstance(module.project).analyze(module) { val context = Kapt4ContextForStubGeneration( @@ -95,7 +81,7 @@ private fun run( withJdk = false, WriterBackedKaptLogger(isVerbose = false), this@analyze, - lightClasses + psiFiles.filterIsInstance() ) val generator = with(context) { Kapt4StubGenerator() } context to generator.generateStubs() @@ -111,4 +97,3 @@ internal data class Kapt4ContextBinaryArtifact( override val kind: BinaryKind get() = Kind } - diff --git a/prepare/compiler/compiler.pro b/prepare/compiler/compiler.pro index 746fd00ad83..7ab50fbcc8a 100644 --- a/prepare/compiler/compiler.pro +++ b/prepare/compiler/compiler.pro @@ -303,3 +303,19 @@ # This class is needed for test framework -keep class com.intellij.openapi.util.text.StringUtil { *; } + + +# This is used from standalone analysis API, which is NOT a part of the compiler but is bundled into kotlin-annotation-processing. +-keepclassmembers class com.intellij.openapi.vfs.VirtualFileManager { + com.intellij.openapi.vfs.VirtualFile findFileByNioPath(java.nio.file.Path); +} +-keepclassmembers class com.intellij.openapi.application.Application { + void addApplicationListener(com.intellij.openapi.application.ApplicationListener, com.intellij.openapi.Disposable); +} +-keepclassmembers class com.intellij.openapi.extensions.ExtensionPointName { + java.util.List getExtensionList(com.intellij.openapi.extensions.AreaInstance); +} +-keepclassmembers class kotlinx.collections.immutable.ExtensionsKt { + kotlinx.collections.immutable.PersistentMap toPersistentHashMap(java.util.Map); + kotlinx.collections.immutable.PersistentSet persistentHashSetOf(java.lang.Object[]); +}