From 695f202e468c7640a7aa007c62ca36895c28295f Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Tue, 28 May 2019 17:19:26 +0100 Subject: [PATCH] KT-31127: add only generated Java sources to JavaCompile inputs This commit changes how generated sources are added to the Gradle JavaCompile task. Previously, directory was added to sources which caused issues with annotation processors that only generate Kotlin sources. I.e. JavaCompile task was executed but no java sources existed. Now, only generated Java sources are added to the JavaCompile task. This means that if only Kotlin sources are generated JavaCompile task will be skipped. Fixes: KT-31127 Test: Kapt3IT.testKotlinProcessorUsingFiler --- .../example/KotlinFilerGeneratingProcessor.kt | 43 +++++++++++++++++++ .../src/main/kotlin/example/annotations.kt | 4 +- .../javax.annotation.processing.Processor | 3 +- .../jetbrains/kotlin/gradle/BaseGradleIT.kt | 6 +++ .../org/jetbrains/kotlin/gradle/Kapt3IT.kt | 29 +++++++++++++ .../kapt/Kapt3KotlinGradleSubplugin.kt | 6 +-- 6 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 libraries/examples/annotation-processor-example/src/main/kotlin/example/KotlinFilerGeneratingProcessor.kt diff --git a/libraries/examples/annotation-processor-example/src/main/kotlin/example/KotlinFilerGeneratingProcessor.kt b/libraries/examples/annotation-processor-example/src/main/kotlin/example/KotlinFilerGeneratingProcessor.kt new file mode 100644 index 00000000000..523f7fb2f33 --- /dev/null +++ b/libraries/examples/annotation-processor-example/src/main/kotlin/example/KotlinFilerGeneratingProcessor.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2019 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 example + +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.RoundEnvironment +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement +import javax.tools.StandardLocation + +/** Annotation processor that users [javax.annotation.processing.Filer] APIs to generate Kotlin sources. */ +class KotlinFilerGeneratingProcessor : AbstractProcessor() { + + override fun process(annotations: MutableSet?, roundEnv: RoundEnvironment): Boolean { + val annotatedWith = roundEnv.getElementsAnnotatedWith(KotlinFilerGenerated::class.java) + + for (element in annotatedWith) { + val packageName = processingEnv.elementUtils.getPackageOf(element).qualifiedName.toString() + val simpleName = element.simpleName.toString() + + processingEnv.filer.createResource(StandardLocation.SOURCE_OUTPUT, packageName, "${simpleName}Generated.kt", element) + .openWriter().use { + it.write( + """ + package $packageName + + class ${simpleName}Generated + """.trimIndent() + ) + } + } + return true + } + + override fun getSupportedSourceVersion() = SourceVersion.RELEASE_6 + + override fun getSupportedAnnotationTypes(): Set { + return setOf(KotlinFilerGenerated::class.java.canonicalName) + } +} \ No newline at end of file diff --git a/libraries/examples/annotation-processor-example/src/main/kotlin/example/annotations.kt b/libraries/examples/annotation-processor-example/src/main/kotlin/example/annotations.kt index 25222c6fc04..b7ccbc84bfa 100644 --- a/libraries/examples/annotation-processor-example/src/main/kotlin/example/annotations.kt +++ b/libraries/examples/annotation-processor-example/src/main/kotlin/example/annotations.kt @@ -17,4 +17,6 @@ annotation class ExampleBinaryAnnotation @Retention(AnnotationRetention.RUNTIME) annotation class ExampleRuntimeAnnotation -annotation class GenError \ No newline at end of file +annotation class GenError + +annotation class KotlinFilerGenerated \ No newline at end of file diff --git a/libraries/examples/annotation-processor-example/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/libraries/examples/annotation-processor-example/src/main/resources/META-INF/services/javax.annotation.processing.Processor index af5b149f6fb..4392f5eafb8 100644 --- a/libraries/examples/annotation-processor-example/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ b/libraries/examples/annotation-processor-example/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -1 +1,2 @@ -example.ExampleAnnotationProcessor \ No newline at end of file +example.ExampleAnnotationProcessor +example.KotlinFilerGeneratingProcessor \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt index 4d04b578ae9..ee03b3a1dd1 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt @@ -517,6 +517,12 @@ abstract class BaseGradleIT { assertTasksNotRealized(*tasks) } + fun CompiledProject.assertTasksSkipped(vararg tasks: String) { + for (task in tasks) { + assertContains("Skipping task '$task'") + } + } + fun CompiledProject.getOutputForTask(taskName: String): String { val taskOutputRegex = ("(?:\\[LIFECYCLE] \\[class org\\.gradle(?:\\.internal\\.buildevents)?\\.TaskExecutionLogger] :$taskName|" + "\\[org\\.gradle\\.execution\\.plan\\.DefaultPlanExecutor\\] :$taskName.*?started)" + 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 4930dab7553..917dea64d45 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 @@ -612,4 +612,33 @@ open class Kapt3IT : Kapt3BaseIT() { assertTasksExecuted(":dac:jdk:kaptGenerateStubsKotlin", ":dac:jdk:compileKotlin") } } + + /** Regression test for KT-31127. */ + @Test + fun testKotlinProcessorUsingFiler() { + val project = Project("kotlinProject").apply { + setupWorkingDir() + gradleBuildScript().appendText(""" + apply plugin: 'kotlin-kapt' + + dependencies { + kapt "org.jetbrains.kotlin:annotation-processor-example:${"$"}kotlin_version" + implementation "org.jetbrains.kotlin:annotation-processor-example:${"$"}kotlin_version" + } + """.trimIndent()) + + // The test must not contain any java sources in order to detect the issue. + Assert.assertEquals(emptyList(), projectDir.allJavaFiles().toList()) + projectDir.getFileByName("Dummy.kt").modify { + it.replace("class Dummy", "@example.KotlinFilerGenerated class Dummy") + } + } + + project.build("build") { + assertSuccessful() + assertFileExists("build/generated/source/kapt/main/demo/DummyGenerated.kt") + assertTasksExecuted(":compileKotlin") + assertTasksSkipped(":compileJava") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 12d25a9d9f9..a2e220f4e2d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -266,8 +266,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { pluginOptions += SubpluginOption("aptMode", aptMode) disableAnnotationProcessingInJavaTask() - javaCompile?.source(generatedFilesDir) - pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName))) @@ -527,7 +525,9 @@ private val artifactType = Attribute.of("artifactType", String::class.java) internal fun registerGeneratedJavaSource(kaptTask: KaptTask, javaTask: AbstractCompile) { - javaTask.source(kaptTask.destinationDir) + val generatedJavaSources = javaTask.project.fileTree(kaptTask.destinationDir) + generatedJavaSources.include("**/*.java") + javaTask.source(generatedJavaSources) } internal fun Configuration.getNamedDependencies(): List = allDependencies.filter { it.group != null && it.name != null }