Avoid marking dirty dependencies from already compiled chunks

#KT-17397 fixed

Original commit: 5ce3a436c7
This commit is contained in:
Alexey Tsvetkov
2017-04-27 19:48:38 +03:00
parent a7db839ba0
commit e93497e995
5 changed files with 55 additions and 43 deletions
@@ -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<File>, excludeFiles: Set<File> = setOf()) {
val filesToMark = files.toMutableSet()
filesToMark.removeAll(excludeFiles)
fun markFiles(files: Iterable<File>) {
markFilesImpl(files) { it.exists() }
}
fun markInChunkOrDependents(files: Iterable<File>, excludeFiles: Set<File>) {
markFilesImpl(files) { it !in excludeFiles && it.exists() && moduleBasedFilter.accept(it) }
}
private inline fun markFilesImpl(files: Iterable<File>, 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<BuildTarget<*>, Set<BuildTarget<*>>>()
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)
}
}
}
@@ -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" }
}
@@ -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
------------------------------------------
------------------------------------------
@@ -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
@@ -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
------------------------------------------