diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseMultiGradleVersionIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseMultiGradleVersionIT.kt new file mode 100644 index 00000000000..59cb0ad3b1a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseMultiGradleVersionIT.kt @@ -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) } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt index 71d808e317c..22e8159d049 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt @@ -109,7 +109,7 @@ class KaptIT: BaseGradleIT() { private fun doTestIncrementalBuild(projectName: String, compileTasks: Array) { 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() diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginMultiVersionIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginMultiVersionIT.kt new file mode 100644 index 00000000000..5eb0e87091f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginMultiVersionIT.kt @@ -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!") + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index b75be85dc9a..369aabd3607 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -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,