From 1417c8961b5d3a634062a6c7ecd1be3379ee5528 Mon Sep 17 00:00:00 2001 From: Nicklas Ansman Date: Tue, 11 Oct 2022 19:20:20 -0400 Subject: [PATCH] KAPT: pass KAPT generated classes to kotlinc classpath Make sure to pass .class files generated by annotation processors to KotlinCompile task. This way, Kotlin files can refer to symbols generated in these .class files during annotation processing. Disable the test in Kapt3ClassLoadersCacheIT #KT-33847 Fixed --- .../org/jetbrains/kotlin/gradle/Kapt3IT.kt | 36 +++++++++++ .../kapt2/kt33847/api/build.gradle | 7 +++ .../kapt2/kt33847/api/src/main/kotlin/Api.kt | 6 ++ .../kapt2/kt33847/app/build.gradle | 8 +++ .../kapt2/kt33847/app/src/main/kotlin/App.kt | 6 ++ .../testProject/kapt2/kt33847/build.gradle | 10 +++ .../kapt2/kt33847/library/build.gradle | 10 +++ .../library/src/main/kotlin/Library.kt | 13 ++++ .../kapt2/kt33847/processor/build.gradle | 11 ++++ .../processor/src/main/kotlin/Processor.kt | 58 ++++++++++++++++++ .../src/main/resources/StringFactory.class | Bin 0 -> 304 bytes .../testProject/kapt2/kt33847/settings.gradle | 5 ++ .../kapt/Kapt3KotlinGradleSubplugin.kt | 9 ++- .../gradle/tasks/configuration/KaptConfig.kt | 2 +- .../configuration/KaptGenerateStubsConfig.kt | 8 ++- 15 files changed, 183 insertions(+), 6 deletions(-) create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/build.gradle create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/src/main/kotlin/Api.kt create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/build.gradle create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/src/main/kotlin/App.kt create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/build.gradle create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/build.gradle create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/src/main/kotlin/Library.kt create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/build.gradle create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/src/main/kotlin/Processor.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/src/main/resources/StringFactory.class create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/settings.gradle diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt index 2f55ae4c88e..3fa5d78765b 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 @@ -90,6 +90,10 @@ class Kapt3ClassLoadersCacheIT : Kapt3IT() { override fun testChangesToKaptConfigurationDoNotTriggerStubGeneration(gradleVersion: GradleVersion) { } + @Disabled("classloaders cache is leaking file descriptors that prevents cleaning test project") + override fun testKt33847(gradleVersion: GradleVersion) { + } + override fun testAnnotationProcessorAsFqName(gradleVersion: GradleVersion) { project("annotationProcessorAsFqName".withPrefix, gradleVersion) { //classloaders caching is not compatible with includeCompileClasspath @@ -812,6 +816,38 @@ open class Kapt3IT : Kapt3BaseIT() { } } + @DisplayName("KT33847: Kapt does not included Filer-generated class files on compilation classpath") + @GradleTest + open fun testKt33847(gradleVersion: GradleVersion) { + project("kt33847".withPrefix, gradleVersion) { + + build("build") { + val processorSubproject = subProject("processor") + processorSubproject + .assertFileInProjectExists("build/tmp/kapt3/classes/main/META-INF/services/javax.annotation.processing.Processor") + + val processorJar = processorSubproject.projectPath.resolve("build/libs/processor.jar") + assertFileExists(processorJar) + + ZipFile(processorJar.toFile()).use { zip -> + assert(zip.getEntry("META-INF/services/javax.annotation.processing.Processor") != null) { + "Generated annotation processor jar file does not contain processor service entry!" + } + } + + assertTasksExecuted( + ":api:compileKotlin", + ":processor:compileKotlin", + ":library:kaptGenerateStubsKotlin", + ":library:kaptKotlin", + ":library:compileKotlin", + ":app:compileKotlin", + ) + assertKaptSuccessful() + } + } + } + @DisplayName("Dependency on kapt module should not resolve all configurations") @GradleTest fun testDependencyOnKaptModule(gradleVersion: GradleVersion) { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/build.gradle new file mode 100755 index 00000000000..439508cdc9a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/build.gradle @@ -0,0 +1,7 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/src/main/kotlin/Api.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/src/main/kotlin/Api.kt new file mode 100755 index 00000000000..c3eeb44bee6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/api/src/main/kotlin/Api.kt @@ -0,0 +1,6 @@ +package com.example + +import kotlin.annotation.AnnotationTarget.CLASS + +@Target(CLASS) +annotation class SomeAnnotation diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/build.gradle new file mode 100755 index 00000000000..bf92b34cb94 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/build.gradle @@ -0,0 +1,8 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation project(':library') +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/src/main/kotlin/App.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/src/main/kotlin/App.kt new file mode 100755 index 00000000000..a74820c7783 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/app/src/main/kotlin/App.kt @@ -0,0 +1,6 @@ +package com.example + +fun app() { + GeneratedSomeClass + println(StringFactory.generateString()) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/build.gradle new file mode 100755 index 00000000000..17bd6a55884 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/build.gradle @@ -0,0 +1,10 @@ +subprojects { + repositories { + mavenLocal() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/build.gradle new file mode 100755 index 00000000000..56b62020636 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/build.gradle @@ -0,0 +1,10 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' + id 'org.jetbrains.kotlin.kapt' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation project(':api') + kapt project(':processor') +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/src/main/kotlin/Library.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/src/main/kotlin/Library.kt new file mode 100755 index 00000000000..3e4cc12d048 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/library/src/main/kotlin/Library.kt @@ -0,0 +1,13 @@ +package com.example + +@SomeAnnotation +object SomeClass { + init { + println(StringFactory.generateString()) + } +} + +fun library() { + GeneratedSomeClass + println(StringFactory.generateString()) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/build.gradle new file mode 100755 index 00000000000..89a6d4a7ef1 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/build.gradle @@ -0,0 +1,11 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' + id 'org.jetbrains.kotlin.kapt' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'com.google.auto.service:auto-service:1.0-rc3' + kapt 'com.google.auto.service:auto-service:1.0-rc3' + implementation project(':api') +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/src/main/kotlin/Processor.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/src/main/kotlin/Processor.kt new file mode 100755 index 00000000000..d9499ef6527 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/src/main/kotlin/Processor.kt @@ -0,0 +1,58 @@ +package com.example + +import com.google.auto.service.AutoService +import org.intellij.lang.annotations.Language +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.ProcessingEnvironment +import javax.annotation.processing.Processor +import javax.annotation.processing.RoundEnvironment +import javax.lang.model.element.TypeElement +import javax.tools.Diagnostic +import javax.tools.Diagnostic.Kind.MANDATORY_WARNING +import javax.tools.StandardLocation + +@AutoService(Processor::class) +class Processor : AbstractProcessor() { + + override fun getSupportedAnnotationTypes() = setOf(SomeAnnotation::class.java.canonicalName) + + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + if (annotations.isNotEmpty()) { + processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "Writing StringFactory") + processingEnv.filer.createClassFile("com.example.StringFactory", *annotations.toTypedArray()) + .openOutputStream() + .use { output -> + javaClass.classLoader.getResourceAsStream("StringFactory.class")!! + .use { it.copyTo(output) } + } + } + + for (element in roundEnv.getElementsAnnotatedWith(SomeAnnotation::class.java)) { + val packageName = processingEnv.elementUtils.getPackageOf(element).qualifiedName + val name = "Generated${element.simpleName}" + val file = processingEnv.filer.createResource( + StandardLocation.SOURCE_OUTPUT, + packageName, + "$name.kt", + element + ) + processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "Writing $name") + file.openWriter().use { writer -> + writer.write( + //language=kotlin + """ + package $packageName + + object $name { + init { + println(StringFactory.generateString()) + } + } + """.trimIndent() + ) + } + } + + return true + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/src/main/resources/StringFactory.class b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/processor/src/main/resources/StringFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..0111d04c7311970562bd5ae1d65a323210618df9 GIT binary patch literal 304 zcmZ9G&q@O^5XQgRc6aMq+giMccyB$p=+)vyC?1L)D&Di}u%u)Y390B?=}GY51Nczl z#1;f6Fn@mY%}2hzKRyARW4}Nbdp!(t40DVK*-TpftSH++Yk;W)5S_XsnRIhlpA_MD3)&RYo6Nnx4Fa-lQS)B*!)6 ZWJg{heUu*kGNI$-^`9`6)vmAv{U702JBt7S literal 0 HcmV?d00001 diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/settings.gradle new file mode 100755 index 00000000000..cefd6c87f38 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/kt33847/settings.gradle @@ -0,0 +1,5 @@ +rootProject.name = 'kapt3-issues' +include ':api' +include ':processor' +include ':library' +include ':app' diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 6cecf5555ad..0dd803c8d70 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -384,8 +384,11 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To kotlinCompilation.output.classesDirs.from(taskProvider.flatMap { it.classesDir }) - kotlinCompilation.compileKotlinTaskProvider.configure { - (it as AbstractKotlinCompileTool<*>).setSource(sourcesOutputDir, kotlinSourcesOutputDir) + kotlinCompilation.compileTaskProvider.configure { task -> + with(task as AbstractKotlinCompile<*>) { + setSource(sourcesOutputDir, kotlinSourcesOutputDir) + libraries.from(classesOutputDir) + } } } taskConfigAction.configureTask { task -> @@ -424,7 +427,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To val kaptTaskName = getKaptTaskName("kaptGenerateStubs") val kaptTaskProvider = project.registerTask(kaptTaskName) - val taskConfig = KaptGenerateStubsConfig(kotlinCompilation, kotlinCompile) + val taskConfig = KaptGenerateStubsConfig(kotlinCompilation, kotlinCompile, classesOutputDir) taskConfig.configureTask { it.stubsDir.set(getKaptStubsDir()) it.destinationDirectory.set(getKaptIncrementalDataDir()) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt index 9da702b6d1f..3f375d38e9d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt @@ -63,7 +63,7 @@ internal open class KaptConfig( internal constructor(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : this(kotlinCompileTask.project, ext) { configureTask { task -> - task.classpath.from(kotlinCompileTask.libraries) + task.classpath.from(kotlinCompileTask.libraries - project.files(task.classesDir)) task.compiledSources.from( kotlinCompileTask.destinationDirectory, Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } }) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt index a9b86b59a5e..40045dd9067 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt @@ -31,13 +31,17 @@ import java.util.concurrent.ConcurrentHashMap internal class KaptGenerateStubsConfig : BaseKotlinCompileConfig { - constructor(compilation: KotlinCompilationData<*>, kotlinTaskProvider: TaskProvider) : super(compilation) { + constructor( + compilation: KotlinCompilationData<*>, + kotlinTaskProvider: TaskProvider, + kaptClassesDir: File, + ) : super(compilation) { configureFromExtension(project.extensions.getByType(KaptExtension::class.java)) configureTask { task -> val kotlinCompileTask = kotlinTaskProvider.get() task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges() task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges() - task.libraries.from({ kotlinCompileTask.libraries }) + task.libraries.from({ kotlinCompileTask.libraries - project.files(kaptClassesDir) }) task.compileKotlinArgumentsContributor.set(providers.provider { kotlinCompileTask.compilerArgumentsContributor }) task.pluginOptions.addAll(kotlinCompileTask.pluginOptions) // KotlinCompile will also have as input output from KaptGenerateStubTask and KaptTask