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).
This commit is contained in:
+22
@@ -270,4 +270,26 @@ class Kapt3IT : BaseGradleIT() {
|
||||
assertCompiledKotlinSources(project.relativize(allMainKotlinSrc))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKaptClassesDirSync() {
|
||||
val project = Project("autoService", GRADLE_VERSION, directoryPrefix = "kapt2")
|
||||
|
||||
project.build("build") {
|
||||
assertSuccessful()
|
||||
assertKaptSuccessful()
|
||||
assertFileExists("processor/build/classes/main/META-INF/services/javax.annotation.processing.Processor")
|
||||
assertFileExists("processor/build/classes/main/processor/MyProcessor.class")
|
||||
}
|
||||
|
||||
project.projectDir.getFileByName("MyProcessor.kt").modify {
|
||||
it.replace("@AutoService(Processor::class)", "")
|
||||
}
|
||||
|
||||
project.build(":processor:build") {
|
||||
assertSuccessful()
|
||||
assertNoSuchFile("processor/build/classes/main/META-INF/services/javax.annotation.processing.Processor")
|
||||
assertFileExists("processor/build/classes/main/processor/MyProcessor.class")
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile project(":processor")
|
||||
kapt project(":processor")
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
dependencies {
|
||||
ext.autoServiceVersion = '1.0-rc2'
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile "com.google.auto.service:auto-service:$autoServiceVersion"
|
||||
kapt "com.google.auto.service:auto-service:$autoServiceVersion"
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package processor
|
||||
|
||||
import com.google.auto.service.AutoService
|
||||
import javax.annotation.processing.*
|
||||
import javax.lang.model.SourceVersion
|
||||
import javax.lang.model.element.TypeElement
|
||||
import javax.tools.Diagnostic
|
||||
|
||||
@AutoService(Processor::class)
|
||||
@SupportedAnnotationTypes("annotation.ProcessThis")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||
class MyProcessor() : AbstractProcessor() {
|
||||
|
||||
private var fileCreated = false
|
||||
|
||||
override fun process(annotations: Set<TypeElement>,
|
||||
roundEnv: RoundEnvironment): Boolean {
|
||||
processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "Working!")
|
||||
if (fileCreated) return true
|
||||
fileCreated = true
|
||||
val file = processingEnv.filer.createSourceFile("Check")
|
||||
file.openWriter().use {
|
||||
it.appendln("// $annotations")
|
||||
it.appendln("public class Check {}")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
rootProject.name = 'kaptbug'
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package annotation
|
||||
|
||||
annotation class ProcessThis
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
import annotation.ProcessThis
|
||||
|
||||
@ProcessThis
|
||||
interface Model {
|
||||
|
||||
var a: Int
|
||||
|
||||
var b: Int
|
||||
}
|
||||
|
||||
@ProcessThis
|
||||
class Class {
|
||||
|
||||
var a = 0
|
||||
}
|
||||
-6
@@ -60,12 +60,6 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil
|
||||
): ExitCode {
|
||||
val outputDir = args.destinationAsFile
|
||||
|
||||
if (environment !is GradleIncrementalCompilerEnvironment) {
|
||||
log.debug("Removing all kotlin classes in $outputDir")
|
||||
// we're free to delete all classes since only we know about that directory
|
||||
outputDir.deleteRecursively()
|
||||
}
|
||||
|
||||
val moduleFile = makeModuleFile(
|
||||
args.moduleName,
|
||||
isTest = false,
|
||||
|
||||
+7
-1
@@ -29,6 +29,7 @@ import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.SyncOutputTask
|
||||
import java.io.File
|
||||
|
||||
// apply plugin: 'kotlin-kapt'
|
||||
@@ -59,6 +60,9 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
||||
}
|
||||
|
||||
fun findMainKaptConfiguration(project: Project) = project.findKaptConfiguration(MAIN_KAPT_CONFIGURATION_NAME)
|
||||
|
||||
fun getKaptClasssesDir(project: Project, sourceSetName: String): File =
|
||||
File(project.project.buildDir, "tmp/kapt3/classes/$sourceSetName")
|
||||
}
|
||||
|
||||
private val kotlinToKaptTasksMap = mutableMapOf<KotlinCompile, KaptTask>()
|
||||
@@ -156,7 +160,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
||||
javaCompile.source(generatedFilesDir)
|
||||
|
||||
pluginOptions += SubpluginOption("sources", generatedFilesDir.canonicalPath)
|
||||
pluginOptions += SubpluginOption("classes", kotlinCompile.destinationDir.canonicalPath)
|
||||
pluginOptions += SubpluginOption("classes", getKaptClasssesDir(project, sourceSetName).canonicalPath)
|
||||
|
||||
val androidPlugin = variantData?.let {
|
||||
project.extensions.findByName("android") as? BaseExtension
|
||||
@@ -193,6 +197,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
||||
|
||||
private fun Kapt3SubpluginContext.createKaptKotlinTask() {
|
||||
val sourcesOutputDir = getKaptGeneratedDir(project, sourceSetName)
|
||||
val classesOutputDir = getKaptClasssesDir(project, sourceSetName)
|
||||
|
||||
// Replace compile*Kotlin to kapt*Kotlin
|
||||
assert(kotlinCompile.name.startsWith("compile"))
|
||||
@@ -207,6 +212,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
||||
|
||||
kaptTask.mapClasspath { kotlinCompile.classpath }
|
||||
kaptTask.destinationDir = sourcesOutputDir
|
||||
kaptTask.classesDir = classesOutputDir
|
||||
kaptTask.dependsOn(*(javaCompile.dependsOn.filter { it !== kotlinCompile }.toTypedArray()))
|
||||
kotlinCompile.dependsOn(kaptTask)
|
||||
|
||||
|
||||
+5
@@ -39,12 +39,17 @@ open class KaptTask : AbstractCompile() {
|
||||
return FileUtil.isAncestor(destinationDir, this, /* strict = */ false)
|
||||
}
|
||||
|
||||
lateinit var classesDir: File
|
||||
|
||||
@TaskAction
|
||||
override fun compile() {
|
||||
/** Delete everything inside the [destinationDir] */
|
||||
destinationDir.deleteRecursively()
|
||||
destinationDir.mkdirs()
|
||||
|
||||
classesDir.deleteRecursively()
|
||||
classesDir.mkdirs()
|
||||
|
||||
val sourceRoots = SourceRoots.ForJvm.create(getSource(), rawSourceRoots)
|
||||
val compileClasspath = classpath.toList().filter(File::exists)
|
||||
|
||||
|
||||
+5
-4
@@ -21,15 +21,15 @@ import org.gradle.api.tasks.bundling.Zip
|
||||
import org.gradle.api.tasks.compile.AbstractCompile
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
|
||||
import org.jetbrains.kotlin.gradle.internal.AnnotationProcessingManager
|
||||
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
|
||||
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin
|
||||
import org.jetbrains.kotlin.gradle.internal.initKapt
|
||||
import org.jetbrains.kotlin.gradle.internal.*
|
||||
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.getKaptClasssesDir
|
||||
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
||||
import org.jetbrains.kotlin.gradle.plugin.android.KotlinJillTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryProviderAndroidWrapper
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
@@ -540,6 +540,7 @@ private fun createSyncOutputTask(
|
||||
syncTask.kotlinTask = kotlinCompile
|
||||
kotlinTask.javaOutputDir = javaDir
|
||||
kotlinAfterJavaTask?.javaOutputDir = javaDir
|
||||
syncTask.kaptClassesDir = getKaptClasssesDir(project, variantName)
|
||||
|
||||
// copying should be executed after a latter task
|
||||
val previousTask = kotlinAfterJavaTask ?: javaTask
|
||||
|
||||
+21
-7
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import ch.qos.logback.core.util.FileUtil
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
@@ -23,6 +24,7 @@ import org.gradle.api.tasks.OutputFiles
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
|
||||
import org.gradle.api.tasks.incremental.InputFileDetails
|
||||
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
|
||||
import java.io.File
|
||||
import java.io.ObjectInputStream
|
||||
@@ -55,6 +57,13 @@ import kotlin.properties.Delegates
|
||||
internal open class SyncOutputTask : DefaultTask() {
|
||||
@get:InputFiles
|
||||
var kotlinOutputDir: File by Delegates.notNull()
|
||||
|
||||
@get:InputFiles
|
||||
var kaptClassesDir: File by Delegates.notNull()
|
||||
|
||||
private val classesDirs: List<File>
|
||||
get() = listOf(kotlinOutputDir, kaptClassesDir).filter(File::exists)
|
||||
|
||||
var javaOutputDir: File by Delegates.notNull()
|
||||
var kotlinTask: KotlinCompile by Delegates.notNull()
|
||||
|
||||
@@ -78,13 +87,14 @@ internal open class SyncOutputTask : DefaultTask() {
|
||||
@Suppress("unused")
|
||||
@TaskAction
|
||||
fun execute(inputs: IncrementalTaskInputs): Unit {
|
||||
val sourceDirs = classesDirs.joinToString()
|
||||
if (inputs.isIncremental) {
|
||||
logger.kotlinDebug { "Incremental copying files from $kotlinOutputDir to $javaOutputDir" }
|
||||
logger.kotlinDebug { "Incremental copying files from $sourceDirs to $javaOutputDir" }
|
||||
inputs.outOfDate { processIncrementally(it) }
|
||||
inputs.removed { processIncrementally(it) }
|
||||
}
|
||||
else {
|
||||
logger.kotlinDebug { "Non-incremental copying files from $kotlinOutputDir to $javaOutputDir" }
|
||||
logger.kotlinDebug { "Non-incremental copying files from $sourceDirs to $javaOutputDir" }
|
||||
processNonIncrementally()
|
||||
}
|
||||
|
||||
@@ -103,14 +113,16 @@ internal open class SyncOutputTask : DefaultTask() {
|
||||
timestampsFile.delete()
|
||||
timestamps.clear()
|
||||
|
||||
kotlinOutputDir.walkTopDown().forEach {
|
||||
copy(it, it.siblingInJavaDir)
|
||||
for (dir in classesDirs) {
|
||||
dir.walkTopDown().forEach {
|
||||
copy(it, it.siblingInJavaDir(baseDir = dir))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processIncrementally(input: InputFileDetails) {
|
||||
val fileInKotlinDir = input.file
|
||||
val fileInJavaDir = fileInKotlinDir.siblingInJavaDir
|
||||
val fileInJavaDir = fileInKotlinDir.siblingInJavaDir()
|
||||
|
||||
if (input.isRemoved) {
|
||||
// file was removed in kotlin dir, remove from java as well
|
||||
@@ -146,8 +158,10 @@ internal open class SyncOutputTask : DefaultTask() {
|
||||
}
|
||||
}
|
||||
|
||||
private val File.siblingInJavaDir: File
|
||||
get() = File(javaOutputDir, this.relativeTo(kotlinOutputDir).path)
|
||||
private fun File.siblingInJavaDir(baseDir: File? = null): File {
|
||||
val base = baseDir ?: classesDirs.find { isAncestor(it, this, true) }!!
|
||||
return File(javaOutputDir, this.relativeTo(base).path)
|
||||
}
|
||||
}
|
||||
|
||||
private val TIMESTAMP_FILE_NAME = "kotlin-files-in-java-timestamps.bin"
|
||||
|
||||
+6
@@ -231,6 +231,12 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
}
|
||||
}
|
||||
|
||||
if (!incremental) {
|
||||
logger.kotlinDebug { "Removing all kotlin classes in $destinationDir" }
|
||||
destinationDir.deleteRecursively()
|
||||
destinationDir.mkdirs()
|
||||
}
|
||||
|
||||
try {
|
||||
val exitCode = compilerRunner.runJvmCompiler(sourceRoots.kotlinSourceFiles, sourceRoots.javaSourceRoots, args, environment)
|
||||
processCompilerExitCode(exitCode)
|
||||
|
||||
Reference in New Issue
Block a user