diff --git a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt index a49ec4eb04a..30ee30d35e1 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt @@ -21,6 +21,7 @@ data class IncrementalModuleEntry( class IncrementalModuleInfo( val projectRoot: File, + val rootProjectBuildDir: File, val dirToModule: Map, val nameToModules: Map>, val jarToClassListFile: Map, @@ -28,6 +29,6 @@ class IncrementalModuleInfo( val jarToModule: Map ) : Serializable { companion object { - private const val serialVersionUID = 0L + private const val serialVersionUID = 1L } } \ No newline at end of file diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt index 8951733c126..ce7ac983cad 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.incremental.multiproject -import org.jetbrains.kotlin.incremental.IncrementalModuleEntry import org.jetbrains.kotlin.incremental.IncrementalModuleInfo import org.jetbrains.kotlin.incremental.util.Either import java.io.File @@ -23,7 +22,14 @@ object EmptyModulesApiHistory : ModulesApiHistory { } abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory { - protected val projectRootPath: Path = Paths.get(modulesInfo.projectRoot.absolutePath) + // All project build dirs should have this dir as their parent. For a default project setup, this will + // be the same as root project path. Some projects map output outside of the root project dir, typically + // with //build, and in that case, this path will be . + // This is using set in order to de-dup paths, and avoid duplicate checks when possible. + protected val possibleParentsToBuildDirs: Set = setOf( + Paths.get(modulesInfo.rootProjectBuildDir.parentFile.absolutePath), + Paths.get(modulesInfo.projectRoot.absolutePath) + ) private val dirToHistoryFileCache = HashMap>() override fun historyFilesForChangedFiles(changedFiles: Set): Either> { @@ -76,7 +82,7 @@ abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModul when { module != null -> setOf(module.buildHistoryFile) - parent != null && projectRootPath.isParentOf(parent) -> { + parent != null && isInProjectBuildDir(parent) -> { val parentHistory = getBuildHistoryForDir(parent) when (parentHistory) { is Either.Success> -> parentHistory.value @@ -90,6 +96,10 @@ abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModul return Either.Success(history) } + protected fun isInProjectBuildDir(file: File): Boolean { + return possibleParentsToBuildDirs.any { it.isParentOf(file) } + } + protected abstract fun getBuildHistoryFilesForJar(jar: File): Either> } @@ -145,14 +155,14 @@ class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiH override fun getBuildHistoryFilesForJar(jar: File): Either> { // Module detection is expensive, so we don't don it for jars outside of project dir - if (!projectRootPath.isParentOf(jar)) return Either.Error("Non-project jar is modified $jar") + if (!isInProjectBuildDir(jar)) return Either.Error("Non-project jar is modified $jar") val jarPath = Paths.get(jar.absolutePath) return getHistoryForModuleNames(jarPath, getPossibleModuleNamesFromJar(jarPath)) } override fun getBuildHistoryForDir(file: File): Either> { - if (!projectRootPath.isParentOf(file)) return Either.Error("Non-project file while looking for history $file") + if (!isInProjectBuildDir(file)) return Either.Error("Non-project file while looking for history $file") // check both meta-inf and META-INF directories val moduleNames = diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt index c46bee28e71..2c25c1f3612 100644 --- a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt +++ b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt @@ -32,7 +32,7 @@ abstract class AbstractIncrementalMultiModuleCompilerRunnerTest() protected val incrementalModuleInfo: IncrementalModuleInfo by lazy { - IncrementalModuleInfo(workingDir, dirToModule, nameToModules, jarToClassListFile, jarToModule) + IncrementalModuleInfo(workingDir, workingDir, dirToModule, nameToModules, jarToClassListFile, jarToModule) } protected abstract val modulesApiHistory: ApiHistory diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt index bb3ec09aacc..c783c7de358 100644 --- a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt +++ b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt @@ -56,6 +56,7 @@ class ModulesApiHistoryAndroidTest { val info = IncrementalModuleInfo( projectRoot = projectRoot, + rootProjectBuildDir = projectRoot.resolve("build"), dirToModule = mapOf(appKotlinDestination to appEntry, libKotlinDestination to libEntry), nameToModules = mapOf("app" to setOf(appEntry), "lib" to setOf(libEntry)), jarToClassListFile = mapOf(), diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt index e14da624cf5..65be9b10dac 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt @@ -347,5 +347,33 @@ open class A { assertCompiledKotlinSources(project.relativize(aaKt)) } } + + /** Regression test for KT-40875. */ + @Test + fun testMoveFunctionFromLibWithRemappedBuildDirs() { + val project = defaultProject() + project.setupWorkingDir() + project.projectDir.resolve("build.gradle").appendText(""" + + allprojects { + it.buildDir = new File(rootDir, "../out" + it.path.replace(":", "/") + "/build") + } + """.trimIndent()) + project.build("build") { + assertSuccessful() + } + + val barUseABKt = project.projectDir.getFileByName("barUseAB.kt") + val barInApp = File(project.projectDir, "app/src/main/kotlin/bar").apply { mkdirs() } + barUseABKt.copyTo(File(barInApp, barUseABKt.name)) + barUseABKt.delete() + + project.build("build") { + assertSuccessful() + val affectedSources = project.projectDir.getFilesByNames("fooCallUseAB.kt", "barUseAB.kt") + val relativePaths = project.relativize(affectedSources) + assertCompiledKotlinSources(relativePaths) + } + } } 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 5bbb9eacf11..fb4fc14b5a2 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 @@ -257,6 +257,7 @@ internal open class GradleCompilerRunner(protected val taskProvider: GradleCompi return IncrementalModuleInfo( projectRoot = gradle.rootProject.projectDir, + rootProjectBuildDir = gradle.rootProject.buildDir, dirToModule = dirToModule, nameToModules = nameToModules, jarToClassListFile = jarToClassListFile,