diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/build/FSOperationsHelper.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/build/FSOperationsHelper.kt index 7ac1a28f3a5..ad996865e47 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/FSOperationsHelper.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/FSOperationsHelper.kt @@ -17,17 +17,25 @@ package org.jetbrains.kotlin.jps.build import com.intellij.openapi.diagnostic.Logger +import com.intellij.util.containers.ContainerUtil import org.jetbrains.jps.ModuleChunk +import org.jetbrains.jps.builders.BuildRootIndex +import org.jetbrains.jps.builders.BuildTarget +import org.jetbrains.jps.builders.BuildTargetIndex +import org.jetbrains.jps.builders.java.dependencyView.Mappings import org.jetbrains.jps.incremental.CompileContext import org.jetbrains.jps.incremental.FSOperations import org.jetbrains.jps.incremental.fs.CompilationRound import java.io.File +import java.util.HashMap class FSOperationsHelper( private val compileContext: CompileContext, private val chunk: ModuleChunk, private val log: Logger ) { + private val moduleBasedFilter = ModulesBasedFileFilter(compileContext, chunk) + internal var hasMarkedDirty = false private set @@ -51,19 +59,50 @@ class FSOperationsHelper( } } - fun markFiles(files: Iterable, excludeFiles: Set = setOf()) { - val filesToMark = files.toMutableSet() - filesToMark.removeAll(excludeFiles) + fun markFiles(files: Iterable) { + markFilesImpl(files) { it.exists() } + } + + fun markInChunkOrDependents(files: Iterable, excludeFiles: Set) { + markFilesImpl(files) { it !in excludeFiles && it.exists() && moduleBasedFilter.accept(it) } + } + + private inline fun markFilesImpl(files: Iterable, shouldMark: (File)->Boolean) { + val filesToMark = files.filterTo(HashSet(), shouldMark) + + if (filesToMark.isEmpty()) return + + for (fileToMark in filesToMark) { + FSOperations.markDirty(compileContext, CompilationRound.NEXT, fileToMark) + } log.debug("Mark dirty: $filesToMark") buildLogger?.markedAsDirty(filesToMark) + hasMarkedDirty = true + } - for (file in filesToMark) { - if (!file.exists()) continue + // Based on `JavaBuilderUtil#ModulesBasedFileFilter` from Intellij + private class ModulesBasedFileFilter( + private val context: CompileContext, + chunk: ModuleChunk + ): Mappings.DependentFilesFilter { + private val chunkTargets = chunk.targets + private val buildRootIndex = context.projectDescriptor.buildRootIndex + private val buildTargetIndex = context.projectDescriptor.buildTargetIndex + private val cache = HashMap, Set>>() - FSOperations.markDirty(compileContext, CompilationRound.NEXT, file) + override fun accept(file: File): Boolean { + val rd = buildRootIndex.findJavaRootDescriptor(context, file) ?: return true + val target = rd.target + if (target in chunkTargets) return true + + val targetOfFileWithDependencies = cache.getOrPut(target) { buildTargetIndex.getDependenciesRecursively(target, context) } + return ContainerUtil.intersects(targetOfFileWithDependencies, chunkTargets) } - hasMarkedDirty = hasMarkedDirty || filesToMark.isNotEmpty() + override fun belongsToCurrentTargetChunk(file: File): Boolean { + val rd = buildRootIndex.findJavaRootDescriptor(context, file) + return rd != null && chunkTargets.contains(rd.target) + } } } diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt index 2ea6f1db364..6aba5f64536 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt @@ -826,7 +826,7 @@ private fun CompilationResult.processChangesUsingLookups( val (dirtyLookupSymbols, dirtyClassFqNames) = getDirtyData(allCaches, reporter) val dirtyFiles = mapLookupSymbolsToFiles(lookupStorage, dirtyLookupSymbols, reporter) + mapClassesFqNamesToFiles(allCaches, dirtyClassFqNames, reporter) - fsOperations.markFiles(dirtyFiles.asIterable(), excludeFiles = compiledFiles) + fsOperations.markInChunkOrDependents(dirtyFiles.asIterable(), excludeFiles = compiledFiles) reporter.report { "End of processing changes" } } diff --git a/jps-plugin/testData/incremental/multiModule/classAdded/build.log b/jps-plugin/testData/incremental/multiModule/classAdded/build.log index 7e91e1f8b82..7836e2f6683 100644 --- a/jps-plugin/testData/incremental/multiModule/classAdded/build.log +++ b/jps-plugin/testData/incremental/multiModule/classAdded/build.log @@ -8,7 +8,6 @@ Compiling files: module2/src/A.kt End of files Marked as dirty by Kotlin: - module1/src/A.kt module2/src/B.kt module2/src/createA.kt module2/src/createB.kt @@ -39,13 +38,7 @@ Unresolved reference: foo ================ Step #2 ================= Building module1 -Cleaning output files: - out/production/module1/foo/A.class -End of files -Compiling files: - module1/src/A.kt -End of files -Exit code: OK +Exit code: NOTHING_DONE ------------------------------------------ Building module2 Cleaning output files: @@ -60,4 +53,4 @@ Compiling files: module2/src/useBbar.kt End of files Exit code: OK ------------------------------------------- +------------------------------------------ \ No newline at end of file diff --git a/jps-plugin/testData/incremental/multiModule/classRemoved/build.log b/jps-plugin/testData/incremental/multiModule/classRemoved/build.log index 1655258a750..4a1d1fc30bd 100644 --- a/jps-plugin/testData/incremental/multiModule/classRemoved/build.log +++ b/jps-plugin/testData/incremental/multiModule/classRemoved/build.log @@ -1,13 +1,7 @@ ================ Step #1 ================= Building module1 -Cleaning output files: - out/production/module1/foo/A.class -End of files -Compiling files: - module1/src/A.kt -End of files -Exit code: OK +Exit code: NOTHING_DONE ------------------------------------------ Cleaning output files: out/production/module2/foo/A.class @@ -40,23 +34,13 @@ Compiling files: module2/src/createA.kt module2/src/useAfoo.kt End of files -Marked as dirty by Kotlin: - module1/src/A.kt -Exit code: ADDITIONAL_PASS_REQUIRED ------------------------------------------- -Exit code: NOTHING_DONE +Exit code: OK ------------------------------------------ ================ Step #3 ================= Building module1 -Cleaning output files: - out/production/module1/foo/A.class -End of files -Compiling files: - module1/src/A.kt -End of files -Exit code: OK +Exit code: NOTHING_DONE ------------------------------------------ Building module2 Compiling files: @@ -65,4 +49,4 @@ End of files Exit code: ABORT ------------------------------------------ COMPILATION FAILED -Expecting a top level declaration +Expecting a top level declaration \ No newline at end of file diff --git a/jps-plugin/testData/incremental/multiModule/moveFileToAnotherModule/build.log b/jps-plugin/testData/incremental/multiModule/moveFileToAnotherModule/build.log index 003b40aecfd..304f246b7d7 100644 --- a/jps-plugin/testData/incremental/multiModule/moveFileToAnotherModule/build.log +++ b/jps-plugin/testData/incremental/multiModule/moveFileToAnotherModule/build.log @@ -25,9 +25,5 @@ Compiling files: module2/src/useClassB.kt module2/src/useFunB.kt End of files -Marked as dirty by Kotlin: - module1/src/b.kt -Exit code: ADDITIONAL_PASS_REQUIRED ------------------------------------------- -Exit code: NOTHING_DONE ------------------------------------------- +Exit code: OK +------------------------------------------ \ No newline at end of file