[KAPT4] KT-51982 Implement Kapt4AnalysisHandlerExtension, add KAPT CLI and Gradle IT

Co-authored-by: Alexander Udalov <Alexander.Udalov@jetbrains.com>
This commit is contained in:
Alexander Udalov
2023-08-31 22:19:13 +00:00
committed by Space Team
parent d50d36f16c
commit 5c19cb3fcb
61 changed files with 1577 additions and 68 deletions
@@ -77,7 +77,10 @@ private fun switchToFallbackModeIfNecessary(arguments: CommonCompilerArguments,
arguments.skipPrereleaseCheck = true arguments.skipPrereleaseCheck = true
arguments.allowUnstableDependencies = 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+."
)
} }
} }
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.jvm.abi.AbstractCompareJvmAbiTest
import org.jetbrains.kotlin.jvm.abi.AbstractCompileAgainstJvmAbiTest import org.jetbrains.kotlin.jvm.abi.AbstractCompileAgainstJvmAbiTest
import org.jetbrains.kotlin.jvm.abi.AbstractJvmAbiContentTest import org.jetbrains.kotlin.jvm.abi.AbstractJvmAbiContentTest
import org.jetbrains.kotlin.kapt.cli.test.AbstractArgumentParsingTest 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.kapt.cli.test.AbstractKaptToolIntegrationTest
import org.jetbrains.kotlin.kapt3.test.runners.AbstractClassFileToSourceStubConverterTest import org.jetbrains.kotlin.kapt3.test.runners.AbstractClassFileToSourceStubConverterTest
import org.jetbrains.kotlin.kapt3.test.runners.AbstractIrClassFileToSourceStubConverterTest import org.jetbrains.kotlin.kapt3.test.runners.AbstractIrClassFileToSourceStubConverterTest
@@ -371,10 +372,12 @@ fun main(args: Array<String>) {
testClass<AbstractArgumentParsingTest> { testClass<AbstractArgumentParsingTest> {
model("argumentParsing", extension = "txt") model("argumentParsing", extension = "txt")
} }
testClass<AbstractKaptToolIntegrationTest> { testClass<AbstractKaptToolIntegrationTest> {
model("integration", recursive = false, extension = null) model("integration", recursive = false, extension = null)
} }
testClass<AbstractKapt4ToolIntegrationTest> {
model("integration-kapt4", recursive = false, extension = null)
}
} }
testGroup("plugins/kapt3/kapt3-compiler/tests-gen", "plugins/kapt3/kapt3-compiler/testData") { testGroup("plugins/kapt3/kapt3-compiler/tests-gen", "plugins/kapt3/kapt3-compiler/testData") {
@@ -36,7 +36,8 @@ import kotlin.io.path.deleteExisting
import kotlin.io.path.outputStream import kotlin.io.path.outputStream
import kotlin.test.assertEquals import kotlin.test.assertEquals
abstract class Kapt3BaseIT(val languageVersion: String = "1.9") : KGPBaseTest() { abstract class Kapt3BaseIT : KGPBaseTest() {
companion object { companion object {
private const val KAPT_SUCCESSFUL_MESSAGE = "Annotation processing complete, errors: 0" 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 override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions
.copy( .copy(
kaptOptions = this.kaptOptions(), kaptOptions = this.kaptOptions(),
languageVersion = languageVersion, ).copyEnsuringK1()
)
protected open fun kaptOptions(): BuildOptions.KaptOptions = BuildOptions.KaptOptions( protected open fun kaptOptions(): BuildOptions.KaptOptions = BuildOptions.KaptOptions(
verbose = true, verbose = true,
@@ -74,8 +74,8 @@ abstract class Kapt3BaseIT(val languageVersion: String = "1.9") : KGPBaseTest()
* *
* then override and disable the test here via `@Disabled`. * then override and disable the test here via `@Disabled`.
*/ */
@DisplayName("Kapt with classloaders cache") @DisplayName("Kapt 3 with classloaders cache")
class Kapt3ClassLoadersCacheIT : Kapt3IT() { open class Kapt3ClassLoadersCacheIT : Kapt3IT() {
override fun kaptOptions(): BuildOptions.KaptOptions = super.kaptOptions().copy( override fun kaptOptions(): BuildOptions.KaptOptions = super.kaptOptions().copy(
classLoadersCacheSize = 10, classLoadersCacheSize = 10,
includeCompileClasspath = false includeCompileClasspath = false
@@ -138,7 +138,7 @@ class Kapt3ClassLoadersCacheIT : Kapt3IT() {
} }
} }
@DisplayName("Kapt base checks") @DisplayName("Kapt 3 base checks")
@OtherGradlePluginTests @OtherGradlePluginTests
open class Kapt3IT : Kapt3BaseIT() { open class Kapt3IT : Kapt3BaseIT() {
@DisplayName("Kapt is skipped when no annotation processors are added") @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") @DisplayName("Should incrementally rebuild on classpath change")
@GradleTest @GradleTest
fun testChangeClasspathICRebuild(gradleVersion: GradleVersion) { open fun testChangeClasspathICRebuild(gradleVersion: GradleVersion) {
testICRebuild(gradleVersion) { project -> testICRebuild(gradleVersion) { project ->
project.buildGradle.modify { project.buildGradle.modify {
"$it\ndependencies { implementation 'org.jetbrains.kotlin:kotlin-reflect:' + kotlin_version }" "$it\ndependencies { implementation 'org.jetbrains.kotlin:kotlin-reflect:' + kotlin_version }"
@@ -944,7 +944,7 @@ open class Kapt3IT : Kapt3BaseIT() {
@DisplayName("kapt works with old MPP") @DisplayName("kapt works with old MPP")
@GradleTest @GradleTest
fun testMPPKaptPresence(gradleVersion: GradleVersion) { open fun testMPPKaptPresence(gradleVersion: GradleVersion) {
project("mpp-kapt-presence".withPrefix, gradleVersion) { project("mpp-kapt-presence".withPrefix, gradleVersion) {
build("build") { build("build") {
@@ -1051,7 +1051,7 @@ open class Kapt3IT : Kapt3BaseIT() {
@DisplayName("KT-46651: kapt is tracking source files properly with configuration cache enabled") @DisplayName("KT-46651: kapt is tracking source files properly with configuration cache enabled")
@GradleTest @GradleTest
fun kaptGenerateStubsShouldNotCaptureSourcesStateInConfigurationCache(gradleVersion: GradleVersion) { open fun kaptGenerateStubsShouldNotCaptureSourcesStateInConfigurationCache(gradleVersion: GradleVersion) {
project( project(
"incrementalRebuild".withPrefix, "incrementalRebuild".withPrefix,
gradleVersion, gradleVersion,
@@ -1208,7 +1208,7 @@ open class Kapt3IT : Kapt3BaseIT() {
@DisplayName("Kapt runs in fallback mode with useK2 = true") @DisplayName("Kapt runs in fallback mode with useK2 = true")
@GradleTest @GradleTest
internal fun fallBackModeWithUseK2(gradleVersion: GradleVersion) { open fun fallBackModeWithUseK2(gradleVersion: GradleVersion) {
project("simple".withPrefix, gradleVersion) { project("simple".withPrefix, gradleVersion) {
buildGradle.appendText( buildGradle.appendText(
""" """
@@ -1237,7 +1237,7 @@ open class Kapt3IT : Kapt3BaseIT() {
@DisplayName("Kapt runs in fallback mode with languageVersion = 2.0") @DisplayName("Kapt runs in fallback mode with languageVersion = 2.0")
@GradleTest @GradleTest
internal fun fallBackModeWithLanguageVersion2_0(gradleVersion: GradleVersion) { open fun fallBackModeWithLanguageVersion2_0(gradleVersion: GradleVersion) {
project("simple".withPrefix, gradleVersion) { project("simple".withPrefix, gradleVersion) {
buildGradle.appendText( 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")
}
}
}
} }
@@ -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()
)
}
}
}
@@ -15,7 +15,7 @@ import kotlin.io.path.appendText
@DisplayName("android with kapt3 external dependencies tests") @DisplayName("android with kapt3 external dependencies tests")
@AndroidGradlePluginTests @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 // 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 // For example: https://github.com/JakeWharton/butterknife/issues/1686
@@ -15,7 +15,7 @@ import kotlin.io.path.writeText
@DisplayName("android with kapt3 tests") @DisplayName("android with kapt3 tests")
@AndroidGradlePluginTests @AndroidGradlePluginTests
class Kapt3AndroidIT : Kapt3BaseIT() { open class Kapt3AndroidIT : Kapt3BaseIT() {
@DisplayName("KT-15001") @DisplayName("KT-15001")
@GradleAndroidTest @GradleAndroidTest
fun testKt15001( fun testKt15001(
@@ -78,7 +78,7 @@ open class Kapt3AndroidIncrementalIT : Kapt3BaseIT() {
@DisplayName("incremental compilation works with dagger") @DisplayName("incremental compilation works with dagger")
@GradleAndroidTest @GradleAndroidTest
fun testAndroidDaggerIC( open fun testAndroidDaggerIC(
gradleVersion: GradleVersion, gradleVersion: GradleVersion,
agpVersion: String, agpVersion: String,
jdkVersion: JdkVersions.ProvidedJdk, jdkVersion: JdkVersions.ProvidedJdk,
@@ -205,6 +205,6 @@ open class Kapt3AndroidIncrementalIT : Kapt3BaseIT() {
} }
@DisplayName("android with kapt3 incremental build tests with precise compilation outputs backup") @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) override val defaultBuildOptions = super.defaultBuildOptions.copy(usePreciseOutputsBackup = true, keepIncrementalCompilationCachesInMemory = true)
} }
@@ -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()
}
}
@@ -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()
}
}
@@ -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) {}
}
@@ -35,4 +35,6 @@ abstract class KGPBaseTest {
@TempDir @TempDir
lateinit var workingDir: Path lateinit var workingDir: Path
internal open fun TestProject.customizeProject() {}
} }
@@ -82,6 +82,8 @@ fun KGPBaseTest.project(
localRepoDir?.let { testProject.configureLocalRepository(localRepoDir) } localRepoDir?.let { testProject.configureLocalRepository(localRepoDir) }
if (buildJdk != null) testProject.setupNonDefaultJdk(buildJdk) if (buildJdk != null) testProject.setupNonDefaultJdk(buildJdk)
testProject.customizeProject()
val result = runCatching { val result = runCatching {
testProject.test() testProject.test()
} }
@@ -0,0 +1,7 @@
plugins {
id 'org.jetbrains.kotlin.jvm'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
@@ -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<TypeElement>, 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<TypeElement>, 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<TypeElement>, 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
}
}
@@ -0,0 +1,6 @@
allprojects {
repositories {
mavenLocal()
mavenCentral()
}
}
@@ -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")
}
@@ -0,0 +1,6 @@
package example
import processors.Annotation1
@Annotation1
class TestClass
@@ -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)
}
}
@@ -0,0 +1 @@
include ':annotation-processors', ':example'
@@ -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()
@@ -9,7 +9,6 @@ import com.intellij.openapi.util.SystemInfo
import org.jetbrains.kotlin.cli.common.arguments.readArgumentsFromArgFile import org.jetbrains.kotlin.cli.common.arguments.readArgumentsFromArgFile
import org.jetbrains.kotlin.test.services.JUnit5Assertions import org.jetbrains.kotlin.test.services.JUnit5Assertions
import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.test.util.KtTestUtil
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInfo import org.junit.jupiter.api.TestInfo
import java.io.File import java.io.File
@@ -88,7 +87,7 @@ abstract class AbstractKaptToolIntegrationTest {
private fun runJavac(args: List<String>) { private fun runJavac(args: List<String>) {
val executableName = if (SystemInfo.isWindows) "javac.exe" else "javac" 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) runProcess(executablePath, args)
} }
@@ -96,7 +95,7 @@ abstract class AbstractKaptToolIntegrationTest {
val outputFile = File(tmpdir, "javaOutput.txt") val outputFile = File(tmpdir, "javaOutput.txt")
val executableName = if (SystemInfo.isWindows) "java.exe" else "java" 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) runProcess(executablePath, args, outputFile)
throw GotResult(outputFile.takeIf { it.isFile }?.readText() ?: "") throw GotResult(outputFile.takeIf { it.isFile }?.readText() ?: "")
@@ -126,18 +125,13 @@ abstract class AbstractKaptToolIntegrationTest {
private fun transformArguments(args: List<String>): List<String> { private fun transformArguments(args: List<String>): List<String> {
return args.map { return args.map {
val arg = it.replace("%KOTLIN_STDLIB%", File("dist/kotlinc/lib/kotlin-stdlib.jar").absolutePath) 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 + "\"" "\"" + arg + "\""
} else { } else {
arg 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)) private val Section.args get() = readArgumentsFromArgFile(preprocessPathSeparators(content))
@@ -0,0 +1,3 @@
-language-version 2.0
-d output/ap
ap/Processor.kt
@@ -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
@@ -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
@@ -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
@@ -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.
@@ -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<String>) {
print(javaClass.getDeclaredField("property").type.toGenericString())
}
}
@@ -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<TypeElement>, roundEnv: RoundEnvironment): Boolean {
for (element in roundEnv.getElementsAnnotatedWith(Anno::class.java).filterIsInstance<VariableElement>()) {
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<String>()
override fun getSupportedSourceVersion() = SourceVersion.RELEASE_8
override fun getSupportedAnnotationTypes() = setOf("apt.Anno")
}
@@ -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
@@ -0,0 +1 @@
class RootClass
@@ -0,0 +1,7 @@
package test
import RootClass
interface Usage {
fun test(): RootClass
}
@@ -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
@@ -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)
}
@@ -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<TypeElement>, 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<String>()
override fun getSupportedSourceVersion() = SourceVersion.RELEASE_8
override fun getSupportedAnnotationTypes() = setOf("apt.Anno")
}
@@ -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
@@ -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
@@ -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)
}
@@ -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
@@ -0,0 +1,11 @@
package test
import apt.Annotation1
import generated.Test123
@Annotation1
class Test
fun main() {
println("Generated class: " + Test123::class.java.name)
}
@@ -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<TypeElement>, 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<TypeElement>, 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<TypeElement>, 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
}
}
@@ -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
@@ -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
@@ -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)
}
@@ -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<TypeElement>, 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")
}
@@ -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
@@ -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
@@ -0,0 +1,11 @@
package test
import apt.Annotation1
import generated.Test123
@Annotation1
class Test
fun main() {
println("Generated class: " + Test123::class.java.name)
}
@@ -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<TypeElement>, 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<TypeElement>, 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<TypeElement>, 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
}
}
@@ -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
@@ -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/");
}
}
@@ -78,6 +78,12 @@ public class KaptToolIntegrationTestGenerated extends AbstractKaptToolIntegratio
runTest("plugins/kapt3/kapt3-cli/testData/integration/kt33800/"); 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 @Test
@TestMetadata("separateStubAptCompilation") @TestMetadata("separateStubAptCompilation")
public void testSeparateStubAptCompilation() throws Exception { public void testSeparateStubAptCompilation() throws Exception {
@@ -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<File>, classLoader: ClassLoader): List<Processor> =
when (classLoader) {
is URLClassLoader -> ServiceLoaderLite.loadImplementations(Processor::class.java, classLoader)
else -> super.doLoadProcessors(classpath, classLoader)
}
}
@@ -59,11 +59,8 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
import org.jetbrains.kotlin.util.ServiceLoaderLite
import org.jetbrains.kotlin.utils.kapt.MemoryLeakDetector import org.jetbrains.kotlin.utils.kapt.MemoryLeakDetector
import java.io.File import java.io.File
import java.net.URLClassLoader
import javax.annotation.processing.Processor
class ClasspathBasedKapt3Extension( class ClasspathBasedKapt3Extension(
options: KaptOptions, options: KaptOptions,
@@ -76,16 +73,8 @@ class ClasspathBasedKapt3Extension(
private var processorLoader: ProcessorLoader? = null private var processorLoader: ProcessorLoader? = null
override fun loadProcessors(): LoadedProcessors { override fun loadProcessors(): LoadedProcessors {
val efficientProcessorLoader = object : ProcessorLoader(options, logger) { this.processorLoader = EfficientProcessorLoader(options, logger)
override fun doLoadProcessors(classpath: LinkedHashSet<File>, classLoader: ClassLoader): List<Processor> = return processorLoader!!.loadProcessors()
when (classLoader) {
is URLClassLoader -> ServiceLoaderLite.loadImplementations(Processor::class.java, classLoader)
else -> super.doLoadProcessors(classpath, classLoader)
}
}
this.processorLoader = efficientProcessorLoader
return efficientProcessorLoader.loadProcessors()
} }
override fun analysisCompleted( override fun analysisCompleted(
+1
View File
@@ -11,6 +11,7 @@ dependencies {
compileOnly(project(":compiler:frontend.java")) compileOnly(project(":compiler:frontend.java"))
compileOnly(project(":compiler:plugin-api")) compileOnly(project(":compiler:plugin-api"))
implementation(project(":kotlin-annotation-processing-compiler")) implementation(project(":kotlin-annotation-processing-compiler"))
compileOnly(project(":kotlin-annotation-processing-base"))
compileOnly(project(":analysis:analysis-api-standalone")) compileOnly(project(":analysis:analysis-api-standalone"))
compileOnly(toolsJarApi()) compileOnly(toolsJarApi())
@@ -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 org.jetbrains.kotlin.kapt4.Kapt4CompilerPluginRegistrar
@@ -5,19 +5,171 @@
package org.jetbrains.kotlin.kapt4 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.compiler.plugin.CompilerPluginRegistrar
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CommonConfigurationKeys.USE_FIR
import org.jetbrains.kotlin.fir.extensions.FirAnalysisHandlerExtension 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.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
private class Kapt4AnalysisHandlerExtension : FirAnalysisHandlerExtension() {
class Kapt4AnalysisHandlerExtension : FirAnalysisHandlerExtension() {
override fun isApplicable(configuration: CompilerConfiguration): Boolean = 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 { 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 <T> getFlag(flag: AnalysisFlag<T>): 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<JvmClasspathRoot>().map { it.file })
javaSourceRoots.addAll(contentRoots.filterIsInstance<JavaSourceRoot>().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<KtFile>())
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
} }
} }
@@ -9,20 +9,33 @@ import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.util.Context import com.sun.tools.javac.util.Context
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.asJava.classes.KtLightClass 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.base.kapt3.KaptOptions
import org.jetbrains.kotlin.kapt3.base.KaptContext import org.jetbrains.kotlin.kapt3.base.KaptContext
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
internal class Kapt4ContextForStubGeneration( internal class Kapt4ContextForStubGeneration(
options: KaptOptions, options: KaptOptions,
withJdk: Boolean, withJdk: Boolean,
logger: KaptLogger, logger: KaptLogger,
val analysisSession: KtAnalysisSession, val analysisSession: KtAnalysisSession,
val classes: Iterable<KtLightClass> val files: List<KtFile>,
) : KaptContext(options, withJdk, logger) { ) : KaptContext(options, withJdk, logger) {
val classes: Iterable<KtLightClass> = buildSet {
files.flatMapTo(this) { file ->
file.children.filterIsInstance<KtClassOrObject>().mapNotNull {
it.toLightClass()
}
}
files.mapNotNullTo(this) { ktFile -> ktFile.findFacadeClass() }.distinct()
}
internal val treeMaker = TreeMaker.instance(context) as Kapt4TreeMaker internal val treeMaker = TreeMaker.instance(context) as Kapt4TreeMaker
override fun preregisterTreeMaker(context: Context) { override fun preregisterTreeMaker(context: Context) {
Kapt4TreeMaker.preRegister(context) Kapt4TreeMaker.preRegister(context)
} }
} }
@@ -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.session.KtAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession
import org.jetbrains.kotlin.asJava.classes.KtLightClass 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.base.kapt3.KaptOptions
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots 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.config.CompilerConfiguration
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
import org.jetbrains.kotlin.kapt3.test.KaptMessageCollectorProvider import org.jetbrains.kotlin.kapt3.test.KaptMessageCollectorProvider
import org.jetbrains.kotlin.kapt3.test.kaptOptionsProvider import org.jetbrains.kotlin.kapt3.test.kaptOptionsProvider
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.* import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.*
@@ -78,16 +74,6 @@ private fun run(
buildKtModuleProviderByCompilerConfiguration(configuration) buildKtModuleProviderByCompilerConfiguration(configuration)
} }
val (module, psiFiles) = standaloneAnalysisAPISession.modulesWithFiles.entries.single() val (module, psiFiles) = standaloneAnalysisAPISession.modulesWithFiles.entries.single()
val ktFiles = psiFiles.filterIsInstance<KtFile>()
val lightClasses = buildSet {
ktFiles.flatMapTo(this) { file ->
file.children.filterIsInstance<KtClassOrObject>().mapNotNull {
it.toLightClass()
}
}
ktFiles.mapNotNullTo(this) { ktFile -> ktFile.findFacadeClass() }.distinct()
}
return KtAnalysisSessionProvider.getInstance(module.project).analyze(module) { return KtAnalysisSessionProvider.getInstance(module.project).analyze(module) {
val context = Kapt4ContextForStubGeneration( val context = Kapt4ContextForStubGeneration(
@@ -95,7 +81,7 @@ private fun run(
withJdk = false, withJdk = false,
WriterBackedKaptLogger(isVerbose = false), WriterBackedKaptLogger(isVerbose = false),
this@analyze, this@analyze,
lightClasses psiFiles.filterIsInstance<KtFile>()
) )
val generator = with(context) { Kapt4StubGenerator() } val generator = with(context) { Kapt4StubGenerator() }
context to generator.generateStubs() context to generator.generateStubs()
@@ -111,4 +97,3 @@ internal data class Kapt4ContextBinaryArtifact(
override val kind: BinaryKind<Kapt4ContextBinaryArtifact> override val kind: BinaryKind<Kapt4ContextBinaryArtifact>
get() = Kind get() = Kind
} }
+16
View File
@@ -303,3 +303,19 @@
# This class is needed for test framework # This class is needed for test framework
-keep class com.intellij.openapi.util.text.StringUtil { *; } -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[]);
}