From 36f99156fd140f1ef58c7763f88b5bca18926b15 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Wed, 9 Dec 2020 17:33:09 +0300 Subject: [PATCH] IC of sealed classes Supported case then children of sealed classes could be declared anywhere in a module. If list of classes implementing sealing class changes the sealed class and all its inheritors should be recompiled (now sealed class should be compiled together with children in order to calculate all possible inheritors at compile time) and and invalidated (as they could have when operators). --- .../incremental/AbstractIncrementalCache.kt | 20 +++++++- .../kotlin/incremental/ChangesCollector.kt | 35 +++++++++++-- .../kotlin/incremental/IncrementalJvmCache.kt | 2 + .../jetbrains/kotlin/incremental/buildUtil.kt | 38 +++++++++++++- .../incremental/protoDifferenceUtils.kt | 20 ++++++-- .../incremental/storage/ClassAttributesMap.kt | 51 +++++++++++++++++++ .../incremental/IncrementalCompilerRunner.kt | 6 ++- .../IncrementalJsCompilerRunner.kt | 2 +- .../IncrementalJvmCompilerRunner.kt | 2 +- .../AbstractProtoComparisonTest.kt | 2 + .../kotlin/jps/build/KotlinBuilder.kt | 25 +++++++-- 11 files changed, 183 insertions(+), 20 deletions(-) create mode 100644 build-common/src/org/jetbrains/kotlin/incremental/storage/ClassAttributesMap.kt diff --git a/build-common/src/org/jetbrains/kotlin/incremental/AbstractIncrementalCache.kt b/build-common/src/org/jetbrains/kotlin/incremental/AbstractIncrementalCache.kt index fedb2949dc8..337c09af52b 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/AbstractIncrementalCache.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/AbstractIncrementalCache.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.incremental import com.intellij.util.io.EnumeratorStringDescriptor import org.jetbrains.kotlin.incremental.storage.* import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.TypeTable import org.jetbrains.kotlin.metadata.deserialization.supertypes @@ -34,12 +35,15 @@ interface IncrementalCacheCommon { val thisWithDependentCaches: Iterable> fun classesFqNamesBySources(files: Iterable): Collection fun getSubtypesOf(className: FqName): Sequence + fun getSupertypesOf(className: FqName): Sequence fun getSourceFileIfClass(fqName: FqName): File? fun markDirty(removedAndCompiledSources: Collection) fun clearCacheForRemovedClasses(changesCollector: ChangesCollector) fun getComplementaryFilesRecursive(dirtyFiles: Collection): Collection fun updateComplementaryFiles(dirtyFiles: Collection, expectActualTracker: ExpectActualTrackerImpl) fun dump(): String + + fun isSealed(className: FqName): Boolean? } /** @@ -50,6 +54,7 @@ abstract class AbstractIncrementalCache( protected val pathConverter: FileToPathConverter ) : BasicMapsOwner(workingDir), IncrementalCacheCommon { companion object { + private val CLASS_ATTRIBUTES = "class-attributes" private val SUBTYPES = "subtypes" private val SUPERTYPES = "supertypes" private val CLASS_FQ_NAME_TO_SOURCE = "class-fq-name-to-source" @@ -71,6 +76,7 @@ abstract class AbstractIncrementalCache( result } + internal val classAttributesMap = registerMap(ClassAttributesMap(CLASS_ATTRIBUTES.storageFile)) private val subtypesMap = registerMap(SubtypesMap(SUBTYPES.storageFile)) private val supertypesMap = registerMap(SupertypesMap(SUPERTYPES.storageFile)) protected val classFqNameToSourceMap = registerMap(ClassFqNameToSourceMap(CLASS_FQ_NAME_TO_SOURCE.storageFile, pathConverter)) @@ -90,6 +96,14 @@ abstract class AbstractIncrementalCache( override fun getSubtypesOf(className: FqName): Sequence = subtypesMap[className].asSequence() + override fun getSupertypesOf(className: FqName): Sequence { + return supertypesMap[className].asSequence() + } + + override fun isSealed(className: FqName): Boolean? { + return classAttributesMap[className]?.isSealed + } + override fun getSourceFileIfClass(fqName: FqName): File? = classFqNameToSourceMap[fqName] @@ -118,6 +132,7 @@ abstract class AbstractIncrementalCache( supertypesMap[child] = parents classFqNameToSourceMap[child] = srcFile + classAttributesMap[child] = ICClassesAttributes(ProtoBuf.Modality.SEALED == Flags.MODALITY.get(proto.flags)) } protected fun removeAllFromClassStorage(removedClasses: Collection, changesCollector: ChangesCollector) { @@ -152,7 +167,10 @@ abstract class AbstractIncrementalCache( } } - removedFqNames.forEach { classFqNameToSourceMap.remove(it) } + removedFqNames.forEach { + classFqNameToSourceMap.remove(it) + classAttributesMap.remove(it) + } } protected class ClassFqNameToSourceMap( diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt b/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt index bf66f3a8e74..90499179685 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt @@ -19,12 +19,14 @@ package org.jetbrains.kotlin.incremental import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.NameResolver +import org.jetbrains.kotlin.metadata.deserialization.supertypes import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.serialization.deserialization.getClassId class ChangesCollector { private val removedMembers = hashMapOf>() + private val changedParents = hashMapOf>() private val changedMembers = hashMapOf>() private val areSubclassesAffected = hashMapOf() @@ -47,6 +49,10 @@ class ChangesCollector { changes.add(ChangeInfo.SignatureChanged(fqName, areSubclassesAffected)) } + for ((fqName, changedParents) in changedParents) { + changes.add(ChangeInfo.ParentsChanged(fqName, changedParents)) + } + return changes } @@ -79,12 +85,12 @@ class ChangesCollector { } if (oldData == null) { - newData!!.collectAll(isRemoved = false, collectAllMembersForNewClass = collectAllMembersForNewClass) + newData!!.collectAll(isRemoved = false, isAdded = true, collectAllMembersForNewClass = collectAllMembersForNewClass) return } if (newData == null) { - oldData.collectAll(isRemoved = true) + oldData.collectAll(isRemoved = true, isAdded = false) return } @@ -98,6 +104,7 @@ class ChangesCollector { collectSignature(oldData, diff.areSubclassesAffected) } collectChangedMembers(fqName, diff.changedMembersNames) + addChangedParents(fqName, diff.changedSupertypes) } is PackagePartProtoData -> { collectSignature(oldData, areSubclassesAffected = true) @@ -121,10 +128,11 @@ class ChangesCollector { private fun T.getNonPrivateNames(nameResolver: NameResolver, vararg members: T.() -> List): Set = members.flatMap { this.it().filterNot { it.isPrivate }.names(nameResolver) }.toSet() - private fun ProtoData.collectAll(isRemoved: Boolean, collectAllMembersForNewClass: Boolean = false) = + //TODO remember all sealed parent classes + private fun ProtoData.collectAll(isRemoved: Boolean, isAdded: Boolean, collectAllMembersForNewClass: Boolean = false) = when (this) { is PackagePartProtoData -> collectAllFromPackage(isRemoved) - is ClassProtoData -> collectAllFromClass(isRemoved, collectAllMembersForNewClass) + is ClassProtoData -> collectAllFromClass(isRemoved, isAdded, collectAllMembersForNewClass) } private fun PackagePartProtoData.collectAllFromPackage(isRemoved: Boolean) { @@ -143,7 +151,7 @@ class ChangesCollector { } } - private fun ClassProtoData.collectAllFromClass(isRemoved: Boolean, collectAllMembersForNewClass: Boolean = false) { + private fun ClassProtoData.collectAllFromClass(isRemoved: Boolean, isAdded: Boolean, collectAllMembersForNewClass: Boolean = false) { val classFqName = nameResolver.getClassId(proto.fqName).asSingleFqName() val kind = Flags.CLASS_KIND.get(proto.flags) @@ -162,6 +170,23 @@ class ChangesCollector { collectSignature(classFqName, areSubclassesAffected = true) } + + if (isRemoved || isAdded) { + collectChangedParents(classFqName, proto.supertypeList) + } + } + + private fun addChangedParents(fqName: FqName, parents: Collection) { + if (parents.isNotEmpty()) { + changedParents.getOrPut(fqName) { HashSet() }.addAll(parents) + } + } + + private fun ClassProtoData.collectChangedParents(fqName: FqName, parents: Collection) { + val changedParentsFqNames = parents.map { type -> + nameResolver.getClassId(type.className).asSingleFqName() + } + addChangedParents(fqName, changedParentsFqNames) } private fun ClassProtoData.getNonPrivateMemberNames(): Set { diff --git a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt index 29e89f95de9..c5f01e1824b 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt @@ -145,6 +145,7 @@ open class IncrementalJvmCache( } protoMap.remove(className, changesCollector) classFqNameToSourceMap.remove(className.fqNameForClassNameWithoutDollars) + classAttributesMap.remove(className.fqNameForClassNameWithoutDollars) internalNameToSource.remove(className.internalName) // TODO NO_CHANGES? (delegates only) @@ -568,6 +569,7 @@ sealed class ChangeInfo(val fqName: FqName) { class SignatureChanged(fqName: FqName, val areSubclassesAffected: Boolean) : ChangeInfo(fqName) + class ParentsChanged(fqName: FqName, val parentsChanged: Collection) : ChangeInfo(fqName) protected open fun toStringProperties(): String = "fqName = $fqName" diff --git a/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt b/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt index 745453842f6..cf215b95ab5 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt @@ -136,7 +136,8 @@ fun LookupStorage.update( data class DirtyData( val dirtyLookupSymbols: Collection = emptyList(), - val dirtyClassesFqNames: Collection = emptyList() + val dirtyClassesFqNames: Collection = emptyList(), + val dirtyClassesFqNamesForceRecompile: Collection = emptyList() ) fun ChangesCollector.getDirtyData( @@ -146,6 +147,9 @@ fun ChangesCollector.getDirtyData( val dirtyLookupSymbols = HashSet() val dirtyClassesFqNames = HashSet() + val sealedParents = HashMap>() + val notSealedParents = HashSet() + for (change in changes()) { reporter.reportVerbose { "Process $change" } @@ -170,10 +174,35 @@ fun ChangesCollector.getDirtyData( } fqNames.mapTo(dirtyLookupSymbols) { LookupSymbol(SAM_LOOKUP_NAME.asString(), it.asString()) } + } else if (change is ChangeInfo.ParentsChanged) { + fun FqName.isSealed(): Boolean { + if (notSealedParents.contains(this)) return false + if (sealedParents.containsKey(this)) return true + return isSealed(this, caches).also { sealed -> + if (sealed) { + sealedParents[this] = HashSet() + } else { + notSealedParents.add(this) + } + } + } + change.parentsChanged.forEach { parent -> + if (parent.isSealed()) { + sealedParents.getOrPut(parent) { HashSet() }.add(change.fqName) + } + } } } - return DirtyData(dirtyLookupSymbols, dirtyClassesFqNames) + val forceRecompile = HashSet().apply { + addAll(sealedParents.keys) + //we should recompile all inheritors with parent sealed class: add known subtypes + addAll(sealedParents.keys.flatMap { withSubtypes(it, caches) }) + //we should recompile all inheritors with parent sealed class: add new subtypes + addAll(sealedParents.values.flatten()) + } + + return DirtyData(dirtyLookupSymbols, dirtyClassesFqNames, forceRecompile) } fun mapLookupSymbolsToFiles( @@ -217,6 +246,11 @@ fun mapClassesFqNamesToFiles( return fqNameToAffectedFiles.values.flattenTo(HashSet()) } +fun isSealed( + fqName: FqName, + caches: Iterable +): Boolean = caches.any { it.isSealed(fqName) ?: false } + fun withSubtypes( typeFqName: FqName, caches: Iterable diff --git a/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt b/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt index 9b84e4857fb..8af998ce9c7 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt @@ -28,12 +28,14 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags import org.jetbrains.kotlin.serialization.deserialization.descriptorVisibility +import org.jetbrains.kotlin.serialization.deserialization.getClassId import java.util.* data class Difference( val isClassAffected: Boolean = false, val areSubclassesAffected: Boolean = false, - val changedMembersNames: Set = emptySet() + val changedMembersNames: Set = emptySet(), + val changedSupertypes: Set = emptySet() ) sealed class ProtoData @@ -187,6 +189,7 @@ class DifferenceCalculatorForClass( var isClassAffected = false var areSubclassesAffected = false + val changedSupertypes = HashSet() val names = hashSetOf() val classIsSealed = newProto.isSealed && oldProto.isSealed @@ -247,12 +250,21 @@ class DifferenceCalculatorForClass( ProtoBufClassKind.FLAGS, ProtoBufClassKind.FQ_NAME, ProtoBufClassKind.TYPE_PARAMETER_LIST, - ProtoBufClassKind.SUPERTYPE_LIST, - ProtoBufClassKind.SUPERTYPE_ID_LIST, ProtoBufClassKind.JS_EXT_CLASS_ANNOTATION_LIST -> { isClassAffected = true areSubclassesAffected = true } + + ProtoBufClassKind.SUPERTYPE_LIST, + ProtoBufClassKind.SUPERTYPE_ID_LIST -> { + isClassAffected = true + areSubclassesAffected = true + + val oldSupertypes = oldProto.supertypeList.map { oldNameResolver.getClassId(it.className).asSingleFqName() } + val newSupertypes = newProto.supertypeList.map { newNameResolver.getClassId(it.className).asSingleFqName() } + val changed = (oldSupertypes union newSupertypes) subtract (oldSupertypes intersect newSupertypes) + changedSupertypes.addAll(changed) + } ProtoBufClassKind.JVM_EXT_CLASS_MODULE_NAME, ProtoBufClassKind.JS_EXT_CLASS_CONTAINING_FILE_ID -> { // TODO @@ -281,7 +293,7 @@ class DifferenceCalculatorForClass( } } - return Difference(isClassAffected, areSubclassesAffected, names) + return Difference(isClassAffected, areSubclassesAffected, names, changedSupertypes) } } diff --git a/build-common/src/org/jetbrains/kotlin/incremental/storage/ClassAttributesMap.kt b/build-common/src/org/jetbrains/kotlin/incremental/storage/ClassAttributesMap.kt new file mode 100644 index 00000000000..7b853709576 --- /dev/null +++ b/build-common/src/org/jetbrains/kotlin/incremental/storage/ClassAttributesMap.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.incremental.storage + +import com.intellij.util.io.DataExternalizer +import org.jetbrains.kotlin.name.FqName +import java.io.DataInput +import java.io.DataOutput +import java.io.File + +internal data class ICClassesAttributes(val isSealed: Boolean) + +internal object ICClassesAttributesExternalizer : DataExternalizer { + override fun read(input: DataInput): ICClassesAttributes { + return ICClassesAttributes(input.readBoolean()) + } + + override fun save(output: DataOutput, value: ICClassesAttributes) { + output.writeBoolean(value.isSealed) + } +} + +internal open class ClassAttributesMap( + storageFile: File +) : BasicStringMap(storageFile, ICClassesAttributesExternalizer) { + override fun dumpValue(value: ICClassesAttributes): String = value.toString() + + operator fun set(key: FqName, value: ICClassesAttributes) { + storage[key.asString()] = value + } + + operator fun get(key: FqName): ICClassesAttributes? = storage[key.asString()] + + fun remove(key: FqName) { + storage.remove(key.asString()) + } +} diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt index ecdbf02d6b2..450e25eb3d3 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt @@ -310,9 +310,10 @@ abstract class IncrementalCompilerRunner< } if (compilationMode is CompilationMode.Rebuild) break - val (dirtyLookupSymbols, dirtyClassFqNames) = changesCollector.getDirtyData(listOf(caches.platformCache), reporter) + val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = changesCollector.getDirtyData(listOf(caches.platformCache), reporter) val compiledInThisIterationSet = sourcesToCompile.toHashSet() + val forceToRecompileFiles = mapClassesFqNamesToFiles(listOf(caches.platformCache), forceRecompile, reporter) with(dirtySources) { clear() addAll(mapLookupSymbolsToFiles(caches.lookupCache, dirtyLookupSymbols, reporter, excludes = compiledInThisIterationSet)) @@ -324,6 +325,9 @@ abstract class IncrementalCompilerRunner< excludes = compiledInThisIterationSet ) ) + if (!compiledInThisIterationSet.containsAll(forceToRecompileFiles)) { + addAll(forceToRecompileFiles) + } } buildDirtyLookupSymbols.addAll(dirtyLookupSymbols) diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJsCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJsCompilerRunner.kt index 09c17ebfd2f..963fa236ddd 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJsCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJsCompilerRunner.kt @@ -125,7 +125,7 @@ class IncrementalJsCompilerRunner( val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles) dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols) dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames) - + dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNamesForceRecompile) return CompilationMode.Incremental(dirtyFiles) } diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt index c85f8e6d573..9c5da3b4972 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt @@ -227,7 +227,7 @@ class IncrementalJvmCompilerRunner( dirtyFiles.addByDirtySymbols(androidLayoutChanges) dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols) dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames) - + dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNamesForceRecompile) return CompilationMode.Incremental(dirtyFiles) } diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt index 4065354f67c..da16372d4c1 100644 --- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt @@ -90,6 +90,8 @@ abstract class AbstractProtoComparisonTest : TestWithWorkingDir() { when (it) { is ChangeInfo.SignatureChanged -> "CLASS_SIGNATURE" is ChangeInfo.MembersChanged -> "MEMBERS\n ${it.names.sorted()}" + is ChangeInfo.ParentsChanged -> "PARENTS\n ${it.parentsChanged.map { it.asString()}.sorted()}" + } }.sorted() 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 d0b97301a60..04afe480d2c 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt @@ -250,7 +250,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) { removedClasses.forEach { changesCollector.collectSignature(FqName(it), areSubclassesAffected = true) } val affectedByRemovedClasses = changesCollector.getDirtyFiles(incrementalCaches.values, kotlinContext.lookupStorageManager) - fsOperations.markFilesForCurrentRound(affectedByRemovedClasses) + fsOperations.markFilesForCurrentRound(affectedByRemovedClasses.dirtyFiles + affectedByRemovedClasses.forceRecompileTogether) } override fun chunkBuildFinished(context: CompileContext, chunk: ModuleChunk) { @@ -695,21 +695,36 @@ private fun ChangesCollector.processChangesUsingLookups( reporter.reportVerbose { "Start processing changes" } val dirtyFiles = getDirtyFiles(allCaches, lookupStorageManager) - fsOperations.markInChunkOrDependents(dirtyFiles.asIterable(), excludeFiles = compiledFiles) + // if list of inheritors of sealed class has changed it should be recompiled with all the inheritors + // Here we have a small optimization. Do not recompile the bunch if ALL these files were recompiled during the previous round. + val excludeFiles = if (compiledFiles.containsAll(dirtyFiles.forceRecompileTogether)) + compiledFiles + else + compiledFiles.minus(dirtyFiles.forceRecompileTogether) + fsOperations.markInChunkOrDependents( + (dirtyFiles.dirtyFiles + dirtyFiles.forceRecompileTogether).asIterable(), + excludeFiles = excludeFiles + ) reporter.reportVerbose { "End of processing changes" } } +data class FilesToRecompile(val dirtyFiles: Set, val forceRecompileTogether: Set) + private fun ChangesCollector.getDirtyFiles( caches: Iterable, lookupStorageManager: JpsLookupStorageManager -): Set { +): FilesToRecompile { val reporter = JpsICReporter() - val (dirtyLookupSymbols, dirtyClassFqNames) = getDirtyData(caches, reporter) + val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = getDirtyData(caches, reporter) val dirtyFilesFromLookups = lookupStorageManager.withLookupStorage { mapLookupSymbolsToFiles(it, dirtyLookupSymbols, reporter) } - return dirtyFilesFromLookups + mapClassesFqNamesToFiles(caches, dirtyClassFqNames, reporter) + return FilesToRecompile( + dirtyFilesFromLookups + mapClassesFqNamesToFiles(caches, dirtyClassFqNames, reporter), + mapClassesFqNamesToFiles(caches, forceRecompile, reporter) + ) + } private fun getLookupTracker(project: JpsProject, representativeTarget: KotlinModuleBuildTarget<*>): LookupTracker {