diff --git a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt index 01f3e0ced60..72438ef864e 100644 --- a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt +++ b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt @@ -62,7 +62,11 @@ class IncrementalCompilationOptions( requestedCompilationResults: Array, val resultDifferenceFile: File? = null, val friendDifferenceFile: File? = null, - val usePreciseJavaTracking: Boolean + val usePreciseJavaTracking: Boolean, + /** + * Directories that should be cleared when IC decides to rebuild + */ + val localStateDirs: List ) : CompilationOptions(compilerMode, targetPlatform, reportCategories, reportSeverity, requestedCompilationResults) { companion object { const val serialVersionUID: Long = 0 @@ -80,6 +84,7 @@ class IncrementalCompilationOptions( "resultDifferenceFile=$resultDifferenceFile, " + "friendDifferenceFile=$friendDifferenceFile, " + "usePreciseJavaTracking=$usePreciseJavaTracking" + + "localStateDirs=$localStateDirs" + ")" } } diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt index 99749b82246..9f4854de86f 100644 --- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt @@ -522,7 +522,8 @@ class CompileServiceImpl( artifactChanges, changesRegistry, buildHistoryFile = incrementalCompilationOptions.resultDifferenceFile, friendBuildHistoryFile = incrementalCompilationOptions.friendDifferenceFile, - usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking + usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking, + localStateDirs = incrementalCompilationOptions.localStateDirs ) return compiler.compile(allKotlinFiles, k2jvmArgs, compilerMessageCollector, changedFiles) } diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt index 55dd0797956..c74b1302761 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt @@ -43,7 +43,8 @@ abstract class IncrementalCompilerRunner< protected val cacheVersions: List, protected val reporter: ICReporter, protected val artifactChangesProvider: ArtifactChangesProvider?, - protected val changesRegistry: ChangesRegistry? + protected val changesRegistry: ChangesRegistry?, + private val localStateDirs: Collection = emptyList() ) { protected val cacheDirectory = File(workingDir, cacheDirName) @@ -70,7 +71,15 @@ abstract class IncrementalCompilerRunner< caches.clean() dirtySourcesSinceLastTimeFile.delete() - destinationDir(args).deleteRecursively() + + reporter.report { "Deleting output directories on rebuild:" } + for (dir in sequenceOf(destinationDir(args)) + localStateDirs.asSequence()) { + if (!dir.isDirectory) continue + + dir.deleteRecursively() + dir.mkdirs() + reporter.report { "deleted $dir" } + } caches = createCacheManager(args) if (providedChangedFiles == null) { diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt index 52490df6f78..d8ccce53fff 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt @@ -71,7 +71,8 @@ fun makeIncrementally( sourceRoots.map { JvmSourceRoot(it, null) }.toSet(), versions, reporter, // Use precise setting in case of non-Gradle build - usePreciseJavaTracking = true + usePreciseJavaTracking = true, + localStateDirs = emptyList() ) compiler.compile(sourceFiles, args, messageCollector, providedChangedFiles = null) } @@ -104,14 +105,16 @@ class IncrementalJvmCompilerRunner( changesRegistry: ChangesRegistry? = null, private val buildHistoryFile: File? = null, private val friendBuildHistoryFile: File? = null, - private val usePreciseJavaTracking: Boolean + private val usePreciseJavaTracking: Boolean, + localStateDirs: Collection ) : IncrementalCompilerRunner( workingDir, "caches-jvm", cacheVersions, reporter, artifactChangesProvider, - changesRegistry + changesRegistry, + localStateDirs = localStateDirs ) { override fun isICEnabled(): Boolean = IncrementalCompilation.isEnabled() diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt index 930b9813294..73dea124b71 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt @@ -193,6 +193,54 @@ open class Kapt3IT : Kapt3BaseIT() { } } + @Test + fun testRemoveJavaClassICRebuild() { + testICRebuild { project -> + project.projectFile("Foo.java").delete() + } + } + + @Test + fun testChangeClasspathICRebuild() { + testICRebuild { project -> + project.projectFile("build.gradle").modify { + "$it\ndependencies { compile 'org.jetbrains.kotlin:kotlin-reflect:' + kotlin_version }" + } + } + } + + // tests all output directories are cleared when IC rebuilds + private fun testICRebuild(performChange: (Project) -> Unit) { + val project = Project("incrementalRebuild", directoryPrefix = "kapt2") + val options = defaultBuildOptions().copy(incremental = true) + val generatedSrc = "build/generated/source/kapt/main" + + project.build("build", options = options) { + assertSuccessful() + + // generated sources + assertFileExists("$generatedSrc/bar/UseBar_MembersInjector.java") + } + + performChange(project) + project.projectFile("UseBar.kt").modify { it.replace("package bar", "package foo.bar") } + + project.build("build", options = options) { + assertSuccessful() + assertTasksExecuted(listOf(":kaptGenerateStubsKotlin", ":kaptKotlin", ":compileKotlin", ":compileJava")) + + // generated sources + assertFileExists("$generatedSrc/foo/bar/UseBar_MembersInjector.java") + assertNoSuchFile("$generatedSrc/bar/UseBar_MembersInjector.java") + + // classes + assertFileExists(kotlinClassesDir() + "foo/bar/UseBar.class") + assertNoSuchFile(kotlinClassesDir() + "bar/UseBar.class") + assertFileExists(javaClassesDir() + "foo/bar/UseBar_MembersInjector.class") + assertNoSuchFile(javaClassesDir() + "bar/UseBar_MembersInjector.class") + } + } + @Test fun testRemoveAnnotationIC() { val project = Project("simple", directoryPrefix = "kapt2") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/build.gradle new file mode 100644 index 00000000000..042cd12474a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/build.gradle @@ -0,0 +1,24 @@ +buildscript { + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: "java" +apply plugin: "kotlin" +apply plugin: "kotlin-kapt" + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + compile 'com.google.dagger:dagger:2.14.1' + kapt 'com.google.dagger:dagger-compiler:2.14.1' +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/bar/UseBar.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/bar/UseBar.kt new file mode 100644 index 00000000000..79830a10b03 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/bar/UseBar.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package bar + +import javax.inject.Inject +import foo.* + +class UseBar { + @Inject + lateinit var bar: Bar +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/foo/Bar.java b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/foo/Bar.java new file mode 100644 index 00000000000..b3be5762e3c --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/foo/Bar.java @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package foo; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class Bar { + @Inject + public Bar(){ + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/foo/Foo.java b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/foo/Foo.java new file mode 100644 index 00000000000..53d5f2d2230 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/incrementalRebuild/src/main/java/foo/Foo.java @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package foo; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class Foo { + @Inject + public Foo(){ + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt index db0245b49e8..0007a3bf615 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt @@ -39,5 +39,6 @@ internal class GradleIncrementalCompilerEnvironment( val artifactFile: File? = null, val buildHistoryFile: File? = null, val friendBuildHistoryFile: File? = null, - val usePreciseJavaTracking: Boolean = false + val usePreciseJavaTracking: Boolean = false, + val localStateDirs: List = emptyList() ) : GradleCompilerEnvironment(compilerClasspath, messageCollector, outputItemsCollector, compilerArgs) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index 8cf153d7d49..a28d8c8612b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -269,7 +269,8 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil targetPlatform = targetPlatform, resultDifferenceFile = environment.buildHistoryFile, friendDifferenceFile = environment.friendBuildHistoryFile, - usePreciseJavaTracking = environment.usePreciseJavaTracking + usePreciseJavaTracking = environment.usePreciseJavaTracking, + localStateDirs = environment.localStateDirs ) log.info("Options for KOTLIN DAEMON: $compilationOptions") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt index 65be5eb088e..48ef00ff0ab 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt @@ -84,16 +84,6 @@ open class KaptGenerateStubsTask : KotlinCompile() { args.destinationAsFile = this.destinationDir } - override fun clearOutputsBeforeNonIncrementalBuild() { - super.clearOutputsBeforeNonIncrementalBuild() - - if (!stubsDir.deleteRecursively()) { - logger.kotlinWarn("Could not delete $stubsDir") - } - - stubsDir.mkdirs() - } - override fun execute(inputs: IncrementalTaskInputs) { val sourceRoots = kotlinCompileTask.getSourceRoots() val allKotlinSources = sourceRoots.kotlinSourceFiles diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt index 2c9787808c9..43071380bd7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt @@ -97,9 +97,7 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput= 0 diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 8293cab7067..f9249497721 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -341,13 +341,6 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl @Internal override fun getSourceRoots() = SourceRoots.ForJvm.create(getSource(), sourceRootsContainer) - protected open fun clearOutputsBeforeNonIncrementalBuild() { - logger.kotlinDebug { "Removing all kotlin classes in $destinationDir" } - - destinationDir.deleteRecursively() - destinationDir.mkdirs() - } - override fun callCompiler(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) { sourceRoots as SourceRoots.ForJvm @@ -371,13 +364,14 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl artifactFile = artifactFile, buildHistoryFile = buildHistoryFile, friendBuildHistoryFile = friendTask?.buildHistoryFile, - usePreciseJavaTracking = usePreciseJavaTracking + usePreciseJavaTracking = usePreciseJavaTracking, + localStateDirs = outputDirectories ) } } if (!incremental) { - clearOutputsBeforeNonIncrementalBuild() + clearOutputDirectories(reason = "IC is disabled for the task") } try { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt index c882aff2913..d2fecfa29d5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt @@ -1,7 +1,15 @@ package org.jetbrains.kotlin.gradle.tasks import org.gradle.api.GradleException +import org.gradle.api.Task +import org.gradle.api.tasks.OutputDirectory import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.gradle.plugin.kotlinDebug +import org.jetbrains.kotlin.gradle.utils.outputsCompatible +import java.io.File +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.memberProperties fun throwGradleExceptionIfError(exitCode: ExitCode) { when (exitCode) { @@ -11,4 +19,25 @@ fun throwGradleExceptionIfError(exitCode: ExitCode) { ExitCode.OK -> {} else -> throw IllegalStateException("Unexpected exit code: $exitCode") } +} + +internal val T.outputDirectories: List + get() = outputsCompatible.files.files.filter { it.isDirectory } + +internal fun T.clearOutputDirectories(reason: String? = null) { + logger.kotlinDebug { + val suffix = reason?.let { " ($it)" }.orEmpty() + "Clearing output directories for task '$path'$suffix:" + } + val outputDirectories = outputDirectories + for (dir in outputDirectories) { + when { + dir.isDirectory -> { + dir.deleteRecursively() + dir.mkdirs() + logger.kotlinDebug { " deleted $dir" } + } + else -> logger.kotlinDebug { " skipping $dir (not a directory)" } + } + } } \ No newline at end of file