diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt index 17cbf09d010..832129a8422 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.util.modify import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test +import kotlin.test.assertFalse class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { @@ -136,4 +137,37 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { assertTrue(getProcessedSources(output).isEmpty()) } } + + @Test + fun testIncompatibleClasspathChanges() { + val project = getProject() + project.projectFile("useB.kt").modify { current -> + current + """ + + @example.ExampleAnnotation + fun addedFunctionB() = "" + """.trimIndent() + } + project.build("clean", "build") { + assertSuccessful() + } + + project.projectFile("useB.kt").modify { current -> + current.replace("fun addedFunctionB", "fun renamedFunctionB") + } + project.gradleBuildScript().appendText(""" + + dependencies { + compile 'com.google.guava:guava:12.0' + } + """.trimIndent()) + project.build("build") { + assertSuccessful() + + assertFalse( + fileInWorkingDir("build/generated/source/kapt/main/bar/AddedFunctionBGenerated.java").exists(), + "Generated file should be deleted for renamed function when classpath changes." + ) + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt index 16169ecfc99..b83d0b4cdb1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt @@ -170,44 +170,44 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { protected fun getCompiledSources() = listOfNotNull(kotlinCompileTask.destinationDir, kotlinCompileTask.javaOutputDir) protected fun getIncrementalChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { - if (!isIncremental) { + return if (isIncremental) { + findClasspathChanges(inputs) + } else { clearLocalState() - return KaptIncrementalChanges.Unknown - } - val allDataFiles = classpathStructure!!.files - if (!inputs.isIncremental) { - clearLocalState() - findClasspathChanges(allDataFiles, allDataFiles) - return KaptIncrementalChanges.Unknown - } - - val changedFiles = with(mutableSetOf()) { - inputs.outOfDate { this.add(it.file) } - inputs.removed { this.add(it.file) } - return@with this - } - - val changedDataFiles = allDataFiles.filterTo(HashSet()) { it in changedFiles } - val classpathStatus = findClasspathChanges(allDataFiles, changedDataFiles) - return when (classpathStatus) { - is KaptClasspathChanges.Unknown -> KaptIncrementalChanges.Unknown - is KaptClasspathChanges.Known -> KaptIncrementalChanges.Known( - changedFiles.filter { it.extension == "java" }.toSet(), classpathStatus.names - ) + KaptIncrementalChanges.Unknown } } - private fun findClasspathChanges(allDataFile: Set, changedDataFiles: Set): KaptClasspathChanges { + private fun findClasspathChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { val incAptCacheDir = incAptCache!! incAptCacheDir.mkdirs() + val allDataFiles = classpathStructure!!.files + val changedFiles = if (inputs.isIncremental) { + with(mutableSetOf()) { + inputs.outOfDate { this.add(it.file) } + inputs.removed { this.add(it.file) } + return@with this + } + } else { + allDataFiles + } + val startTime = System.currentTimeMillis() - val previousSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(incAptCacheDir) + val previousSnapshot = if (inputs.isIncremental) { + ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(incAptCacheDir) + } else { + ClasspathSnapshot.ClasspathSnapshotFactory.getEmptySnapshot() + } val currentSnapshot = - ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(incAptCacheDir, classpath.files.toList(), allDataFile) + ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(incAptCacheDir, classpath.files.toList(), allDataFiles) - val classpathChanges = currentSnapshot.diff(previousSnapshot, changedDataFiles) + val classpathChanges = currentSnapshot.diff(previousSnapshot, changedFiles) + if (classpathChanges == KaptClasspathChanges.Unknown) { + // We are unable to determine classpath changes, so clean the local state as we will run non-incrementally + clearLocalState() + } currentSnapshot.writeToCache() if (logger.isInfoEnabled) { @@ -223,7 +223,12 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { } } } - return classpathChanges + return when (classpathChanges) { + is KaptClasspathChanges.Unknown -> KaptIncrementalChanges.Unknown + is KaptClasspathChanges.Known -> KaptIncrementalChanges.Known( + changedFiles.filter { it.extension == "java" }.toSet(), classpathChanges.names + ) + } } private fun hasAnnotationProcessors(file: File): Boolean { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt index 0f02ea2dc56..6509abc7218 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt @@ -43,6 +43,8 @@ open class ClasspathSnapshot protected constructor( return ClasspathSnapshot(cacheDir, classpath, data) } + + fun getEmptySnapshot() = UnknownSnapshot } private fun isCompatible(snapshot: ClasspathSnapshot) =