Skip to content

Commit d59b9e7

Browse files
Fix annotation processors outputting to classes dir with kapt 3
#KT-15915 fixed Annotation processor can access a classes directory provided by AP environment. Previously kapt 3 was using kotlin-classes directory as a a classes directory. However compileKotlin task does not expect this. Also having multiple tasks with the same output dir is a bad practise in Gradle. This change introduces a separate directory for classes generated by kapt 3. Its output is copied to a resulting classes dir (just as a kotlin-classes dir).
1 parent 10079ce commit d59b9e7

File tree

13 files changed

+149
-18
lines changed

13 files changed

+149
-18
lines changed

libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,26 @@ class Kapt3IT : BaseGradleIT() {
270270
assertCompiledKotlinSources(project.relativize(allMainKotlinSrc))
271271
}
272272
}
273+
274+
@Test
275+
fun testKaptClassesDirSync() {
276+
val project = Project("autoService", GRADLE_VERSION, directoryPrefix = "kapt2")
277+
278+
project.build("build") {
279+
assertSuccessful()
280+
assertKaptSuccessful()
281+
assertFileExists("processor/build/classes/main/META-INF/services/javax.annotation.processing.Processor")
282+
assertFileExists("processor/build/classes/main/processor/MyProcessor.class")
283+
}
284+
285+
project.projectDir.getFileByName("MyProcessor.kt").modify {
286+
it.replace("@AutoService(Processor::class)", "")
287+
}
288+
289+
project.build(":processor:build") {
290+
assertSuccessful()
291+
assertNoSuchFile("processor/build/classes/main/META-INF/services/javax.annotation.processing.Processor")
292+
assertFileExists("processor/build/classes/main/processor/MyProcessor.class")
293+
}
294+
}
273295
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
buildscript {
2+
repositories {
3+
mavenLocal()
4+
mavenCentral()
5+
}
6+
dependencies {
7+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
8+
}
9+
}
10+
11+
apply plugin: 'kotlin-kapt'
12+
apply plugin: 'kotlin'
13+
14+
allprojects {
15+
repositories {
16+
mavenLocal()
17+
mavenCentral()
18+
}
19+
}
20+
21+
dependencies {
22+
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
23+
compile project(":processor")
24+
kapt project(":processor")
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apply plugin: 'kotlin-kapt'
2+
apply plugin: 'kotlin'
3+
4+
dependencies {
5+
ext.autoServiceVersion = '1.0-rc2'
6+
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
7+
compile "com.google.auto.service:auto-service:$autoServiceVersion"
8+
kapt "com.google.auto.service:auto-service:$autoServiceVersion"
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package processor
2+
3+
import com.google.auto.service.AutoService
4+
import javax.annotation.processing.*
5+
import javax.lang.model.SourceVersion
6+
import javax.lang.model.element.TypeElement
7+
import javax.tools.Diagnostic
8+
9+
@AutoService(Processor::class)
10+
@SupportedAnnotationTypes("annotation.ProcessThis")
11+
@SupportedSourceVersion(SourceVersion.RELEASE_8)
12+
class MyProcessor() : AbstractProcessor() {
13+
14+
private var fileCreated = false
15+
16+
override fun process(annotations: Set<TypeElement>,
17+
roundEnv: RoundEnvironment): Boolean {
18+
processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "Working!")
19+
if (fileCreated) return true
20+
fileCreated = true
21+
val file = processingEnv.filer.createSourceFile("Check")
22+
file.openWriter().use {
23+
it.appendln("// $annotations")
24+
it.appendln("public class Check {}")
25+
}
26+
return true
27+
}
28+
}

libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/autoService/settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rootProject.name = 'kaptbug'include 'processor'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package annotation
2+
3+
annotation class ProcessThis
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package model
2+
3+
import annotation.ProcessThis
4+
5+
@ProcessThis
6+
interface Model {
7+
8+
var a: Int
9+
10+
var b: Int
11+
}
12+
13+
@ProcessThis
14+
class Class {
15+
16+
var a = 0
17+
}

libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,6 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil
6060
): ExitCode {
6161
val outputDir = args.destinationAsFile
6262

63-
if (environment !is GradleIncrementalCompilerEnvironment) {
64-
log.debug("Removing all kotlin classes in $outputDir")
65-
// we're free to delete all classes since only we know about that directory
66-
outputDir.deleteRecursively()
67-
}
68-
6963
val moduleFile = makeModuleFile(
7064
args.moduleName,
7165
isTest = false,

libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.gradle.api.tasks.compile.JavaCompile
2929
import org.jetbrains.kotlin.gradle.plugin.*
3030
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
3131
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
32+
import org.jetbrains.kotlin.gradle.tasks.SyncOutputTask
3233
import java.io.File
3334

3435
// apply plugin: 'kotlin-kapt'
@@ -59,6 +60,9 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
5960
}
6061

6162
fun findMainKaptConfiguration(project: Project) = project.findKaptConfiguration(MAIN_KAPT_CONFIGURATION_NAME)
63+
64+
fun getKaptClasssesDir(project: Project, sourceSetName: String): File =
65+
File(project.project.buildDir, "tmp/kapt3/classes/$sourceSetName")
6266
}
6367

6468
private val kotlinToKaptTasksMap = mutableMapOf<KotlinCompile, KaptTask>()
@@ -156,7 +160,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
156160
javaCompile.source(generatedFilesDir)
157161

158162
pluginOptions += SubpluginOption("sources", generatedFilesDir.canonicalPath)
159-
pluginOptions += SubpluginOption("classes", kotlinCompile.destinationDir.canonicalPath)
163+
pluginOptions += SubpluginOption("classes", getKaptClasssesDir(project, sourceSetName).canonicalPath)
160164

161165
val androidPlugin = variantData?.let {
162166
project.extensions.findByName("android") as? BaseExtension
@@ -193,6 +197,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
193197

194198
private fun Kapt3SubpluginContext.createKaptKotlinTask() {
195199
val sourcesOutputDir = getKaptGeneratedDir(project, sourceSetName)
200+
val classesOutputDir = getKaptClasssesDir(project, sourceSetName)
196201

197202
// Replace compile*Kotlin to kapt*Kotlin
198203
assert(kotlinCompile.name.startsWith("compile"))
@@ -207,6 +212,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
207212

208213
kaptTask.mapClasspath { kotlinCompile.classpath }
209214
kaptTask.destinationDir = sourcesOutputDir
215+
kaptTask.classesDir = classesOutputDir
210216
kaptTask.dependsOn(*(javaCompile.dependsOn.filter { it !== kotlinCompile }.toTypedArray()))
211217
kotlinCompile.dependsOn(kaptTask)
212218

libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,17 @@ open class KaptTask : AbstractCompile() {
3939
return FileUtil.isAncestor(destinationDir, this, /* strict = */ false)
4040
}
4141

42+
lateinit var classesDir: File
43+
4244
@TaskAction
4345
override fun compile() {
4446
/** Delete everything inside the [destinationDir] */
4547
destinationDir.deleteRecursively()
4648
destinationDir.mkdirs()
4749

50+
classesDir.deleteRecursively()
51+
classesDir.mkdirs()
52+
4853
val sourceRoots = SourceRoots.ForJvm.create(getSource(), rawSourceRoots)
4954
val compileClasspath = classpath.toList().filter(File::exists)
5055

libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ import org.gradle.api.tasks.bundling.Zip
2121
import org.gradle.api.tasks.compile.AbstractCompile
2222
import org.gradle.api.tasks.compile.JavaCompile
2323
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
24-
import org.jetbrains.kotlin.gradle.internal.AnnotationProcessingManager
25-
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
26-
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin
27-
import org.jetbrains.kotlin.gradle.internal.initKapt
24+
import org.jetbrains.kotlin.gradle.internal.*
25+
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.getKaptClasssesDir
2826
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
2927
import org.jetbrains.kotlin.gradle.plugin.android.KotlinJillTask
3028
import org.jetbrains.kotlin.gradle.tasks.*
3129
import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation
3230
import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryProviderAndroidWrapper
31+
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
32+
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
3333
import java.io.File
3434
import java.net.URL
3535
import java.util.*
@@ -540,6 +540,7 @@ private fun createSyncOutputTask(
540540
syncTask.kotlinTask = kotlinCompile
541541
kotlinTask.javaOutputDir = javaDir
542542
kotlinAfterJavaTask?.javaOutputDir = javaDir
543+
syncTask.kaptClassesDir = getKaptClasssesDir(project, variantName)
543544

544545
// copying should be executed after a latter task
545546
val previousTask = kotlinAfterJavaTask ?: javaTask

libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SyncOutputTask.kt

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616

1717
package org.jetbrains.kotlin.gradle.tasks
1818

19+
import ch.qos.logback.core.util.FileUtil
1920
import org.gradle.api.DefaultTask
2021
import org.gradle.api.tasks.InputFiles
2122
import org.gradle.api.tasks.OutputDirectory
2223
import org.gradle.api.tasks.OutputFiles
2324
import org.gradle.api.tasks.TaskAction
2425
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
2526
import org.gradle.api.tasks.incremental.InputFileDetails
27+
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil.*
2628
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
2729
import java.io.File
2830
import java.io.ObjectInputStream
@@ -55,6 +57,13 @@ import kotlin.properties.Delegates
5557
internal open class SyncOutputTask : DefaultTask() {
5658
@get:InputFiles
5759
var kotlinOutputDir: File by Delegates.notNull()
60+
61+
@get:InputFiles
62+
var kaptClassesDir: File by Delegates.notNull()
63+
64+
private val classesDirs: List<File>
65+
get() = listOf(kotlinOutputDir, kaptClassesDir).filter(File::exists)
66+
5867
var javaOutputDir: File by Delegates.notNull()
5968
var kotlinTask: KotlinCompile by Delegates.notNull()
6069

@@ -78,13 +87,14 @@ internal open class SyncOutputTask : DefaultTask() {
7887
@Suppress("unused")
7988
@TaskAction
8089
fun execute(inputs: IncrementalTaskInputs): Unit {
90+
val sourceDirs = classesDirs.joinToString()
8191
if (inputs.isIncremental) {
82-
logger.kotlinDebug { "Incremental copying files from $kotlinOutputDir to $javaOutputDir" }
92+
logger.kotlinDebug { "Incremental copying files from $sourceDirs to $javaOutputDir" }
8393
inputs.outOfDate { processIncrementally(it) }
8494
inputs.removed { processIncrementally(it) }
8595
}
8696
else {
87-
logger.kotlinDebug { "Non-incremental copying files from $kotlinOutputDir to $javaOutputDir" }
97+
logger.kotlinDebug { "Non-incremental copying files from $sourceDirs to $javaOutputDir" }
8898
processNonIncrementally()
8999
}
90100

@@ -103,14 +113,16 @@ internal open class SyncOutputTask : DefaultTask() {
103113
timestampsFile.delete()
104114
timestamps.clear()
105115

106-
kotlinOutputDir.walkTopDown().forEach {
107-
copy(it, it.siblingInJavaDir)
116+
for (dir in classesDirs) {
117+
dir.walkTopDown().forEach {
118+
copy(it, it.siblingInJavaDir(baseDir = dir))
119+
}
108120
}
109121
}
110122

111123
private fun processIncrementally(input: InputFileDetails) {
112124
val fileInKotlinDir = input.file
113-
val fileInJavaDir = fileInKotlinDir.siblingInJavaDir
125+
val fileInJavaDir = fileInKotlinDir.siblingInJavaDir()
114126

115127
if (input.isRemoved) {
116128
// file was removed in kotlin dir, remove from java as well
@@ -146,8 +158,10 @@ internal open class SyncOutputTask : DefaultTask() {
146158
}
147159
}
148160

149-
private val File.siblingInJavaDir: File
150-
get() = File(javaOutputDir, this.relativeTo(kotlinOutputDir).path)
161+
private fun File.siblingInJavaDir(baseDir: File? = null): File {
162+
val base = baseDir ?: classesDirs.find { isAncestor(it, this, true) }!!
163+
return File(javaOutputDir, this.relativeTo(base).path)
164+
}
151165
}
152166

153167
private val TIMESTAMP_FILE_NAME = "kotlin-files-in-java-timestamps.bin"

libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
231231
}
232232
}
233233

234+
if (!incremental) {
235+
logger.kotlinDebug { "Removing all kotlin classes in $destinationDir" }
236+
destinationDir.deleteRecursively()
237+
destinationDir.mkdirs()
238+
}
239+
234240
try {
235241
val exitCode = compilerRunner.runJvmCompiler(sourceRoots.kotlinSourceFiles, sourceRoots.javaSourceRoots, args, environment)
236242
processCompilerExitCode(exitCode)

0 commit comments

Comments
 (0)