Kapt: Do not use AbstractCompile as a supertype for KaptTask (KT-19179)

Gradle sometimes tells that kaptCompile is UP-TO-DATE even when it's not true, so the annotation processing step is silently skipped.
Looks like replacing `mapSource {}` with an explicit getter or with manual `source()` invocation does not fix the problem.

This looks like a bug in Gradle appeared since 3.0. The test from this commit works with Gradle 2.14.1.
This commit is contained in:
Yan Zhulanow
2017-07-21 20:24:29 +03:00
parent 53fda33499
commit 725f51056f
12 changed files with 148 additions and 23 deletions
@@ -1,8 +1,10 @@
package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.util.getFileByName
import org.jetbrains.kotlin.gradle.util.modify
import org.junit.Test
import java.io.File
import java.util.zip.ZipFile
class KotlinGradlePluginMultiVersionIT : BaseMultiGradleVersionIT() {
@Test
@@ -18,6 +20,48 @@ class KotlinGradlePluginMultiVersionIT : BaseMultiGradleVersionIT() {
}
}
@Test
fun testKt19179() {
val project = Project("kt19179", gradleVersion, directoryPrefix = "kapt2")
project.build("build") {
assertSuccessful()
assertFileExists("processor/build/tmp/kapt3/classes/main/META-INF/services/javax.annotation.processing.Processor")
val processorJar = fileInWorkingDir("processor/build/libs/processor.jar")
assert(processorJar.exists())
ZipFile(processorJar).use { zip ->
assert(zip.getEntry("META-INF/services/javax.annotation.processing.Processor") != null)
}
assertTasksExecuted(listOf(
":processor:kaptGenerateStubsKotlin", ":processor:kaptKotlin",
":app:kaptGenerateStubsKotlin", ":app:kaptKotlin"))
}
project.projectDir.getFileByName("Test.kt").modify { text ->
assert("SomeClass()" in text)
text.replace("SomeClass()", "SomeClass(); val a = 5")
}
project.build("build") {
assertSuccessful()
assertTasksUpToDate(listOf(":processor:kaptGenerateStubsKotlin", ":processor:kaptKotlin", ":app:kaptKotlin"))
assertTasksExecuted(listOf(":app:kaptGenerateStubsKotlin"))
}
project.projectDir.getFileByName("Test.kt").modify { text ->
text + "\n\nfun t() {}"
}
project.build("build") {
assertSuccessful()
assertTasksUpToDate(listOf(":processor:kaptGenerateStubsKotlin", ":processor:kaptKotlin"))
assertTasksExecuted(listOf(":app:kaptGenerateStubsKotlin", ":app:kaptKotlin"))
}
}
@Test
fun testJavaIcCompatibility() {
val version = gradleVersion.split(".").map(String::toInt)
@@ -0,0 +1,5 @@
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-runtime:$kotlin_version"
}
@@ -0,0 +1,6 @@
package com.example
import kotlin.annotation.AnnotationTarget.CLASS
@Target(CLASS)
annotation class SomeAnnotation
@@ -0,0 +1,8 @@
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile project(':api')
kapt project(':processor')
}
@@ -0,0 +1,7 @@
package com.example
@SomeAnnotation class SomeClass
fun main(vararg args: String) {
SomeClass()
}
@@ -0,0 +1,20 @@
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
subprojects {
repositories {
mavenLocal()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
@@ -0,0 +1,9 @@
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'com.google.auto.service:auto-service:1.0-rc3'
kapt 'com.google.auto.service:auto-service:1.0-rc3'
compile project(':api')
}
@@ -0,0 +1,19 @@
package com.example
import com.google.auto.service.AutoService
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.Processor
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.TypeElement
import javax.tools.Diagnostic.Kind.MANDATORY_WARNING
@AutoService(Processor::class)
class Processor : AbstractProcessor() {
override fun getSupportedAnnotationTypes() = setOf(SomeAnnotation::class.java.canonicalName)
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
processingEnv.messager.printMessage(MANDATORY_WARNING, "*** AP RUNNING ***' ")
return true
}
}
@@ -0,0 +1,4 @@
rootProject.name = 'kapt3-issues'
include ':app'
include ':api'
include ':processor'
@@ -281,19 +281,8 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
kaptTask.stubsDir = getKaptStubsDir()
kaptTask.destinationDir = sourcesOutputDir
kaptTask.mapClasspath { kotlinCompile.classpath }
kaptTask.classesDir = classesOutputDir
kaptTask.mapSource {
val sourcesFromKotlinTask = kotlinCompile.source
.filter { it.extension == "java" && !kaptTask.isInsideDestinationDirs(it) }
.asFileTree
val stubSources = project.fileTree(kaptTask.stubsDir)
sourcesFromKotlinTask + stubSources
}
kotlinCompile.source(sourcesOutputDir, kotlinSourcesOutputDir)
if (kaptVariantData != null) {
@@ -1,8 +1,9 @@
package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.GradleException
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.ConventionTask
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
@@ -11,20 +12,37 @@ import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.gradle.tasks.*
import java.io.File
open class KaptTask : AbstractCompile() {
open class KaptTask : ConventionTask() {
internal val pluginOptions = CompilerPluginOptions()
internal lateinit var kotlinCompileTask: KotlinCompile
fun isInsideDestinationDirs(file: File): Boolean {
internal lateinit var kotlinCompileTask: KotlinCompile
internal lateinit var stubsDir: File
private fun isInsideDestinationDirs(file: File): Boolean {
return FileUtil.isAncestor(destinationDir, file, /* strict = */ false)
|| FileUtil.isAncestor(classesDir, file, /* strict = */ false)
}
lateinit var classesDir: File
lateinit var stubsDir: File
@OutputDirectory
internal lateinit var classesDir: File
@OutputDirectory
lateinit var destinationDir: File
val classpath: FileCollection
@InputFiles get() = kotlinCompileTask.classpath
val source: FileCollection
@InputFiles get() {
val sourcesFromKotlinTask = kotlinCompileTask.source
.filter { it.extension == "java" && !isInsideDestinationDirs(it) }
val stubSources = project.fileTree(stubsDir)
return sourcesFromKotlinTask + stubSources
}
@TaskAction
override fun compile() {
fun compile() {
/** Delete everything inside generated sources and classes output directory
* (annotation processing is not incremental) */
destinationDir.clearDirectory()
@@ -51,10 +51,6 @@ fun AbstractCompile.mapClasspath(fn: () -> FileCollection) {
conventionMapping.map("classpath", fn)
}
internal fun AbstractCompile.mapSource(fn: () -> FileTree) {
conventionMapping.map("source", fn)
}
internal inline fun <reified T : Any> Any.addConvention(name: String, plugin: T) {
(this as HasConvention).convention.plugins[name] = plugin
}