Avoid marking dirty dependencies from already compiled chunks
#KT-17397 fixed
Original commit: 5ce3a436c7
This commit is contained in:
@@ -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
|
||||
------------------------------------------
|
||||
Reference in New Issue
Block a user