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).
This commit is contained in:
committed by
Andrey Uskov
parent
a0651cdba7
commit
36f99156fd
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.incremental
|
|||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.storage.*
|
import org.jetbrains.kotlin.incremental.storage.*
|
||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
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.NameResolver
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.supertypes
|
import org.jetbrains.kotlin.metadata.deserialization.supertypes
|
||||||
@@ -34,12 +35,15 @@ interface IncrementalCacheCommon {
|
|||||||
val thisWithDependentCaches: Iterable<AbstractIncrementalCache<*>>
|
val thisWithDependentCaches: Iterable<AbstractIncrementalCache<*>>
|
||||||
fun classesFqNamesBySources(files: Iterable<File>): Collection<FqName>
|
fun classesFqNamesBySources(files: Iterable<File>): Collection<FqName>
|
||||||
fun getSubtypesOf(className: FqName): Sequence<FqName>
|
fun getSubtypesOf(className: FqName): Sequence<FqName>
|
||||||
|
fun getSupertypesOf(className: FqName): Sequence<FqName>
|
||||||
fun getSourceFileIfClass(fqName: FqName): File?
|
fun getSourceFileIfClass(fqName: FqName): File?
|
||||||
fun markDirty(removedAndCompiledSources: Collection<File>)
|
fun markDirty(removedAndCompiledSources: Collection<File>)
|
||||||
fun clearCacheForRemovedClasses(changesCollector: ChangesCollector)
|
fun clearCacheForRemovedClasses(changesCollector: ChangesCollector)
|
||||||
fun getComplementaryFilesRecursive(dirtyFiles: Collection<File>): Collection<File>
|
fun getComplementaryFilesRecursive(dirtyFiles: Collection<File>): Collection<File>
|
||||||
fun updateComplementaryFiles(dirtyFiles: Collection<File>, expectActualTracker: ExpectActualTrackerImpl)
|
fun updateComplementaryFiles(dirtyFiles: Collection<File>, expectActualTracker: ExpectActualTrackerImpl)
|
||||||
fun dump(): String
|
fun dump(): String
|
||||||
|
|
||||||
|
fun isSealed(className: FqName): Boolean?
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,6 +54,7 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
protected val pathConverter: FileToPathConverter
|
protected val pathConverter: FileToPathConverter
|
||||||
) : BasicMapsOwner(workingDir), IncrementalCacheCommon {
|
) : BasicMapsOwner(workingDir), IncrementalCacheCommon {
|
||||||
companion object {
|
companion object {
|
||||||
|
private val CLASS_ATTRIBUTES = "class-attributes"
|
||||||
private val SUBTYPES = "subtypes"
|
private val SUBTYPES = "subtypes"
|
||||||
private val SUPERTYPES = "supertypes"
|
private val SUPERTYPES = "supertypes"
|
||||||
private val CLASS_FQ_NAME_TO_SOURCE = "class-fq-name-to-source"
|
private val CLASS_FQ_NAME_TO_SOURCE = "class-fq-name-to-source"
|
||||||
@@ -71,6 +76,7 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val classAttributesMap = registerMap(ClassAttributesMap(CLASS_ATTRIBUTES.storageFile))
|
||||||
private val subtypesMap = registerMap(SubtypesMap(SUBTYPES.storageFile))
|
private val subtypesMap = registerMap(SubtypesMap(SUBTYPES.storageFile))
|
||||||
private val supertypesMap = registerMap(SupertypesMap(SUPERTYPES.storageFile))
|
private val supertypesMap = registerMap(SupertypesMap(SUPERTYPES.storageFile))
|
||||||
protected val classFqNameToSourceMap = registerMap(ClassFqNameToSourceMap(CLASS_FQ_NAME_TO_SOURCE.storageFile, pathConverter))
|
protected val classFqNameToSourceMap = registerMap(ClassFqNameToSourceMap(CLASS_FQ_NAME_TO_SOURCE.storageFile, pathConverter))
|
||||||
@@ -90,6 +96,14 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
override fun getSubtypesOf(className: FqName): Sequence<FqName> =
|
override fun getSubtypesOf(className: FqName): Sequence<FqName> =
|
||||||
subtypesMap[className].asSequence()
|
subtypesMap[className].asSequence()
|
||||||
|
|
||||||
|
override fun getSupertypesOf(className: FqName): Sequence<FqName> {
|
||||||
|
return supertypesMap[className].asSequence()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSealed(className: FqName): Boolean? {
|
||||||
|
return classAttributesMap[className]?.isSealed
|
||||||
|
}
|
||||||
|
|
||||||
override fun getSourceFileIfClass(fqName: FqName): File? =
|
override fun getSourceFileIfClass(fqName: FqName): File? =
|
||||||
classFqNameToSourceMap[fqName]
|
classFqNameToSourceMap[fqName]
|
||||||
|
|
||||||
@@ -118,6 +132,7 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
|
|
||||||
supertypesMap[child] = parents
|
supertypesMap[child] = parents
|
||||||
classFqNameToSourceMap[child] = srcFile
|
classFqNameToSourceMap[child] = srcFile
|
||||||
|
classAttributesMap[child] = ICClassesAttributes(ProtoBuf.Modality.SEALED == Flags.MODALITY.get(proto.flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun removeAllFromClassStorage(removedClasses: Collection<FqName>, changesCollector: ChangesCollector) {
|
protected fun removeAllFromClassStorage(removedClasses: Collection<FqName>, changesCollector: ChangesCollector) {
|
||||||
@@ -152,7 +167,10 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removedFqNames.forEach { classFqNameToSourceMap.remove(it) }
|
removedFqNames.forEach {
|
||||||
|
classFqNameToSourceMap.remove(it)
|
||||||
|
classAttributesMap.remove(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class ClassFqNameToSourceMap(
|
protected class ClassFqNameToSourceMap(
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ package org.jetbrains.kotlin.incremental
|
|||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.supertypes
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
|
|
||||||
class ChangesCollector {
|
class ChangesCollector {
|
||||||
private val removedMembers = hashMapOf<FqName, MutableSet<String>>()
|
private val removedMembers = hashMapOf<FqName, MutableSet<String>>()
|
||||||
|
private val changedParents = hashMapOf<FqName, MutableSet<FqName>>()
|
||||||
private val changedMembers = hashMapOf<FqName, MutableSet<String>>()
|
private val changedMembers = hashMapOf<FqName, MutableSet<String>>()
|
||||||
private val areSubclassesAffected = hashMapOf<FqName, Boolean>()
|
private val areSubclassesAffected = hashMapOf<FqName, Boolean>()
|
||||||
|
|
||||||
@@ -47,6 +49,10 @@ class ChangesCollector {
|
|||||||
changes.add(ChangeInfo.SignatureChanged(fqName, areSubclassesAffected))
|
changes.add(ChangeInfo.SignatureChanged(fqName, areSubclassesAffected))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ((fqName, changedParents) in changedParents) {
|
||||||
|
changes.add(ChangeInfo.ParentsChanged(fqName, changedParents))
|
||||||
|
}
|
||||||
|
|
||||||
return changes
|
return changes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,12 +85,12 @@ class ChangesCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (oldData == null) {
|
if (oldData == null) {
|
||||||
newData!!.collectAll(isRemoved = false, collectAllMembersForNewClass = collectAllMembersForNewClass)
|
newData!!.collectAll(isRemoved = false, isAdded = true, collectAllMembersForNewClass = collectAllMembersForNewClass)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newData == null) {
|
if (newData == null) {
|
||||||
oldData.collectAll(isRemoved = true)
|
oldData.collectAll(isRemoved = true, isAdded = false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +104,7 @@ class ChangesCollector {
|
|||||||
collectSignature(oldData, diff.areSubclassesAffected)
|
collectSignature(oldData, diff.areSubclassesAffected)
|
||||||
}
|
}
|
||||||
collectChangedMembers(fqName, diff.changedMembersNames)
|
collectChangedMembers(fqName, diff.changedMembersNames)
|
||||||
|
addChangedParents(fqName, diff.changedSupertypes)
|
||||||
}
|
}
|
||||||
is PackagePartProtoData -> {
|
is PackagePartProtoData -> {
|
||||||
collectSignature(oldData, areSubclassesAffected = true)
|
collectSignature(oldData, areSubclassesAffected = true)
|
||||||
@@ -121,10 +128,11 @@ class ChangesCollector {
|
|||||||
private fun <T> T.getNonPrivateNames(nameResolver: NameResolver, vararg members: T.() -> List<MessageLite>): Set<String> =
|
private fun <T> T.getNonPrivateNames(nameResolver: NameResolver, vararg members: T.() -> List<MessageLite>): Set<String> =
|
||||||
members.flatMap { this.it().filterNot { it.isPrivate }.names(nameResolver) }.toSet()
|
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) {
|
when (this) {
|
||||||
is PackagePartProtoData -> collectAllFromPackage(isRemoved)
|
is PackagePartProtoData -> collectAllFromPackage(isRemoved)
|
||||||
is ClassProtoData -> collectAllFromClass(isRemoved, collectAllMembersForNewClass)
|
is ClassProtoData -> collectAllFromClass(isRemoved, isAdded, collectAllMembersForNewClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PackagePartProtoData.collectAllFromPackage(isRemoved: Boolean) {
|
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 classFqName = nameResolver.getClassId(proto.fqName).asSingleFqName()
|
||||||
val kind = Flags.CLASS_KIND.get(proto.flags)
|
val kind = Flags.CLASS_KIND.get(proto.flags)
|
||||||
|
|
||||||
@@ -162,6 +170,23 @@ class ChangesCollector {
|
|||||||
|
|
||||||
collectSignature(classFqName, areSubclassesAffected = true)
|
collectSignature(classFqName, areSubclassesAffected = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isRemoved || isAdded) {
|
||||||
|
collectChangedParents(classFqName, proto.supertypeList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addChangedParents(fqName: FqName, parents: Collection<FqName>) {
|
||||||
|
if (parents.isNotEmpty()) {
|
||||||
|
changedParents.getOrPut(fqName) { HashSet() }.addAll(parents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ClassProtoData.collectChangedParents(fqName: FqName, parents: Collection<ProtoBuf.Type>) {
|
||||||
|
val changedParentsFqNames = parents.map { type ->
|
||||||
|
nameResolver.getClassId(type.className).asSingleFqName()
|
||||||
|
}
|
||||||
|
addChangedParents(fqName, changedParentsFqNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ClassProtoData.getNonPrivateMemberNames(): Set<String> {
|
private fun ClassProtoData.getNonPrivateMemberNames(): Set<String> {
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ open class IncrementalJvmCache(
|
|||||||
}
|
}
|
||||||
protoMap.remove(className, changesCollector)
|
protoMap.remove(className, changesCollector)
|
||||||
classFqNameToSourceMap.remove(className.fqNameForClassNameWithoutDollars)
|
classFqNameToSourceMap.remove(className.fqNameForClassNameWithoutDollars)
|
||||||
|
classAttributesMap.remove(className.fqNameForClassNameWithoutDollars)
|
||||||
internalNameToSource.remove(className.internalName)
|
internalNameToSource.remove(className.internalName)
|
||||||
|
|
||||||
// TODO NO_CHANGES? (delegates only)
|
// 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 SignatureChanged(fqName: FqName, val areSubclassesAffected: Boolean) : ChangeInfo(fqName)
|
||||||
|
|
||||||
|
class ParentsChanged(fqName: FqName, val parentsChanged: Collection<FqName>) : ChangeInfo(fqName)
|
||||||
|
|
||||||
protected open fun toStringProperties(): String = "fqName = $fqName"
|
protected open fun toStringProperties(): String = "fqName = $fqName"
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,8 @@ fun LookupStorage.update(
|
|||||||
|
|
||||||
data class DirtyData(
|
data class DirtyData(
|
||||||
val dirtyLookupSymbols: Collection<LookupSymbol> = emptyList(),
|
val dirtyLookupSymbols: Collection<LookupSymbol> = emptyList(),
|
||||||
val dirtyClassesFqNames: Collection<FqName> = emptyList()
|
val dirtyClassesFqNames: Collection<FqName> = emptyList(),
|
||||||
|
val dirtyClassesFqNamesForceRecompile: Collection<FqName> = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ChangesCollector.getDirtyData(
|
fun ChangesCollector.getDirtyData(
|
||||||
@@ -146,6 +147,9 @@ fun ChangesCollector.getDirtyData(
|
|||||||
val dirtyLookupSymbols = HashSet<LookupSymbol>()
|
val dirtyLookupSymbols = HashSet<LookupSymbol>()
|
||||||
val dirtyClassesFqNames = HashSet<FqName>()
|
val dirtyClassesFqNames = HashSet<FqName>()
|
||||||
|
|
||||||
|
val sealedParents = HashMap<FqName, MutableSet<FqName>>()
|
||||||
|
val notSealedParents = HashSet<FqName>()
|
||||||
|
|
||||||
for (change in changes()) {
|
for (change in changes()) {
|
||||||
reporter.reportVerbose { "Process $change" }
|
reporter.reportVerbose { "Process $change" }
|
||||||
|
|
||||||
@@ -170,10 +174,35 @@ fun ChangesCollector.getDirtyData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fqNames.mapTo(dirtyLookupSymbols) { LookupSymbol(SAM_LOOKUP_NAME.asString(), it.asString()) }
|
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<FqName>().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(
|
fun mapLookupSymbolsToFiles(
|
||||||
@@ -217,6 +246,11 @@ fun mapClassesFqNamesToFiles(
|
|||||||
return fqNameToAffectedFiles.values.flattenTo(HashSet())
|
return fqNameToAffectedFiles.values.flattenTo(HashSet())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isSealed(
|
||||||
|
fqName: FqName,
|
||||||
|
caches: Iterable<IncrementalCacheCommon>
|
||||||
|
): Boolean = caches.any { it.isSealed(fqName) ?: false }
|
||||||
|
|
||||||
fun withSubtypes(
|
fun withSubtypes(
|
||||||
typeFqName: FqName,
|
typeFqName: FqName,
|
||||||
caches: Iterable<IncrementalCacheCommon>
|
caches: Iterable<IncrementalCacheCommon>
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptorVisibility
|
import org.jetbrains.kotlin.serialization.deserialization.descriptorVisibility
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class Difference(
|
data class Difference(
|
||||||
val isClassAffected: Boolean = false,
|
val isClassAffected: Boolean = false,
|
||||||
val areSubclassesAffected: Boolean = false,
|
val areSubclassesAffected: Boolean = false,
|
||||||
val changedMembersNames: Set<String> = emptySet()
|
val changedMembersNames: Set<String> = emptySet(),
|
||||||
|
val changedSupertypes: Set<FqName> = emptySet()
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed class ProtoData
|
sealed class ProtoData
|
||||||
@@ -187,6 +189,7 @@ class DifferenceCalculatorForClass(
|
|||||||
|
|
||||||
var isClassAffected = false
|
var isClassAffected = false
|
||||||
var areSubclassesAffected = false
|
var areSubclassesAffected = false
|
||||||
|
val changedSupertypes = HashSet<FqName>()
|
||||||
val names = hashSetOf<String>()
|
val names = hashSetOf<String>()
|
||||||
val classIsSealed = newProto.isSealed && oldProto.isSealed
|
val classIsSealed = newProto.isSealed && oldProto.isSealed
|
||||||
|
|
||||||
@@ -247,12 +250,21 @@ class DifferenceCalculatorForClass(
|
|||||||
ProtoBufClassKind.FLAGS,
|
ProtoBufClassKind.FLAGS,
|
||||||
ProtoBufClassKind.FQ_NAME,
|
ProtoBufClassKind.FQ_NAME,
|
||||||
ProtoBufClassKind.TYPE_PARAMETER_LIST,
|
ProtoBufClassKind.TYPE_PARAMETER_LIST,
|
||||||
ProtoBufClassKind.SUPERTYPE_LIST,
|
|
||||||
ProtoBufClassKind.SUPERTYPE_ID_LIST,
|
|
||||||
ProtoBufClassKind.JS_EXT_CLASS_ANNOTATION_LIST -> {
|
ProtoBufClassKind.JS_EXT_CLASS_ANNOTATION_LIST -> {
|
||||||
isClassAffected = true
|
isClassAffected = true
|
||||||
areSubclassesAffected = 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.JVM_EXT_CLASS_MODULE_NAME,
|
||||||
ProtoBufClassKind.JS_EXT_CLASS_CONTAINING_FILE_ID -> {
|
ProtoBufClassKind.JS_EXT_CLASS_CONTAINING_FILE_ID -> {
|
||||||
// TODO
|
// TODO
|
||||||
@@ -281,7 +293,7 @@ class DifferenceCalculatorForClass(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Difference(isClassAffected, areSubclassesAffected, names)
|
return Difference(isClassAffected, areSubclassesAffected, names, changedSupertypes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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<ICClassesAttributes> {
|
||||||
|
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<ICClassesAttributes>(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())
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-1
@@ -310,9 +310,10 @@ abstract class IncrementalCompilerRunner<
|
|||||||
}
|
}
|
||||||
if (compilationMode is CompilationMode.Rebuild) break
|
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 compiledInThisIterationSet = sourcesToCompile.toHashSet()
|
||||||
|
|
||||||
|
val forceToRecompileFiles = mapClassesFqNamesToFiles(listOf(caches.platformCache), forceRecompile, reporter)
|
||||||
with(dirtySources) {
|
with(dirtySources) {
|
||||||
clear()
|
clear()
|
||||||
addAll(mapLookupSymbolsToFiles(caches.lookupCache, dirtyLookupSymbols, reporter, excludes = compiledInThisIterationSet))
|
addAll(mapLookupSymbolsToFiles(caches.lookupCache, dirtyLookupSymbols, reporter, excludes = compiledInThisIterationSet))
|
||||||
@@ -324,6 +325,9 @@ abstract class IncrementalCompilerRunner<
|
|||||||
excludes = compiledInThisIterationSet
|
excludes = compiledInThisIterationSet
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if (!compiledInThisIterationSet.containsAll(forceToRecompileFiles)) {
|
||||||
|
addAll(forceToRecompileFiles)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildDirtyLookupSymbols.addAll(dirtyLookupSymbols)
|
buildDirtyLookupSymbols.addAll(dirtyLookupSymbols)
|
||||||
|
|||||||
+1
-1
@@ -125,7 +125,7 @@ class IncrementalJsCompilerRunner(
|
|||||||
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
|
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
|
||||||
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
||||||
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
||||||
|
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNamesForceRecompile)
|
||||||
return CompilationMode.Incremental(dirtyFiles)
|
return CompilationMode.Incremental(dirtyFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -227,7 +227,7 @@ class IncrementalJvmCompilerRunner(
|
|||||||
dirtyFiles.addByDirtySymbols(androidLayoutChanges)
|
dirtyFiles.addByDirtySymbols(androidLayoutChanges)
|
||||||
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
||||||
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
||||||
|
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNamesForceRecompile)
|
||||||
return CompilationMode.Incremental(dirtyFiles)
|
return CompilationMode.Incremental(dirtyFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -90,6 +90,8 @@ abstract class AbstractProtoComparisonTest<PROTO_DATA> : TestWithWorkingDir() {
|
|||||||
when (it) {
|
when (it) {
|
||||||
is ChangeInfo.SignatureChanged -> "CLASS_SIGNATURE"
|
is ChangeInfo.SignatureChanged -> "CLASS_SIGNATURE"
|
||||||
is ChangeInfo.MembersChanged -> "MEMBERS\n ${it.names.sorted()}"
|
is ChangeInfo.MembersChanged -> "MEMBERS\n ${it.names.sorted()}"
|
||||||
|
is ChangeInfo.ParentsChanged -> "PARENTS\n ${it.parentsChanged.map { it.asString()}.sorted()}"
|
||||||
|
|
||||||
}
|
}
|
||||||
}.sorted()
|
}.sorted()
|
||||||
|
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
|||||||
removedClasses.forEach { changesCollector.collectSignature(FqName(it), areSubclassesAffected = true) }
|
removedClasses.forEach { changesCollector.collectSignature(FqName(it), areSubclassesAffected = true) }
|
||||||
val affectedByRemovedClasses = changesCollector.getDirtyFiles(incrementalCaches.values, kotlinContext.lookupStorageManager)
|
val affectedByRemovedClasses = changesCollector.getDirtyFiles(incrementalCaches.values, kotlinContext.lookupStorageManager)
|
||||||
|
|
||||||
fsOperations.markFilesForCurrentRound(affectedByRemovedClasses)
|
fsOperations.markFilesForCurrentRound(affectedByRemovedClasses.dirtyFiles + affectedByRemovedClasses.forceRecompileTogether)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chunkBuildFinished(context: CompileContext, chunk: ModuleChunk) {
|
override fun chunkBuildFinished(context: CompileContext, chunk: ModuleChunk) {
|
||||||
@@ -695,21 +695,36 @@ private fun ChangesCollector.processChangesUsingLookups(
|
|||||||
reporter.reportVerbose { "Start processing changes" }
|
reporter.reportVerbose { "Start processing changes" }
|
||||||
|
|
||||||
val dirtyFiles = getDirtyFiles(allCaches, lookupStorageManager)
|
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" }
|
reporter.reportVerbose { "End of processing changes" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class FilesToRecompile(val dirtyFiles: Set<File>, val forceRecompileTogether: Set<File>)
|
||||||
|
|
||||||
private fun ChangesCollector.getDirtyFiles(
|
private fun ChangesCollector.getDirtyFiles(
|
||||||
caches: Iterable<IncrementalCacheCommon>,
|
caches: Iterable<IncrementalCacheCommon>,
|
||||||
lookupStorageManager: JpsLookupStorageManager
|
lookupStorageManager: JpsLookupStorageManager
|
||||||
): Set<File> {
|
): FilesToRecompile {
|
||||||
val reporter = JpsICReporter()
|
val reporter = JpsICReporter()
|
||||||
val (dirtyLookupSymbols, dirtyClassFqNames) = getDirtyData(caches, reporter)
|
val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = getDirtyData(caches, reporter)
|
||||||
val dirtyFilesFromLookups = lookupStorageManager.withLookupStorage {
|
val dirtyFilesFromLookups = lookupStorageManager.withLookupStorage {
|
||||||
mapLookupSymbolsToFiles(it, dirtyLookupSymbols, reporter)
|
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 {
|
private fun getLookupTracker(project: JpsProject, representativeTarget: KotlinModuleBuildTarget<*>): LookupTracker {
|
||||||
|
|||||||
Reference in New Issue
Block a user