Java IC compatibility fix for Gradle 2.14+

Added version check to switch between old and new approaches because
Gradle versions before 2.14 have a bug in Java IC.
Added Kotlin classes to Java task input.
Added  annotationsFile into task input to include it into up-to-date check.

Related issues: #KT-16585 Fixed
This commit is contained in:
Jonathan Leitschuh
2017-03-06 14:58:17 -05:00
committed by Sergey Igushkin
parent 9b34e21619
commit cc0ac36fed
4 changed files with 83 additions and 10 deletions
@@ -0,0 +1,17 @@
package org.jetbrains.kotlin.gradle
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameter
import org.junit.runners.Parameterized.Parameters
@RunWith(Parameterized::class)
abstract class BaseMultiGradleVersionIT : BaseGradleIT() {
@Parameter lateinit var gradleVersion: String
companion object {
@JvmStatic
@Parameters(name = "Test with Gradle version {0}")
fun params() = listOf("2.10", "2.14.1", "3.2", "3.3", "3.4").map { arrayOf(it) }
}
}
@@ -109,7 +109,7 @@ class KaptIT: BaseGradleIT() {
private fun doTestIncrementalBuild(projectName: String, compileTasks: Array<String>) {
val compileTasksUpToDate = compileTasks.map { it + " UP-TO-DATE" }.toTypedArray()
val project = Project(projectName, GRADLE_VERSION)
val project = Project(projectName, "2.10")
project.build("build") {
assertSuccessful()
@@ -0,0 +1,49 @@
package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.util.modify
import org.junit.Test
import java.io.File
class KotlinGradlePluginMultiVersionIT : BaseMultiGradleVersionIT() {
@Test
fun testJavaIcCompatibility() {
val version = gradleVersion.split(".").map(String::toInt)
val expectIncrementalCompilation = version.let { (major, minor) -> major > 2 || major == 2 && minor >= 14 }
val expectVerboseIncrementalLogs = version.let { (major, minor) -> major < 3 || major == 3 && minor < 4 }
val project = Project("kotlinJavaProject", gradleVersion)
project.setupWorkingDir()
val buildScript = File(project.projectDir, "build.gradle")
buildScript.modify { "$it\n" + "compileJava.options.incremental = true" }
project.build("build") {
assertSuccessful()
}
// Then modify a Java source and check that compileJava is incremental:
File(project.projectDir, "src/main/java/demo/HelloWorld.java").modify { "$it\n" + "class NewClass { }" }
project.build("build") {
assertSuccessful()
if (expectIncrementalCompilation && expectVerboseIncrementalLogs)
assertContains("Incremental compilation")
if (expectIncrementalCompilation)
assertNotContains("not incremental") else
assertContains("not incremental")
}
// Then modify a Kotlin source and check that Gradle sees that Java is not up-to-date:
File(project.projectDir, "src/main/kotlin/helloWorld.kt").modify {
it.trim('\r', '\n').trimEnd('}') + "\nval z: Int = 0 }"
}
project.build("build") {
assertSuccessful()
assertContains(":compileKotlin")
assertNotContains(":compileJava UP-TO-DATE")
if (expectIncrementalCompilation)
assertNotContains("not incremental") else
assertContains("not incremental")
assertNotContains("None of the classes needs to be compiled!")
}
}
}
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion
import org.jetbrains.kotlin.gradle.internal.initKapt
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.ParsedGradleVersion
import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation
import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryProviderAndroidWrapper
import java.io.File
@@ -520,19 +521,25 @@ internal open class KotlinAndroidPlugin(
}
private fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractCompile, logger: Logger) {
// Since we cannot update classpath statically, java not able to detect changes in the classpath after kotlin compiler.
// Therefore this (probably inefficient since java cannot decide "uptodateness" by the list of changed class files, but told
// explicitly being out of date whenever any kotlin files are compiled
// Gradle Java IC in older Gradle versions (before 2.14) cannot check .class directories updates.
// To make it work, reset the up-to-date status of compileJava with this flag.
kotlinTask.anyClassesCompiled = false
javaTask.outputs.upToDateWhen { task ->
val kotlinClassesCompiled = kotlinTask.anyClassesCompiled
if (kotlinClassesCompiled) {
logger.info("Marking $task out of date, because kotlin classes are changed")
val gradleSupportsJavaIcWithClassesDirs = ParsedGradleVersion.parse(javaTask.project.gradle.gradleVersion)
?.let { it >= ParsedGradleVersion(2, 14) } ?: false
if (!gradleSupportsJavaIcWithClassesDirs) {
javaTask.outputs.upToDateWhen { task ->
if (kotlinTask.anyClassesCompiled) {
logger.info("Marking $task out of date, because kotlin classes are changed")
false
} else true
}
!kotlinClassesCompiled
}
// Make Gradle check if the javaTask is up-to-date based on the Kotlin classes
javaTask.inputs.dir(kotlinTask.destinationDir)
// Also, use kapt1 annotations file for up-to-date check since annotation processing is done with javac
kotlinTask.kaptOptions.annotationsFile?.let { javaTask.inputs.file(it) }
javaTask.dependsOn(kotlinTask.name)
/*
* It's important to modify javaTask.classpath only in doFirst,