diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt index 4c5e1bea2c9..329e72d5318 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt @@ -74,6 +74,35 @@ abstract class KaptIncrementalBaseIT(val shouldUseStubs: Boolean, val useKapt3: } } + @Test + fun testChangeFunctionBodyWithoutChangingSignature() { + val project = getProject() + + project.build("build") { + assertSuccessful() + checkStubUsage() + checkGenerated(*annotatedElements) + checkNotGenerated("notAnnotatedFun") + assertContains("foo.ATest PASSED") + } + + val utilKt = project.projectDir.getFileByName("util.kt") + utilKt.modify { oldContent -> + assert(oldContent.contains("2 * 2 == 4")) + oldContent.replace("2 * 2 == 4", "2 * 2 == 5") + } + + project.build("build") { + assertSuccessful() + checkStubUsage() + + if (useKapt3) { + assertNotContains(":kaptGenerateStubsKotlin UP-TO-DATE") + assertContains(":kaptKotlin UP-TO-DATE") + } + } + } + @Test fun testAddAnnotatedElement() { val project = getProject() diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalCompilationProject/src/main/java/baz/util.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalCompilationProject/src/main/java/baz/util.kt index eddfdea211c..b03fc09c3dd 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalCompilationProject/src/main/java/baz/util.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalCompilationProject/src/main/java/baz/util.kt @@ -6,4 +6,10 @@ val valUtil = 0 @example.ExampleAnnotation fun funUtil() {} -fun notAnnotatedFun() {} \ No newline at end of file +fun notAnnotatedFun() {} + +fun functionWithBody() { + if (2 * 2 == 4) { + // All's right + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt index 8481d3a7571..7835e19e9ec 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt @@ -68,7 +68,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { File(project.project.buildDir, "tmp/kapt3/classes/$sourceSetName") } - private val kotlinToKaptTasksMap = mutableMapOf() private val kotlinToKaptGenerateStubsTasksMap = mutableMapOf() override fun isApplicable(project: Project, task: KotlinCompile) = Kapt3GradleSubplugin.isEnabled(project) @@ -158,9 +157,8 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { } override fun getSubpluginKotlinTasks(project: Project, kotlinCompile: KotlinCompile): List { - val kaptTask = kotlinToKaptTasksMap[kotlinCompile] val kaptGenerateStubsTask = kotlinToKaptGenerateStubsTasksMap[kotlinCompile] - return listOf(kaptTask, kaptGenerateStubsTask).filterNotNull() + return if (kaptGenerateStubsTask == null) emptyList() else listOf(kaptGenerateStubsTask) } // This method should be called no more than once for each Kapt3SubpluginContext @@ -254,7 +252,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { private fun Kapt3SubpluginContext.createKaptKotlinTask(kaptGenerateStubsTask: KaptGenerateStubsTask) { val kaptTask = project.tasks.create(getKaptTaskName("kapt"), KaptTask::class.java) kaptTask.kotlinCompileTask = kotlinCompile - kotlinToKaptTasksMap[kotlinCompile] = kaptTask kaptClasspathArtifacts.forEach { kaptTask.pluginOptions.addClasspathEntry(it) } @@ -263,6 +260,16 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { 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 + } + kaptTask.dependsOn(kaptGenerateStubsTask) kotlinCompile.dependsOn(kaptTask) 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 27d904ac49c..96e826d0c49 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 @@ -18,19 +18,16 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.tasks.SourceTask import org.gradle.api.tasks.incremental.IncrementalTaskInputs -import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.incremental.ChangedFiles -import org.jetbrains.kotlin.incremental.GradleICReporter -import org.jetbrains.kotlin.incremental.ICReporter import org.jetbrains.kotlin.incremental.pathsAsStringRelativeTo import java.io.File open class KaptGenerateStubsTask : KotlinCompile() { - override val sourceRootsContainer = FilteringSourceRootsContainer({ isSourceRootAllowed(it) }) + override val sourceRootsContainer = FilteringSourceRootsContainer(emptyList(), { isSourceRootAllowed(it) }) internal lateinit var kotlinCompileTask: KotlinCompile @@ -56,8 +53,6 @@ open class KaptGenerateStubsTask : KotlinCompile() { val sourceRoots = kotlinCompileTask.getSourceRoots() val allKotlinSources = sourceRoots.kotlinSourceFiles - generatedSourcesDir.deleteRecursively() - logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(project.rootProject.projectDir)}" } if (allKotlinSources.isEmpty()) { 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 7b6bae2e59a..a6ef4a21000 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 @@ -1,7 +1,6 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.GradleException -import org.gradle.api.tasks.SourceTask import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.compile.AbstractCompile import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments @@ -9,33 +8,16 @@ import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl -import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues import org.jetbrains.kotlin.gradle.tasks.* -import org.jetbrains.kotlin.incremental.classpathAsList -import org.jetbrains.kotlin.incremental.destinationAsFile import java.io.File -import java.net.URLDecoder -import java.nio.charset.Charset open class KaptTask : AbstractCompile() { - private val rawSourceRoots = FilteringSourceRootsContainer({ !it.isInsideDestinationDir() }) - internal val pluginOptions = CompilerPluginOptions() internal lateinit var kotlinCompileTask: KotlinCompile - override fun setSource(sources: Any?) { - val filteredSources = rawSourceRoots.set(sources) - super.setSource(filteredSources) - } - - override fun source(vararg sources: Any?): SourceTask? { - val filteredSources = rawSourceRoots.add(*sources) - return super.source(filteredSources) - } - - private fun File.isInsideDestinationDir(): Boolean { - return FileUtil.isAncestor(destinationDir, this, /* strict = */ false) + fun isInsideDestinationDirs(file: File): Boolean { + return FileUtil.isAncestor(destinationDir, file, /* strict = */ false) + || FileUtil.isAncestor(classesDir, file, /* strict = */ false) } lateinit var classesDir: File @@ -43,12 +25,14 @@ open class KaptTask : AbstractCompile() { @TaskAction override fun compile() { - /** Delete everything inside the [destinationDir] (sources output dir) */ + /** Delete everything inside generated sources and classes output directory + * (annotation processing is not incremental) */ destinationDir.clearDirectory() - classesDir.clearDirectory() - val sourceRoots = SourceRoots.ForJvm.create(getSource(), rawSourceRoots) + val sourceRootsFromKotlin = kotlinCompileTask.sourceRootsContainer.sourceRoots + val rawSourceRoots = FilteringSourceRootsContainer(sourceRootsFromKotlin, { !isInsideDestinationDirs(it) }) + val sourceRoots = SourceRoots.ForJvm.create(kotlinCompileTask.source, rawSourceRoots) val args = K2JVMCompilerArguments() kotlinCompileTask.setupCompilerArgs(args) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/gradleUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/gradleUtils.kt index 181af3fdf9a..9e9a72bcb90 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/gradleUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/gradleUtils.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Task import org.gradle.api.file.FileCollection +import org.gradle.api.file.FileTree import org.gradle.api.internal.HasConvention import org.gradle.api.logging.Logger import org.gradle.api.plugins.ExtensionAware @@ -50,6 +51,10 @@ internal fun AbstractCompile.mapClasspath(fn: () -> FileCollection) { conventionMapping.map("classpath", fn) } +internal fun AbstractCompile.mapSource(fn: () -> FileTree) { + conventionMapping.map("source", fn) +} + internal inline fun Any.addConvention(name: String, plugin: T) { (this as HasConvention).convention.plugins[name] = plugin } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt index aea6d4e1a3e..7471b668380 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/SourceRoots.kt @@ -58,8 +58,8 @@ internal sealed class SourceRoots(val kotlinSourceFiles: List) { } } -internal class FilteringSourceRootsContainer(val filter: (File) -> Boolean = { true }) { - private val mutableSourceRoots = mutableListOf() +internal class FilteringSourceRootsContainer(roots: List = emptyList(), val filter: (File) -> Boolean = { true }) { + private val mutableSourceRoots = roots.filterTo(mutableListOf(), filter) val sourceRoots: List get() = mutableSourceRoots