[IC] Refactor IC maps to reuse code and ensure consistency - Part 2
In commit 4e89dcf, we have prepared the API for IC maps in top
interfaces and provide the implementation in abstract classes.
In this commit, we refactor IC maps so that they directly inherit/reuse
the implementation from the superclasses without having to reimplement
the APIs for a map.
Test: Existing tests (refactoring change)
^KT-63456: In progress
Authored-by: Hung Nguyen <hungnv@google.com>
Merge-request: KOTLIN-MR-801
Merged-by: Evgenii Mazhukin <evgenii.mazhukin@jetbrains.com>
This commit is contained in:
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental
|
package org.jetbrains.kotlin.incremental
|
||||||
|
|
||||||
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.Flags
|
||||||
@@ -26,7 +25,6 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.HashSet
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Incremental cache common for JVM and JS, ClassName type aware
|
* Incremental cache common for JVM and JS, ClassName type aware
|
||||||
@@ -94,13 +92,13 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
private val complementaryFilesMap = registerMap(ComplementarySourceFilesMap(COMPLEMENTARY_FILES.storageFile, icContext))
|
private val complementaryFilesMap = registerMap(ComplementarySourceFilesMap(COMPLEMENTARY_FILES.storageFile, icContext))
|
||||||
|
|
||||||
override fun classesFqNamesBySources(files: Iterable<File>): Collection<FqName> =
|
override fun classesFqNamesBySources(files: Iterable<File>): Collection<FqName> =
|
||||||
files.flatMapTo(HashSet()) { sourceToClassesMap.getFqNames(it) }
|
files.flatMapTo(mutableSetOf()) { sourceToClassesMap.getFqNames(it).orEmpty() }
|
||||||
|
|
||||||
override fun getSubtypesOf(className: FqName): Sequence<FqName> =
|
override fun getSubtypesOf(className: FqName): Sequence<FqName> =
|
||||||
subtypesMap[className].asSequence()
|
subtypesMap[className].orEmpty().asSequence()
|
||||||
|
|
||||||
override fun getSupertypesOf(className: FqName): Sequence<FqName> {
|
override fun getSupertypesOf(className: FqName): Sequence<FqName> {
|
||||||
return supertypesMap[className].asSequence()
|
return supertypesMap[className].orEmpty().asSequence()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isSealed(className: FqName): Boolean? {
|
override fun isSealed(className: FqName): Boolean? {
|
||||||
@@ -112,10 +110,10 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
|
|
||||||
override fun markDirty(removedAndCompiledSources: Collection<File>) {
|
override fun markDirty(removedAndCompiledSources: Collection<File>) {
|
||||||
for (sourceFile in removedAndCompiledSources) {
|
for (sourceFile in removedAndCompiledSources) {
|
||||||
sourceToClassesMap[sourceFile].forEach { className ->
|
sourceToClassesMap[sourceFile]?.forEach { className ->
|
||||||
markDirty(className)
|
markDirty(className)
|
||||||
}
|
}
|
||||||
sourceToClassesMap.clearOutputsForSource(sourceFile)
|
sourceToClassesMap.remove(sourceFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,9 +135,9 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
.toSet()
|
.toSet()
|
||||||
val child = nameResolver.getClassId(proto.fqName).asSingleFqName()
|
val child = nameResolver.getClassId(proto.fqName).asSingleFqName()
|
||||||
|
|
||||||
parents.forEach { subtypesMap.add(it, child) }
|
parents.forEach { subtypesMap.append(it, child) }
|
||||||
|
|
||||||
val removedSupertypes = supertypesMap[child].filter { it !in parents }
|
val removedSupertypes = supertypesMap[child].orEmpty().filter { it !in parents }
|
||||||
removedSupertypes.forEach { subtypesMap.removeValues(it, setOf(child)) }
|
removedSupertypes.forEach { subtypesMap.removeValues(it, setOf(child)) }
|
||||||
|
|
||||||
supertypesMap[child] = parents
|
supertypesMap[child] = parents
|
||||||
@@ -163,8 +161,8 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
val childrenFqNames = hashSetOf<FqName>()
|
val childrenFqNames = hashSetOf<FqName>()
|
||||||
|
|
||||||
for (removedFqName in removedFqNames) {
|
for (removedFqName in removedFqNames) {
|
||||||
parentsFqNames.addAll(cache.supertypesMap[removedFqName])
|
parentsFqNames.addAll(cache.supertypesMap[removedFqName].orEmpty())
|
||||||
childrenFqNames.addAll(cache.subtypesMap[removedFqName])
|
childrenFqNames.addAll(cache.subtypesMap[removedFqName].orEmpty())
|
||||||
|
|
||||||
cache.supertypesMap.remove(removedFqName)
|
cache.supertypesMap.remove(removedFqName)
|
||||||
cache.subtypesMap.remove(removedFqName)
|
cache.subtypesMap.remove(removedFqName)
|
||||||
@@ -188,20 +186,12 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
protected class ClassFqNameToSourceMap(
|
protected class ClassFqNameToSourceMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : BasicStringMap<String>(storageFile, EnumeratorStringDescriptor(), PathStringDescriptor, icContext) {
|
) : AbstractBasicMap<FqName, File>(
|
||||||
operator fun set(fqName: FqName, sourceFile: File) {
|
storageFile,
|
||||||
storage[fqName.asString()] = pathConverter.toPath(sourceFile)
|
FqNameExternalizer.toDescriptor(),
|
||||||
}
|
icContext.fileDescriptorForSourceFiles,
|
||||||
|
icContext
|
||||||
operator fun get(fqName: FqName): File? =
|
)
|
||||||
storage[fqName.asString()]?.let(pathConverter::toFile)
|
|
||||||
|
|
||||||
fun remove(fqName: FqName) {
|
|
||||||
storage.remove(fqName.asString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dumpValue(value: String) = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getComplementaryFilesRecursive(dirtyFiles: Collection<File>): Collection<File> {
|
override fun getComplementaryFilesRecursive(dirtyFiles: Collection<File>): Collection<File> {
|
||||||
val complementaryFiles = HashSet<File>()
|
val complementaryFiles = HashSet<File>()
|
||||||
@@ -216,10 +206,10 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
processedFiles.add(file)
|
processedFiles.add(file)
|
||||||
complementaryFilesMap[file].forEach {
|
complementaryFilesMap[file]?.forEach {
|
||||||
if (complementaryFiles.add(it) && !processedFiles.contains(it)) filesQueue.add(it)
|
if (complementaryFiles.add(it) && !processedFiles.contains(it)) filesQueue.add(it)
|
||||||
}
|
}
|
||||||
val classes2recompile = sourceToClassesMap.getFqNames(file)
|
val classes2recompile = sourceToClassesMap.getFqNames(file).orEmpty()
|
||||||
classes2recompile.filter { !processedClasses.contains(it) }.forEach { class2recompile ->
|
classes2recompile.filter { !processedClasses.contains(it) }.forEach { class2recompile ->
|
||||||
processedClasses.add(class2recompile)
|
processedClasses.add(class2recompile)
|
||||||
val sealedClasses = findSealedSupertypes(class2recompile, listOf(this))
|
val sealedClasses = findSealedSupertypes(class2recompile, listOf(this))
|
||||||
@@ -248,11 +238,11 @@ abstract class AbstractIncrementalCache<ClassName>(
|
|||||||
for (actual in actuals) {
|
for (actual in actuals) {
|
||||||
actualToExpect.getOrPut(actual) { hashSetOf() }.add(expect)
|
actualToExpect.getOrPut(actual) { hashSetOf() }.add(expect)
|
||||||
}
|
}
|
||||||
complementaryFilesMap[expect] = actuals.union(complementaryFilesMap[expect])
|
complementaryFilesMap[expect] = actuals.union(complementaryFilesMap[expect].orEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((actual, expects) in actualToExpect) {
|
for ((actual, expects) in actualToExpect) {
|
||||||
complementaryFilesMap[actual] = expects.union(complementaryFilesMap[actual])
|
complementaryFilesMap[actual] = expects.union(complementaryFilesMap[actual].orEmpty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,15 +5,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental
|
package org.jetbrains.kotlin.incremental
|
||||||
|
|
||||||
|
import com.intellij.util.io.KeyDescriptor
|
||||||
import org.jetbrains.kotlin.build.report.DoNothingICReporter
|
import org.jetbrains.kotlin.build.report.DoNothingICReporter
|
||||||
import org.jetbrains.kotlin.build.report.ICReporter
|
import org.jetbrains.kotlin.build.report.ICReporter
|
||||||
import org.jetbrains.kotlin.incremental.storage.FileToAbsolutePathConverter
|
import org.jetbrains.kotlin.incremental.storage.BasicFileToPathConverter
|
||||||
import org.jetbrains.kotlin.incremental.storage.FileToPathConverter
|
import org.jetbrains.kotlin.incremental.storage.FileToPathConverter
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class IncrementalCompilationContext(
|
class IncrementalCompilationContext(
|
||||||
// The root directories of source files and output files are different, so we may need different `FileToPathConverter`s
|
// The root directories of source files and output files are different, so we need different `FileToPathConverter`s
|
||||||
val pathConverterForSourceFiles: FileToPathConverter = FileToAbsolutePathConverter,
|
val pathConverterForSourceFiles: FileToPathConverter = BasicFileToPathConverter,
|
||||||
val pathConverterForOutputFiles: FileToPathConverter = FileToAbsolutePathConverter,
|
val pathConverterForOutputFiles: FileToPathConverter = BasicFileToPathConverter,
|
||||||
val storeFullFqNamesInLookupCache: Boolean = false,
|
val storeFullFqNamesInLookupCache: Boolean = false,
|
||||||
val transaction: CompilationTransaction = NonRecoverableCompilationTransaction(),
|
val transaction: CompilationTransaction = NonRecoverableCompilationTransaction(),
|
||||||
val reporter: ICReporter = DoNothingICReporter,
|
val reporter: ICReporter = DoNothingICReporter,
|
||||||
@@ -46,7 +48,6 @@ class IncrementalCompilationContext(
|
|||||||
keepIncrementalCompilationCachesInMemory
|
keepIncrementalCompilationCachesInMemory
|
||||||
)
|
)
|
||||||
|
|
||||||
// FIXME: Remove `pathConverter` and require its users to decide whether to use `pathConverterForSourceFiles` or
|
val fileDescriptorForSourceFiles: KeyDescriptor<File> = pathConverterForSourceFiles.getFileDescriptor()
|
||||||
// `pathConverterForOutputFiles`
|
val fileDescriptorForOutputFiles: KeyDescriptor<File> = pathConverterForOutputFiles.getFileDescriptor()
|
||||||
val pathConverter = pathConverterForSourceFiles
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.incremental
|
package org.jetbrains.kotlin.incremental
|
||||||
|
|
||||||
import com.intellij.util.io.DataExternalizer
|
import com.intellij.util.io.DataExternalizer
|
||||||
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.build.GeneratedFile
|
import org.jetbrains.kotlin.build.GeneratedFile
|
||||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
|
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
|
||||||
import org.jetbrains.kotlin.incremental.js.IrTranslationResultValue
|
import org.jetbrains.kotlin.incremental.js.IrTranslationResultValue
|
||||||
@@ -79,7 +80,7 @@ open class IncrementalJsCache(
|
|||||||
removedAndCompiledSources.forEach { sourceFile ->
|
removedAndCompiledSources.forEach { sourceFile ->
|
||||||
sourceToJsOutputsMap.remove(sourceFile)
|
sourceToJsOutputsMap.remove(sourceFile)
|
||||||
// The common prefix of all FQN parents has to be the file package
|
// The common prefix of all FQN parents has to be the file package
|
||||||
sourceToClassesMap[sourceFile].map { it.parentOrNull()?.asString() ?: "" }.minByOrNull { it.length }?.let {
|
sourceToClassesMap[sourceFile].orEmpty().map { it.parentOrNull()?.asString() ?: "" }.minByOrNull { it.length }?.let {
|
||||||
packageMetadata.remove(it)
|
packageMetadata.remove(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,7 @@ open class IncrementalJsCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getOutputsBySource(sourceFile: File): Collection<File> {
|
fun getOutputsBySource(sourceFile: File): Collection<File> {
|
||||||
return sourceToJsOutputsMap[sourceFile]
|
return sourceToJsOutputsMap[sourceFile].orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compareAndUpdate(incrementalResults: IncrementalResultsConsumerImpl, changesCollector: ChangesCollector) {
|
fun compareAndUpdate(incrementalResults: IncrementalResultsConsumerImpl, changesCollector: ChangesCollector) {
|
||||||
@@ -132,7 +133,7 @@ open class IncrementalJsCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for ((packageName, metadata) in incrementalResults.packageMetadata) {
|
for ((packageName, metadata) in incrementalResults.packageMetadata) {
|
||||||
packageMetadata.put(packageName, metadata)
|
packageMetadata[packageName] = metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((srcFile, irData) in incrementalResults.irFileData) {
|
for ((srcFile, irData) in incrementalResults.irFileData) {
|
||||||
@@ -142,7 +143,7 @@ open class IncrementalJsCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun registerOutputForFile(srcFile: File, name: FqName) {
|
private fun registerOutputForFile(srcFile: File, name: FqName) {
|
||||||
sourceToClassesMap.add(srcFile, name)
|
sourceToClassesMap.append(srcFile, name)
|
||||||
dirtyOutputClassesMap.notDirty(name)
|
dirtyOutputClassesMap.notDirty(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ open class IncrementalJsCache(
|
|||||||
|
|
||||||
fun nonDirtyPackageParts(): Map<File, TranslationResultValue> =
|
fun nonDirtyPackageParts(): Map<File, TranslationResultValue> =
|
||||||
hashMapOf<File, TranslationResultValue>().apply {
|
hashMapOf<File, TranslationResultValue>().apply {
|
||||||
for (file in translationResults.keys()) {
|
for (file in translationResults.keys) {
|
||||||
|
|
||||||
if (file !in dirtySources) {
|
if (file !in dirtySources) {
|
||||||
put(file, translationResults[file]!!)
|
put(file, translationResults[file]!!)
|
||||||
@@ -175,7 +176,7 @@ open class IncrementalJsCache(
|
|||||||
|
|
||||||
fun nonDirtyIrParts(): Map<File, IrTranslationResultValue> =
|
fun nonDirtyIrParts(): Map<File, IrTranslationResultValue> =
|
||||||
hashMapOf<File, IrTranslationResultValue>().apply {
|
hashMapOf<File, IrTranslationResultValue>().apply {
|
||||||
for (file in irTranslationResults.keys()) {
|
for (file in irTranslationResults.keys) {
|
||||||
|
|
||||||
if (file !in dirtySources) {
|
if (file !in dirtySources) {
|
||||||
put(file, irTranslationResults[file]!!)
|
put(file, irTranslationResults[file]!!)
|
||||||
@@ -189,7 +190,7 @@ open class IncrementalJsCache(
|
|||||||
for (generatedFile in generatedFiles) {
|
for (generatedFile in generatedFiles) {
|
||||||
for (source in generatedFile.sourceFiles) {
|
for (source in generatedFile.sourceFiles) {
|
||||||
if (dirtySources.contains(source))
|
if (dirtySources.contains(source))
|
||||||
sourceToJsOutputsMap.add(source, generatedFile.outputFile)
|
sourceToJsOutputsMap.append(source, generatedFile.outputFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,34 +229,32 @@ private class TranslationResultMap(
|
|||||||
storageFile: File,
|
storageFile: File,
|
||||||
private val protoData: ProtoDataProvider,
|
private val protoData: ProtoDataProvider,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) :
|
) : AbstractBasicMap<File, TranslationResultValue>(
|
||||||
BasicStringMap<TranslationResultValue>(storageFile, TranslationResultValueExternalizer, icContext) {
|
storageFile,
|
||||||
|
icContext.fileDescriptorForSourceFiles,
|
||||||
|
TranslationResultValueExternalizer,
|
||||||
|
icContext
|
||||||
|
) {
|
||||||
|
|
||||||
|
@TestOnly
|
||||||
override fun dumpValue(value: TranslationResultValue): String =
|
override fun dumpValue(value: TranslationResultValue): String =
|
||||||
"Metadata: ${value.metadata.md5()}, Binary AST: ${value.binaryAst.md5()}, InlineData: ${value.inlineData.md5()}"
|
"Metadata: ${value.metadata.md5()}, Binary AST: ${value.binaryAst.md5()}, InlineData: ${value.inlineData.md5()}"
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun put(sourceFile: File, newMetadata: ByteArray, newBinaryAst: ByteArray, newInlineData: ByteArray) {
|
fun put(sourceFile: File, newMetadata: ByteArray, newBinaryAst: ByteArray, newInlineData: ByteArray) {
|
||||||
storage[pathConverter.toPath(sourceFile)] =
|
this[sourceFile] =
|
||||||
TranslationResultValue(metadata = newMetadata, binaryAst = newBinaryAst, inlineData = newInlineData)
|
TranslationResultValue(metadata = newMetadata, binaryAst = newBinaryAst, inlineData = newInlineData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
operator fun get(sourceFile: File): TranslationResultValue? =
|
|
||||||
storage[pathConverter.toPath(sourceFile)]
|
|
||||||
|
|
||||||
fun keys(): Collection<File> =
|
|
||||||
storage.keys.map { pathConverter.toFile(it) }
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun remove(sourceFile: File, changesCollector: ChangesCollector) {
|
fun remove(sourceFile: File, changesCollector: ChangesCollector) {
|
||||||
val path = pathConverter.toPath(sourceFile)
|
val protoBytes = this[sourceFile]!!.metadata
|
||||||
val protoBytes = storage[path]!!.metadata
|
|
||||||
val protoMap = protoData(sourceFile, protoBytes)
|
val protoMap = protoData(sourceFile, protoBytes)
|
||||||
|
|
||||||
for ((_, protoData) in protoMap) {
|
for ((_, protoData) in protoMap) {
|
||||||
changesCollector.collectProtoChanges(oldData = protoData, newData = null)
|
changesCollector.collectProtoChanges(oldData = protoData, newData = null)
|
||||||
}
|
}
|
||||||
storage.remove(path)
|
remove(sourceFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,8 +312,14 @@ private object IrTranslationResultValueExternalizer : DataExternalizer<IrTransla
|
|||||||
private class IrTranslationResultMap(
|
private class IrTranslationResultMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) :
|
) : AbstractBasicMap<File, IrTranslationResultValue>(
|
||||||
BasicStringMap<IrTranslationResultValue>(storageFile, IrTranslationResultValueExternalizer, icContext) {
|
storageFile,
|
||||||
|
icContext.fileDescriptorForSourceFiles,
|
||||||
|
IrTranslationResultValueExternalizer,
|
||||||
|
icContext
|
||||||
|
) {
|
||||||
|
|
||||||
|
@TestOnly
|
||||||
override fun dumpValue(value: IrTranslationResultValue): String =
|
override fun dumpValue(value: IrTranslationResultValue): String =
|
||||||
"Filedata: ${value.fileData.md5()}, " +
|
"Filedata: ${value.fileData.md5()}, " +
|
||||||
"Types: ${value.types.md5()}, " +
|
"Types: ${value.types.md5()}, " +
|
||||||
@@ -323,6 +328,7 @@ private class IrTranslationResultMap(
|
|||||||
"Declarations: ${value.declarations.md5()}, " +
|
"Declarations: ${value.declarations.md5()}, " +
|
||||||
"Bodies: ${value.bodies.md5()}"
|
"Bodies: ${value.bodies.md5()}"
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
fun put(
|
fun put(
|
||||||
sourceFile: File,
|
sourceFile: File,
|
||||||
newFiledata: ByteArray,
|
newFiledata: ByteArray,
|
||||||
@@ -335,20 +341,9 @@ private class IrTranslationResultMap(
|
|||||||
newFileMetadata: ByteArray,
|
newFileMetadata: ByteArray,
|
||||||
debugInfos: ByteArray?,
|
debugInfos: ByteArray?,
|
||||||
) {
|
) {
|
||||||
storage[pathConverter.toPath(sourceFile)] =
|
this[sourceFile] =
|
||||||
IrTranslationResultValue(newFiledata, newTypes, newSignatures, newStrings, newDeclarations, newBodies, fqn, newFileMetadata, debugInfos)
|
IrTranslationResultValue(newFiledata, newTypes, newSignatures, newStrings, newDeclarations, newBodies, fqn, newFileMetadata, debugInfos)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(sourceFile: File): IrTranslationResultValue? =
|
|
||||||
storage[pathConverter.toPath(sourceFile)]
|
|
||||||
|
|
||||||
fun keys(): Collection<File> =
|
|
||||||
storage.keys.map { pathConverter.toFile(it) }
|
|
||||||
|
|
||||||
fun remove(sourceFile: File) {
|
|
||||||
val path = pathConverter.toPath(sourceFile)
|
|
||||||
storage.remove(path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProtoDataProvider(private val serializerProtocol: SerializerExtensionProtocol) {
|
private class ProtoDataProvider(private val serializerProtocol: SerializerExtensionProtocol) {
|
||||||
@@ -396,16 +391,21 @@ fun getProtoData(sourceFile: File, metadata: ByteArray): Map<ClassId, ProtoData>
|
|||||||
private class InlineFunctionsMap(
|
private class InlineFunctionsMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer, icContext) {
|
) : AbstractBasicMap<File, Map<String, Long>>(
|
||||||
|
storageFile,
|
||||||
|
icContext.fileDescriptorForSourceFiles,
|
||||||
|
StringToLongMapExternalizer,
|
||||||
|
icContext
|
||||||
|
) {
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun process(srcFile: File, newMap: Map<String, Long>, changesCollector: ChangesCollector) {
|
fun process(srcFile: File, newMap: Map<String, Long>, changesCollector: ChangesCollector) {
|
||||||
val key = pathConverter.toPath(srcFile)
|
val oldMap = this[srcFile] ?: emptyMap()
|
||||||
val oldMap = storage[key] ?: emptyMap()
|
|
||||||
|
|
||||||
if (newMap.isNotEmpty()) {
|
if (newMap.isNotEmpty()) {
|
||||||
storage[key] = newMap
|
this[srcFile] = newMap
|
||||||
} else {
|
} else {
|
||||||
storage.remove(key)
|
remove(srcFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (fn in oldMap.keys + newMap.keys) {
|
for (fn in oldMap.keys + newMap.keys) {
|
||||||
@@ -415,11 +415,7 @@ private class InlineFunctionsMap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@TestOnly
|
||||||
fun remove(sourceFile: File) {
|
|
||||||
storage.remove(pathConverter.toPath(sourceFile))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dumpValue(value: Map<String, Long>): String =
|
override fun dumpValue(value: Map<String, Long>): String =
|
||||||
value.dumpMap { java.lang.Long.toHexString(it) }
|
value.dumpMap { java.lang.Long.toHexString(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.incremental
|
package org.jetbrains.kotlin.incremental
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil.toSystemIndependentName
|
import com.intellij.openapi.util.io.FileUtil.toSystemIndependentName
|
||||||
import com.intellij.util.containers.CollectionFactory
|
|
||||||
import com.intellij.util.io.BooleanDataDescriptor
|
import com.intellij.util.io.BooleanDataDescriptor
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
|
||||||
import gnu.trove.THashSet
|
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
||||||
import org.jetbrains.kotlin.incremental.storage.*
|
import org.jetbrains.kotlin.incremental.storage.*
|
||||||
@@ -88,13 +85,10 @@ open class IncrementalJvmCache(
|
|||||||
// used in gradle
|
// used in gradle
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun classesBySources(sources: Iterable<File>): Iterable<JvmClassName> =
|
fun classesBySources(sources: Iterable<File>): Iterable<JvmClassName> =
|
||||||
sources.flatMap { sourceToClassesMap[it] }
|
sources.flatMap { sourceToClassesMap[it].orEmpty() }
|
||||||
|
|
||||||
fun sourceInCache(file: File): Boolean =
|
|
||||||
sourceToClassesMap.contains(file)
|
|
||||||
|
|
||||||
fun sourcesByInternalName(internalName: String): Collection<File> =
|
fun sourcesByInternalName(internalName: String): Collection<File> =
|
||||||
internalNameToSource.getFiles(internalName)
|
internalNameToSource[internalName].orEmpty()
|
||||||
|
|
||||||
fun getAllPartsOfMultifileFacade(facade: JvmClassName): Collection<String>? {
|
fun getAllPartsOfMultifileFacade(facade: JvmClassName): Collection<String>? {
|
||||||
return multifileFacadeToParts[facade]
|
return multifileFacadeToParts[facade]
|
||||||
@@ -111,7 +105,7 @@ open class IncrementalJvmCache(
|
|||||||
val jvmClassName = JvmClassName.byInternalName(MODULE_MAPPING_FILE_NAME)
|
val jvmClassName = JvmClassName.byInternalName(MODULE_MAPPING_FILE_NAME)
|
||||||
protoMap.storeModuleMapping(jvmClassName, file.readBytes())
|
protoMap.storeModuleMapping(jvmClassName, file.readBytes())
|
||||||
dirtyOutputClassesMap.notDirty(jvmClassName)
|
dirtyOutputClassesMap.notDirty(jvmClassName)
|
||||||
sourceFiles.forEach { sourceToClassesMap.add(it, jvmClassName) }
|
sourceFiles.forEach { sourceToClassesMap.append(it, jvmClassName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun saveFileToCache(generatedClass: GeneratedJvmClass, changesCollector: ChangesCollector) {
|
open fun saveFileToCache(generatedClass: GeneratedJvmClass, changesCollector: ChangesCollector) {
|
||||||
@@ -133,7 +127,7 @@ open class IncrementalJvmCache(
|
|||||||
|
|
||||||
if (sourceFiles != null) {
|
if (sourceFiles != null) {
|
||||||
sourceFiles.forEach {
|
sourceFiles.forEach {
|
||||||
sourceToClassesMap.add(it, className)
|
sourceToClassesMap.append(it, className)
|
||||||
}
|
}
|
||||||
internalNameToSource[className.internalName] = sourceFiles
|
internalNameToSource[className.internalName] = sourceFiles
|
||||||
}
|
}
|
||||||
@@ -176,7 +170,7 @@ open class IncrementalJvmCache(
|
|||||||
assert(sourceFiles.size == 1) { "Multifile class part from several source files: $sourceFiles" }
|
assert(sourceFiles.size == 1) { "Multifile class part from several source files: $sourceFiles" }
|
||||||
}
|
}
|
||||||
packagePartMap.addPackagePart(className)
|
packagePartMap.addPackagePart(className)
|
||||||
partToMultifileFacade.set(className.internalName, kotlinClassInfo.multifileClassName!!)
|
partToMultifileFacade[className] = kotlinClassInfo.multifileClassName!!
|
||||||
|
|
||||||
protoMap.process(kotlinClassInfo, changesCollector)
|
protoMap.process(kotlinClassInfo, changesCollector)
|
||||||
constantsMap.process(kotlinClassInfo, changesCollector)
|
constantsMap.process(kotlinClassInfo, changesCollector)
|
||||||
@@ -235,7 +229,7 @@ open class IncrementalJvmCache(
|
|||||||
fun saveJavaClassProto(source: File?, serializedJavaClass: SerializedJavaClass, collector: ChangesCollector) {
|
fun saveJavaClassProto(source: File?, serializedJavaClass: SerializedJavaClass, collector: ChangesCollector) {
|
||||||
val jvmClassName = JvmClassName.byClassId(serializedJavaClass.classId)
|
val jvmClassName = JvmClassName.byClassId(serializedJavaClass.classId)
|
||||||
javaSourcesProtoMap.process(jvmClassName, serializedJavaClass, collector)
|
javaSourcesProtoMap.process(jvmClassName, serializedJavaClass, collector)
|
||||||
source?.let { sourceToClassesMap.add(source, jvmClassName) }
|
source?.let { sourceToClassesMap.append(source, jvmClassName) }
|
||||||
addToClassStorage(serializedJavaClass.toProtoData(), source)
|
addToClassStorage(serializedJavaClass.toProtoData(), source)
|
||||||
// collector.addJavaProto(ClassProtoData(proto, nameResolver))
|
// collector.addJavaProto(ClassProtoData(proto, nameResolver))
|
||||||
dirtyOutputClassesMap.notDirty(jvmClassName)
|
dirtyOutputClassesMap.notDirty(jvmClassName)
|
||||||
@@ -263,7 +257,7 @@ open class IncrementalJvmCache(
|
|||||||
|
|
||||||
val facadesWithRemovedParts = hashMapOf<JvmClassName, MutableSet<String>>()
|
val facadesWithRemovedParts = hashMapOf<JvmClassName, MutableSet<String>>()
|
||||||
for (dirtyClass in dirtyClasses) {
|
for (dirtyClass in dirtyClasses) {
|
||||||
val facade = partToMultifileFacade.get(dirtyClass) ?: continue
|
val facade = partToMultifileFacade[dirtyClass] ?: continue
|
||||||
val facadeClassName = JvmClassName.byInternalName(facade)
|
val facadeClassName = JvmClassName.byInternalName(facade)
|
||||||
val removedParts = facadesWithRemovedParts.getOrPut(facadeClassName) { hashSetOf() }
|
val removedParts = facadesWithRemovedParts.getOrPut(facadeClassName) { hashSetOf() }
|
||||||
removedParts.add(dirtyClass.internalName)
|
removedParts.add(dirtyClass.internalName)
|
||||||
@@ -311,7 +305,7 @@ open class IncrementalJvmCache(
|
|||||||
override fun getObsoleteMultifileClasses(): Collection<String> {
|
override fun getObsoleteMultifileClasses(): Collection<String> {
|
||||||
val obsoleteMultifileClasses = linkedSetOf<String>()
|
val obsoleteMultifileClasses = linkedSetOf<String>()
|
||||||
for (dirtyClass in dirtyOutputClassesMap.getDirtyOutputClasses()) {
|
for (dirtyClass in dirtyOutputClassesMap.getDirtyOutputClasses()) {
|
||||||
val dirtyFacade = partToMultifileFacade.get(dirtyClass) ?: continue
|
val dirtyFacade = partToMultifileFacade[dirtyClass] ?: continue
|
||||||
obsoleteMultifileClasses.add(dirtyFacade)
|
obsoleteMultifileClasses.add(dirtyFacade)
|
||||||
}
|
}
|
||||||
debugLog("Obsolete multifile class facades: $obsoleteMultifileClasses")
|
debugLog("Obsolete multifile class facades: $obsoleteMultifileClasses")
|
||||||
@@ -514,59 +508,32 @@ open class IncrementalJvmCache(
|
|||||||
private inner class MultifileClassFacadeMap(
|
private inner class MultifileClassFacadeMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) :
|
) : AppendableBasicMap<JvmClassName, String>(
|
||||||
BasicStringMap<Collection<String>>(storageFile, StringCollectionExternalizer, icContext) {
|
storageFile,
|
||||||
|
JvmClassNameExternalizer.toDescriptor(),
|
||||||
@Synchronized
|
StringExternalizer,
|
||||||
operator fun set(className: JvmClassName, partNames: Collection<String>) {
|
icContext
|
||||||
storage[className.internalName] = partNames
|
)
|
||||||
}
|
|
||||||
|
|
||||||
operator fun get(className: JvmClassName): Collection<String>? =
|
|
||||||
storage[className.internalName]
|
|
||||||
|
|
||||||
operator fun contains(className: JvmClassName): Boolean =
|
|
||||||
className.internalName in storage
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun remove(className: JvmClassName) {
|
|
||||||
storage.remove(className.internalName)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dumpValue(value: Collection<String>): String = value.dumpCollection()
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class MultifileClassPartMap(
|
private inner class MultifileClassPartMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) :
|
) : AbstractBasicMap<JvmClassName, String>(
|
||||||
BasicStringMap<String>(storageFile, EnumeratorStringDescriptor.INSTANCE, icContext) {
|
storageFile,
|
||||||
|
JvmClassNameExternalizer.toDescriptor(),
|
||||||
fun get(partName: JvmClassName): String? =
|
StringExternalizer,
|
||||||
storage[partName.internalName]
|
icContext
|
||||||
|
)
|
||||||
@Synchronized
|
|
||||||
fun remove(className: JvmClassName) {
|
|
||||||
storage.remove(className.internalName)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dumpValue(value: String): String = value
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class InternalNameToSourcesMap(
|
inner class InternalNameToSourcesMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : BasicStringMap<Collection<String>>(storageFile, EnumeratorStringDescriptor(), PathCollectionExternalizer, icContext) {
|
) : AppendableBasicMap<String, File>(
|
||||||
operator fun set(internalName: String, sourceFiles: Collection<File>) {
|
storageFile,
|
||||||
storage[internalName] = pathConverter.toPaths(sourceFiles)
|
StringExternalizer.toDescriptor(),
|
||||||
}
|
icContext.fileDescriptorForSourceFiles,
|
||||||
|
icContext
|
||||||
fun getFiles(internalName: String): Collection<File> =
|
)
|
||||||
pathConverter.toFiles(storage[internalName] ?: emptyList())
|
|
||||||
|
|
||||||
override fun dumpValue(value: Collection<String>): String =
|
|
||||||
value.dumpCollection()
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class InlineFunctionsMap(
|
private inner class InlineFunctionsMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
@@ -628,9 +595,6 @@ open class IncrementalJvmCache(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object PathCollectionExternalizer :
|
|
||||||
CollectionExternalizerV2<String, Collection<String>>(PathStringDescriptor, { THashSet(CollectionFactory.createFilePathSet()) })
|
|
||||||
|
|
||||||
sealed class ChangeInfo(val fqName: FqName) {
|
sealed class ChangeInfo(val fqName: FqName) {
|
||||||
open class MembersChanged(fqName: FqName, val names: Collection<String>) : ChangeInfo(fqName) {
|
open class MembersChanged(fqName: FqName, val names: Collection<String>) : ChangeInfo(fqName) {
|
||||||
override fun toStringProperties(): String = super.toStringProperties() + ", names = $names"
|
override fun toStringProperties(): String = super.toStringProperties() + ", names = $names"
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ open class LookupStorage(
|
|||||||
val filtered = mutableSetOf<Int>()
|
val filtered = mutableSetOf<Int>()
|
||||||
|
|
||||||
for (fileId in fileIds) {
|
for (fileId in fileIds) {
|
||||||
val path = idToFile.getFile(fileId)?.path
|
val path = idToFile[fileId]?.path
|
||||||
|
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
paths.add(path)
|
paths.add(path)
|
||||||
@@ -171,7 +171,7 @@ open class LookupStorage(
|
|||||||
lookupMap[hash] = lookupMap[hash]!!.filter { it in idToFile }.toSet()
|
lookupMap[hash] = lookupMap[hash]!!.filter { it in idToFile }.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
val oldFileToId = fileToId.toMap()
|
val oldFileToId = fileToId.keys.associateWith { fileToId[it]!! }
|
||||||
val oldIdToNewId = HashMap<Int, Int>(oldFileToId.size)
|
val oldIdToNewId = HashMap<Int, Int>(oldFileToId.size)
|
||||||
idToFile.clear()
|
idToFile.clear()
|
||||||
fileToId.clear()
|
fileToId.clear()
|
||||||
@@ -302,17 +302,17 @@ private class TrackedLookupMap(private val lookupMap: LookupMap, private val tra
|
|||||||
val addedKeys = if (trackChanges) mutableSetOf<LookupSymbolKey>() else null
|
val addedKeys = if (trackChanges) mutableSetOf<LookupSymbolKey>() else null
|
||||||
val removedKeys = if (trackChanges) mutableSetOf<LookupSymbolKey>() else null
|
val removedKeys = if (trackChanges) mutableSetOf<LookupSymbolKey>() else null
|
||||||
|
|
||||||
val keys: Collection<LookupSymbolKey>
|
val keys: Set<LookupSymbolKey>
|
||||||
get() = lookupMap.keys
|
get() = lookupMap.keys
|
||||||
|
|
||||||
operator fun get(key: LookupSymbolKey): Collection<Int>? = lookupMap[key]
|
operator fun get(key: LookupSymbolKey): Set<Int>? = lookupMap[key]
|
||||||
|
|
||||||
operator fun set(key: LookupSymbolKey, fileIds: Set<Int>) {
|
operator fun set(key: LookupSymbolKey, fileIds: Set<Int>) {
|
||||||
recordSet(key)
|
recordSet(key)
|
||||||
lookupMap[key] = fileIds
|
lookupMap[key] = fileIds
|
||||||
}
|
}
|
||||||
|
|
||||||
fun append(key: LookupSymbolKey, fileIds: Collection<Int>) {
|
fun append(key: LookupSymbolKey, fileIds: Set<Int>) {
|
||||||
recordSet(key)
|
recordSet(key)
|
||||||
lookupMap.append(key, fileIds)
|
lookupMap.append(key, fileIds)
|
||||||
}
|
}
|
||||||
@@ -324,23 +324,19 @@ private class TrackedLookupMap(private val lookupMap: LookupMap, private val tra
|
|||||||
|
|
||||||
private fun recordSet(key: LookupSymbolKey) {
|
private fun recordSet(key: LookupSymbolKey) {
|
||||||
if (!trackChanges) return
|
if (!trackChanges) return
|
||||||
if (lookupMap[key] == null) {
|
when (key) {
|
||||||
if (key in removedKeys!!) {
|
in lookupMap -> Unit
|
||||||
removedKeys.remove(key)
|
in removedKeys!! -> removedKeys.remove(key)
|
||||||
} else {
|
else -> addedKeys!!.add(key)
|
||||||
addedKeys!!.add(key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun recordRemove(key: LookupSymbolKey) {
|
private fun recordRemove(key: LookupSymbolKey) {
|
||||||
if (!trackChanges) return
|
if (!trackChanges) return
|
||||||
if (lookupMap[key] != null) {
|
when (key) {
|
||||||
if (key in addedKeys!!) {
|
!in lookupMap -> Unit
|
||||||
addedKeys.remove(key)
|
in addedKeys!! -> addedKeys.remove(key)
|
||||||
} else {
|
else -> removedKeys!!.add(key)
|
||||||
removedKeys!!.add(key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
import com.intellij.util.io.DataExternalizer
|
import com.intellij.util.io.DataExternalizer
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
|
||||||
import com.intellij.util.io.IOUtil
|
import com.intellij.util.io.IOUtil
|
||||||
import com.intellij.util.io.KeyDescriptor
|
import com.intellij.util.io.KeyDescriptor
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
@@ -30,7 +29,9 @@ interface BasicMap<KEY, VALUE> : PersistentStorage<KEY, VALUE> {
|
|||||||
|
|
||||||
/** Removes all entries. */
|
/** Removes all entries. */
|
||||||
fun clear() {
|
fun clear() {
|
||||||
keys.forEach { remove(it) }
|
synchronized(this) {
|
||||||
|
keys.forEach { remove(it) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,22 +41,29 @@ interface BasicMap<KEY, VALUE> : PersistentStorage<KEY, VALUE> {
|
|||||||
* Make sure the storage has been closed first before calling this method.
|
* Make sure the storage has been closed first before calling this method.
|
||||||
*/
|
*/
|
||||||
fun deleteStorageFiles() {
|
fun deleteStorageFiles() {
|
||||||
check(IOUtil.deleteAllFilesStartingWith(storageFile)) {
|
synchronized(this) {
|
||||||
"Unable to delete storage file(s) with name prefix: ${storageFile.path}"
|
check(IOUtil.deleteAllFilesStartingWith(storageFile)) {
|
||||||
|
"Unable to delete storage file(s) with name prefix: ${storageFile.path}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
fun dump(): String {
|
fun dump(): String {
|
||||||
|
val map: Map<KEY, VALUE> = synchronized(this) {
|
||||||
|
keys.associateWith { this[it]!! }
|
||||||
|
}
|
||||||
|
val printableMap: Map<String, String> = map.map {
|
||||||
|
dumpKey(it.key) to dumpValue(it.value)
|
||||||
|
}.sortedBy { it.first }.toMap()
|
||||||
|
|
||||||
return StringBuilder().apply {
|
return StringBuilder().apply {
|
||||||
Printer(this).apply {
|
Printer(this).apply {
|
||||||
println("${storageFile.name.substringBefore(".tab")} (${this@BasicMap::class.java.simpleName})")
|
println("${storageFile.name.substringBefore(".tab")} (${this@BasicMap::class.java.simpleName})")
|
||||||
pushIndent()
|
pushIndent()
|
||||||
|
printableMap.forEach {
|
||||||
for (key in keys.sortedBy { dumpKey(it) }) {
|
println("${it.key} -> ${it.value}")
|
||||||
println("${dumpKey(key)} -> ${dumpValue(this@BasicMap[key]!!)}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
popIndent()
|
popIndent()
|
||||||
}
|
}
|
||||||
}.toString()
|
}.toString()
|
||||||
@@ -65,59 +73,113 @@ interface BasicMap<KEY, VALUE> : PersistentStorage<KEY, VALUE> {
|
|||||||
fun dumpKey(key: KEY): String = key.toString()
|
fun dumpKey(key: KEY): String = key.toString()
|
||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
fun dumpValue(value: VALUE): String = value.toString()
|
fun dumpValue(value: VALUE): String {
|
||||||
|
return if (value is Collection<*>) {
|
||||||
|
// Sort the elements so that we can reliably compare `Collection`s in tests (in case the order of the elements is not stable).
|
||||||
|
value.sortedBy { it.toString() }.toString()
|
||||||
|
} else {
|
||||||
|
value.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BasicMapBase<KEY, VALUE>(
|
abstract class BasicMapBase<KEY, VALUE>(
|
||||||
protected val storage: PersistentStorage<KEY, VALUE>,
|
// TODO(KT-63456): Remove `protected val` (currently this property is still used by BasicStringMap)
|
||||||
) : PersistentStorageWrapper<KEY, VALUE>(storage), BasicMap<KEY, VALUE>
|
protected val persistentStorage: PersistentStorage<KEY, VALUE>,
|
||||||
|
) : PersistentStorageWrapper<KEY, VALUE>(persistentStorage), BasicMap<KEY, VALUE>
|
||||||
|
|
||||||
abstract class AppendableBasicMapBase<KEY, E, VALUE : Collection<E>>(
|
abstract class AppendableBasicMapBase<KEY, E>(
|
||||||
protected val storage: AppendablePersistentStorage<KEY, E, VALUE>,
|
storage: AppendablePersistentStorage<KEY, E>,
|
||||||
) : AppendablePersistentStorageWrapper<KEY, E, VALUE>(storage), BasicMap<KEY, VALUE>
|
) : AppendablePersistentStorageWrapper<KEY, E>(storage), BasicMap<KEY, Collection<E>>
|
||||||
|
|
||||||
abstract class AbstractBasicMap<KEY, VALUE>(
|
abstract class AbstractBasicMap<KEY, VALUE>(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
keyDescriptor: KeyDescriptor<KEY>,
|
keyDescriptor: KeyDescriptor<KEY>,
|
||||||
valueExternalizer: DataExternalizer<VALUE>,
|
valueExternalizer: DataExternalizer<VALUE>,
|
||||||
protected val icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : BasicMapBase<KEY, VALUE>(
|
) : BasicMapBase<KEY, VALUE>(
|
||||||
createPersistentStorage(storageFile, keyDescriptor, valueExternalizer, icContext)
|
createPersistentStorage(storageFile, keyDescriptor, valueExternalizer, icContext)
|
||||||
) {
|
)
|
||||||
protected val pathConverter
|
|
||||||
get() = icContext.pathConverter
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AppendableAbstractBasicMap<KEY, E, VALUE : Collection<E>>(
|
abstract class AppendableBasicMap<KEY, E>(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
keyDescriptor: KeyDescriptor<KEY>,
|
keyDescriptor: KeyDescriptor<KEY>,
|
||||||
elementExternalizer: DataExternalizer<E>,
|
elementExternalizer: DataExternalizer<E>,
|
||||||
protected val icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : AppendableBasicMapBase<KEY, E, VALUE>(
|
) : AppendableBasicMapBase<KEY, E>(
|
||||||
createAppendablePersistentStorage(storageFile, keyDescriptor, elementExternalizer, icContext)
|
createAppendablePersistentStorage(storageFile, keyDescriptor, elementExternalizer, icContext)
|
||||||
) {
|
)
|
||||||
protected val pathConverter
|
|
||||||
get() = icContext.pathConverter
|
abstract class AppendableSetBasicMap<KEY, E>(
|
||||||
|
storageFile: File,
|
||||||
|
keyDescriptor: KeyDescriptor<KEY>,
|
||||||
|
elementExternalizer: DataExternalizer<E>,
|
||||||
|
icContext: IncrementalCompilationContext,
|
||||||
|
) : PersistentStorage<KEY, Set<E>>, BasicMap<KEY, Set<E>> {
|
||||||
|
|
||||||
|
private val storage = createAppendablePersistentStorage(storageFile, keyDescriptor, elementExternalizer, icContext)
|
||||||
|
|
||||||
|
override val storageFile: File = storage.storageFile
|
||||||
|
|
||||||
|
@get:Synchronized
|
||||||
|
override val keys: Set<KEY>
|
||||||
|
get() = storage.keys
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun contains(key: KEY): Boolean =
|
||||||
|
storage.contains(key)
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun get(key: KEY): Set<E>? {
|
||||||
|
// Note: To optimize this getter, consider changing the type of `storage` from PersistentStorage<KEY, Collection<E>> to
|
||||||
|
// PersistentStorage<KEY, Set<E>> so that we don't have to call `toSet()`. The downside is that it will make the code more complex,
|
||||||
|
// so we'll do it only if it's necessary.
|
||||||
|
return storage[key]?.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun set(key: KEY, value: Set<E>) {
|
||||||
|
storage[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun remove(key: KEY) {
|
||||||
|
storage.remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun flush() {
|
||||||
|
storage.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun close() {
|
||||||
|
storage.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun append(key: KEY, element: E) {
|
||||||
|
storage.append(key, setOf(element))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun append(key: KEY, elements: Set<E>) {
|
||||||
|
storage.append(key, elements)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BasicStringMap<VALUE>(
|
abstract class BasicStringMap<VALUE>(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
keyDescriptor: KeyDescriptor<String>,
|
|
||||||
valueExternalizer: DataExternalizer<VALUE>,
|
valueExternalizer: DataExternalizer<VALUE>,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : AbstractBasicMap<String, VALUE>(storageFile, keyDescriptor, valueExternalizer, icContext) {
|
) : AbstractBasicMap<String, VALUE>(
|
||||||
|
storageFile,
|
||||||
constructor(storageFile: File, valueExternalizer: DataExternalizer<VALUE>, icContext: IncrementalCompilationContext) :
|
StringExternalizer.toDescriptor(),
|
||||||
this(storageFile, EnumeratorStringDescriptor.INSTANCE, valueExternalizer, icContext)
|
valueExternalizer,
|
||||||
}
|
icContext
|
||||||
|
) {
|
||||||
abstract class AppendableBasicStringMap<E, VALUE : Collection<E>>(
|
// TODO(KT-63456): Remove this property
|
||||||
storageFile: File,
|
// (To do this, we need to refactor all subclasses of BasicStringMap such that they don't use this property. For examples of what the
|
||||||
keyDescriptor: KeyDescriptor<String>,
|
// outcome of the refactoring should look like, see other subclasses of AbstractBasicMap.)
|
||||||
elementExternalizer: DataExternalizer<E>,
|
protected val storage: PersistentStorage<String, VALUE> = persistentStorage
|
||||||
icContext: IncrementalCompilationContext,
|
|
||||||
) : AppendableAbstractBasicMap<String, E, VALUE>(storageFile, keyDescriptor, elementExternalizer, icContext) {
|
|
||||||
|
|
||||||
constructor(storageFile: File, elementExternalizer: DataExternalizer<E>, icContext: IncrementalCompilationContext) :
|
|
||||||
this(storageFile, EnumeratorStringDescriptor.INSTANCE, elementExternalizer, icContext)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,49 +16,38 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
|
import com.intellij.util.io.DataExternalizer
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
||||||
import org.jetbrains.kotlin.incremental.dumpCollection
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import java.io.DataInput
|
||||||
|
import java.io.DataOutput
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal open class ClassOneToManyMap(
|
internal open class ClassOneToManyMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : AppendableBasicStringMap<String, Collection<String>>(storageFile, EnumeratorStringDescriptor.INSTANCE, icContext) {
|
) : AppendableSetBasicMap<FqName, FqName>(
|
||||||
override fun dumpValue(value: Collection<String>): String = value.toSet().dumpCollection()
|
storageFile,
|
||||||
|
LegacyFqNameExternalizer.toDescriptor(),
|
||||||
|
LegacyFqNameExternalizer,
|
||||||
|
icContext
|
||||||
|
) {
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun add(key: FqName, value: FqName) {
|
override operator fun set(key: FqName, value: Set<FqName>) {
|
||||||
storage.append(key.asString(), value.asString())
|
if (value.isNotEmpty()) {
|
||||||
}
|
super.set(key, value)
|
||||||
|
} else {
|
||||||
@Synchronized
|
|
||||||
operator fun get(key: FqName): Collection<FqName> =
|
|
||||||
storage[key.asString()]?.mapTo(mutableSetOf(), ::FqName) ?: setOf()
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
operator fun set(key: FqName, values: Collection<FqName>) {
|
|
||||||
if (values.isEmpty()) {
|
|
||||||
remove(key)
|
remove(key)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
storage[key.asString()] = values.map(FqName::asString)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun remove(key: FqName) {
|
|
||||||
storage.remove(key.asString())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Access to caches could be done from multiple threads (e.g. JPS worker and RMI). The underlying collection is already synchronized,
|
|
||||||
// thus we need synchronization of this method and all modification methods.
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun removeValues(key: FqName, removed: Set<FqName>) {
|
fun removeValues(key: FqName, removed: Set<FqName>) {
|
||||||
val notRemoved = this[key].filter { it !in removed }
|
this[key] = this[key].orEmpty() - removed
|
||||||
this[key] = notRemoved
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SubtypesMap(
|
internal class SubtypesMap(
|
||||||
@@ -70,3 +59,22 @@ internal class SupertypesMap(
|
|||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : ClassOneToManyMap(storageFile, icContext)
|
) : ClassOneToManyMap(storageFile, icContext)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use [LegacyFqNameExternalizer] instead of [FqNameExternalizer] for [SubtypesMap] for now because they internally use different types of
|
||||||
|
* `DataExternalizer<String>`, and the `compiler-reference-index` module in the Kotlin IDEA plugin currently can only read the old data
|
||||||
|
* format (see KTIJ-27258).
|
||||||
|
*
|
||||||
|
* Once we fix that bug, we can remove this class and use [FqNameExternalizer].
|
||||||
|
*/
|
||||||
|
private object LegacyFqNameExternalizer : DataExternalizer<FqName> {
|
||||||
|
|
||||||
|
override fun save(output: DataOutput, fqName: FqName) {
|
||||||
|
EnumeratorStringDescriptor.INSTANCE.save(output, fqName.asString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(input: DataInput): FqName {
|
||||||
|
return FqName(EnumeratorStringDescriptor.INSTANCE.read(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
+4
-22
@@ -5,33 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
||||||
import org.jetbrains.kotlin.incremental.dumpCollection
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ComplementarySourceFilesMap(
|
class ComplementarySourceFilesMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : AppendableBasicStringMap<String, Collection<String>>(
|
) : AppendableSetBasicMap<File, File>(
|
||||||
storageFile,
|
storageFile,
|
||||||
PathStringDescriptor,
|
icContext.fileDescriptorForSourceFiles,
|
||||||
EnumeratorStringDescriptor.INSTANCE,
|
icContext.fileDescriptorForSourceFiles,
|
||||||
icContext
|
icContext
|
||||||
) {
|
)
|
||||||
|
|
||||||
operator fun set(sourceFile: File, complementaryFiles: Collection<File>) {
|
|
||||||
storage[pathConverter.toPath(sourceFile)] = pathConverter.toPaths(complementaryFiles)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun get(sourceFile: File): Collection<File> {
|
|
||||||
val paths = storage[pathConverter.toPath(sourceFile)].orEmpty()
|
|
||||||
return pathConverter.toFiles(paths).toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dumpValue(value: Collection<String>) =
|
|
||||||
value.dumpCollection()
|
|
||||||
|
|
||||||
fun remove(file: File): Collection<File> =
|
|
||||||
get(file).also { storage.remove(pathConverter.toPath(file)) }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -20,27 +20,11 @@ import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal class FileToIdMap(
|
internal class FileToIdMap(
|
||||||
file: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : BasicStringMap<Int>(file, IntExternalizer, icContext) {
|
) : AbstractBasicMap<File, Int>(
|
||||||
override fun dumpValue(value: Int): String = value.toString()
|
storageFile,
|
||||||
|
icContext.fileDescriptorForSourceFiles,
|
||||||
operator fun get(file: File): Int? = storage[pathConverter.toPath(file)]
|
IntExternalizer,
|
||||||
|
icContext
|
||||||
operator fun set(file: File, id: Int) {
|
)
|
||||||
storage[pathConverter.toPath(file)] = id
|
|
||||||
}
|
|
||||||
|
|
||||||
fun remove(file: File) {
|
|
||||||
storage.remove(pathConverter.toPath(file))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toMap(): Map<File, Int> {
|
|
||||||
val result = HashMap<File, Int>()
|
|
||||||
for (key in storage.keys) {
|
|
||||||
val value = storage[key] ?: continue
|
|
||||||
result[pathConverter.toFile(key)] = value
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,22 +5,54 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
|
import com.intellij.util.io.KeyDescriptor
|
||||||
|
import java.io.DataInput
|
||||||
|
import java.io.DataOutput
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/** Converts a [File] to a path of type [String] to store in IC caches, and vice versa. */
|
/** Converts a [File] to a path of type [String] (and vice versa) for serialization of file paths in IC caches. */
|
||||||
interface FileToPathConverter {
|
interface FileToPathConverter {
|
||||||
fun toPath(file: File): String
|
fun toPath(file: File): String
|
||||||
fun toFile(path: String): File
|
fun toFile(path: String): File
|
||||||
|
fun getFileDescriptor(): KeyDescriptor<File> = FileDescriptor(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FileToPathConverter.toPaths(files: Collection<File>): List<String> =
|
object BasicFileToPathConverter : FileToPathConverter {
|
||||||
files.map { toPath(it) }
|
override fun toPath(file: File): String = file.path
|
||||||
|
|
||||||
fun FileToPathConverter.toFiles(paths: Collection<String>): List<File> =
|
|
||||||
paths.map { toFile(it) }
|
|
||||||
|
|
||||||
object FileToAbsolutePathConverter : FileToPathConverter {
|
|
||||||
override fun toPath(file: File): String = file.normalize().absolutePath
|
|
||||||
|
|
||||||
override fun toFile(path: String): File = File(path)
|
override fun toFile(path: String): File = File(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [KeyDescriptor] for a [File] which uses the given [pathConverter] for serialization of file paths.
|
||||||
|
*
|
||||||
|
* To support build cache relocatability, the user of this class can provide a [RelocatableFileToPathConverter] as the [pathConverter].
|
||||||
|
*/
|
||||||
|
private class FileDescriptor(private val pathConverter: FileToPathConverter) : KeyDescriptor<File> {
|
||||||
|
|
||||||
|
override fun save(output: DataOutput, file: File) {
|
||||||
|
StringExternalizer.save(output, pathConverter.toPath(file))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(input: DataInput): File {
|
||||||
|
return pathConverter.toFile(StringExternalizer.read(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getHashCode(file: File): Int {
|
||||||
|
// It's important to use the pathConverter to get a possibly relocatable path first before computing the hash code because the
|
||||||
|
// returned hash code affects the contents of IC caches.
|
||||||
|
// For example, if we get the hash code directly without using pathConverter, the hash codes of the following files will be
|
||||||
|
// different and therefore the contents of the IC caches will also be different (i.e., the IC caches will not be relocatable):
|
||||||
|
// File("/path/to/project1/src/foo.kt").hashCode() = 123
|
||||||
|
// File("/path/to/project2/src/foo.kt").hashCode() = 456
|
||||||
|
// If we use a RelocatableFileToPathConverter instead, the file paths will be normalized first, so we'll get the same hash codes:
|
||||||
|
// [In "/path/to/project1"] File("src/foo.kt").hashCode() = 789
|
||||||
|
// [In "/path/to/project2"] File("src/foo.kt").hashCode() = 789
|
||||||
|
// It's also important to get the hash code using `File.hashCode()` instead of `String.hashCode()` because the hashCode() method
|
||||||
|
// needs to account for case-insensitive filesystems.
|
||||||
|
return File(pathConverter.toPath(file)).hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEqual(file1: File, file2: File): Boolean {
|
||||||
|
return file1 == file2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,23 +16,42 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
|
import com.intellij.util.io.DataExternalizer
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||||
import com.intellij.util.io.ExternalIntegerKeyDescriptor
|
import com.intellij.util.io.ExternalIntegerKeyDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
||||||
|
import java.io.DataInput
|
||||||
|
import java.io.DataOutput
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal class IdToFileMap(
|
internal class IdToFileMap(
|
||||||
file: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : AbstractBasicMap<Int, String>(file, ExternalIntegerKeyDescriptor(), EnumeratorStringDescriptor.INSTANCE, icContext) {
|
) : AbstractBasicMap<Int, File>(
|
||||||
override fun dumpKey(key: Int): String = key.toString()
|
storageFile,
|
||||||
|
LegacyIntExternalizer.toDescriptor(),
|
||||||
|
LegacyFileExternalizer(icContext.pathConverterForSourceFiles),
|
||||||
|
icContext
|
||||||
|
)
|
||||||
|
|
||||||
override fun dumpValue(value: String): String = value
|
/** Similar to [LegacyFileExternalizer]. */
|
||||||
|
private val LegacyIntExternalizer = ExternalIntegerKeyDescriptor.INSTANCE
|
||||||
|
|
||||||
fun getFile(id: Int): File? = storage[id]?.let { pathConverter.toFile(it) }
|
/**
|
||||||
|
* Use [LegacyFqNameExternalizer] instead of [org.jetbrains.kotlin.incremental.IncrementalCompilationContext.fileDescriptorForOutputFiles]
|
||||||
|
* for [IdToFileMap] for now because they internally use different types of `DataExternalizer<String>`, and the `compiler-reference-index`
|
||||||
|
* module in the Kotlin IDEA plugin currently can only read the old data format (see KTIJ-27258).
|
||||||
|
*
|
||||||
|
* Once we fix that bug, we can remove this class and use
|
||||||
|
* [org.jetbrains.kotlin.incremental.IncrementalCompilationContext.fileDescriptorForOutputFiles].
|
||||||
|
*/
|
||||||
|
private class LegacyFileExternalizer(private val pathConverter: FileToPathConverter) : DataExternalizer<File> {
|
||||||
|
|
||||||
operator fun set(id: Int, file: File) {
|
override fun save(output: DataOutput, file: File) {
|
||||||
storage[id] = pathConverter.toPath(file)
|
EnumeratorStringDescriptor.INSTANCE.save(output, pathConverter.toPath(file))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun read(input: DataInput): File {
|
||||||
|
return pathConverter.toFile(EnumeratorStringDescriptor.INSTANCE.read(input))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,14 +59,14 @@ open class InMemoryStorage<KEY, VALUE>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun get(key: KEY): VALUE? = addedEntries[key] ?: modifiedEntries[key] ?: when (key) {
|
override fun get(key: KEY): VALUE? =
|
||||||
in appendedEntries -> {
|
addedEntries[key]
|
||||||
@Suppress("UNCHECKED_CAST")
|
?: modifiedEntries[key]
|
||||||
((storage[key]!! as Collection<*>) + (appendedEntries[key]!! as Collection<*>)) as VALUE
|
// appendedEntries is handled by AppendableInMemoryStorage#get
|
||||||
}
|
?: when (key) {
|
||||||
in removedKeys -> null
|
in removedKeys -> null
|
||||||
else -> storage[key]
|
else -> storage[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun set(key: KEY, value: VALUE) = when (key) {
|
override fun set(key: KEY, value: VALUE) = when (key) {
|
||||||
@@ -110,7 +110,7 @@ open class InMemoryStorage<KEY, VALUE>(
|
|||||||
modifiedEntries.forEach {
|
modifiedEntries.forEach {
|
||||||
storage[it.key] = it.value
|
storage[it.key] = it.value
|
||||||
}
|
}
|
||||||
check(appendedEntries.isEmpty()) { "appendedEntries is not empty" }
|
// appendedEntries is handled by AppendableInMemoryStorage#applyChanges
|
||||||
removedKeys.forEach {
|
removedKeys.forEach {
|
||||||
storage.remove(it)
|
storage.remove(it)
|
||||||
}
|
}
|
||||||
@@ -139,18 +139,23 @@ open class InMemoryStorage<KEY, VALUE>(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [InMemoryStorage] where a map entry's value is a [Collection]. */
|
/** [InMemoryStorage] where a map entry's value is a [Collection] of elements of type [E]. */
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class AppendableInMemoryStorage<KEY, E, VALUE : Collection<E>>(
|
class AppendableInMemoryStorage<KEY, E>(
|
||||||
private val storage: AppendablePersistentStorage<KEY, E, VALUE>,
|
private val storage: AppendablePersistentStorage<KEY, E>,
|
||||||
) : InMemoryStorage<KEY, VALUE>(storage), AppendablePersistentStorage<KEY, E, VALUE> {
|
) : InMemoryStorage<KEY, Collection<E>>(storage), AppendablePersistentStorage<KEY, E> {
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun append(key: KEY, elements: VALUE) = when (key) {
|
override fun get(key: KEY): Collection<E>? = when (key) {
|
||||||
in addedEntries -> addedEntries[key] = (addedEntries[key]!! + elements) as VALUE
|
in appendedEntries -> storage[key]!! + appendedEntries[key]!!
|
||||||
in modifiedEntries -> modifiedEntries[key] = (modifiedEntries[key]!! + elements) as VALUE
|
else -> super.get(key)
|
||||||
in appendedEntries -> appendedEntries[key] = (appendedEntries[key]!! + elements) as VALUE
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun append(key: KEY, elements: Collection<E>) = when (key) {
|
||||||
|
in addedEntries -> addedEntries[key] = addedEntries[key]!! + elements
|
||||||
|
in modifiedEntries -> modifiedEntries[key] = modifiedEntries[key]!! + elements
|
||||||
|
in appendedEntries -> appendedEntries[key] = appendedEntries[key]!! + elements
|
||||||
in removedKeys -> {
|
in removedKeys -> {
|
||||||
removedKeys.remove(key)
|
removedKeys.remove(key)
|
||||||
// Note: We update `modifiedEntries` (not `appendedEntries`), because if the entry is removed and then appended, it is
|
// Note: We update `modifiedEntries` (not `appendedEntries`), because if the entry is removed and then appended, it is
|
||||||
|
|||||||
@@ -95,19 +95,19 @@ open class LazyStorage<KEY, VALUE>(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [LazyStorage] where a map entry's value is a [Collection]. */
|
/** [LazyStorage] where a map entry's value is a [Collection] of elements of type [E]. */
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class AppendableLazyStorage<KEY, E, VALUE : Collection<E>>(
|
class AppendableLazyStorage<KEY, E>(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
keyDescriptor: KeyDescriptor<KEY>,
|
keyDescriptor: KeyDescriptor<KEY>,
|
||||||
elementExternalizer: DataExternalizer<E>,
|
elementExternalizer: DataExternalizer<E>,
|
||||||
) : LazyStorage<KEY, VALUE>(storageFile, keyDescriptor, AppendableCollectionExternalizer(elementExternalizer)),
|
) : LazyStorage<KEY, Collection<E>>(storageFile, keyDescriptor, AppendableCollectionExternalizer(elementExternalizer)),
|
||||||
AppendablePersistentStorage<KEY, E, VALUE> {
|
AppendablePersistentStorage<KEY, E> {
|
||||||
|
|
||||||
private val appendableCollectionExternalizer = AppendableCollectionExternalizer(elementExternalizer)
|
private val appendableCollectionExternalizer = AppendableCollectionExternalizer(elementExternalizer)
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun append(key: KEY, elements: VALUE) {
|
override fun append(key: KEY, elements: Collection<E>) {
|
||||||
getStorageOrCreateNew().appendData(
|
getStorageOrCreateNew().appendData(
|
||||||
key,
|
key,
|
||||||
AppendablePersistentMap.ValueDataAppender { appendableCollectionExternalizer.append(it, elements) }
|
AppendablePersistentMap.ValueDataAppender { appendableCollectionExternalizer.append(it, elements) }
|
||||||
@@ -116,25 +116,25 @@ class AppendableLazyStorage<KEY, E, VALUE : Collection<E>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [DataExternalizer] for a [Collection] of type [E].
|
* [DataExternalizer] for a [Collection] of elements of type [E].
|
||||||
*
|
*
|
||||||
* IMPORTANT: It is a *private* class because it is meant to be used only with a [PersistentHashMap] (e.g., the [read] method reads until
|
* IMPORTANT: It is a *private* class because it is meant to be used only with a [PersistentHashMap] (e.g., the [read] method reads until
|
||||||
* the stream ends, [append] can be called multiple times and its implementation is identical to [save] -- these only work with a
|
* the stream ends, [append] can be called multiple times and its implementation is identical to [save] -- these only work with a
|
||||||
* [PersistentHashMap]).
|
* [PersistentHashMap]).
|
||||||
*/
|
*/
|
||||||
private class AppendableCollectionExternalizer<E, VALUE : Collection<E>>(
|
private class AppendableCollectionExternalizer<E>(
|
||||||
private val elementExternalizer: DataExternalizer<E>,
|
private val elementExternalizer: DataExternalizer<E>,
|
||||||
) : DataExternalizer<VALUE> {
|
) : DataExternalizer<Collection<E>> {
|
||||||
|
|
||||||
fun append(output: DataOutput, elements: VALUE) {
|
fun append(output: DataOutput, elements: Collection<E>) {
|
||||||
save(output, elements)
|
save(output, elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun save(output: DataOutput, value: VALUE) {
|
override fun save(output: DataOutput, value: Collection<E>) {
|
||||||
value.forEach { elementExternalizer.save(output, it) }
|
value.forEach { elementExternalizer.save(output, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(input: DataInput): VALUE {
|
override fun read(input: DataInput): Collection<E> {
|
||||||
val result = ArrayList<E>()
|
val result = ArrayList<E>()
|
||||||
val stream = input as DataInputStream
|
val stream = input as DataInputStream
|
||||||
|
|
||||||
@@ -142,8 +142,7 @@ private class AppendableCollectionExternalizer<E, VALUE : Collection<E>>(
|
|||||||
result.add(elementExternalizer.read(stream))
|
result.add(elementExternalizer.read(stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
return result
|
||||||
return result as VALUE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,13 +163,13 @@ fun <KEY, VALUE> createPersistentStorage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <KEY, E, VALUE : Collection<E>> createAppendablePersistentStorage(
|
fun <KEY, E> createAppendablePersistentStorage(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
keyDescriptor: KeyDescriptor<KEY>,
|
keyDescriptor: KeyDescriptor<KEY>,
|
||||||
elementExternalizer: DataExternalizer<E>,
|
elementExternalizer: DataExternalizer<E>,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
): AppendablePersistentStorage<KEY, E, VALUE> {
|
): AppendablePersistentStorage<KEY, E> {
|
||||||
return AppendableLazyStorage<KEY, E, VALUE>(storageFile, keyDescriptor, elementExternalizer).let { storage ->
|
return AppendableLazyStorage(storageFile, keyDescriptor, elementExternalizer).let { storage ->
|
||||||
if (icContext.keepIncrementalCompilationCachesInMemory) {
|
if (icContext.keepIncrementalCompilationCachesInMemory) {
|
||||||
AppendableInMemoryStorage(storage).also {
|
AppendableInMemoryStorage(storage).also {
|
||||||
icContext.transaction.registerInMemoryStorageWrapper(it)
|
icContext.transaction.registerInMemoryStorageWrapper(it)
|
||||||
|
|||||||
@@ -22,26 +22,15 @@ import java.io.File
|
|||||||
class LookupMap(
|
class LookupMap(
|
||||||
storage: File,
|
storage: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) :
|
) : AppendableSetBasicMap<LookupSymbolKey, Int>(
|
||||||
AppendableAbstractBasicMap<LookupSymbolKey, Int, Collection<Int>>(
|
storage,
|
||||||
storage,
|
LookupSymbolKeyDescriptor(icContext.storeFullFqNamesInLookupCache),
|
||||||
LookupSymbolKeyDescriptor(icContext.storeFullFqNamesInLookupCache),
|
IntExternalizer,
|
||||||
IntExternalizer,
|
icContext,
|
||||||
icContext,
|
) {
|
||||||
) {
|
|
||||||
|
|
||||||
override fun dumpKey(key: LookupSymbolKey): String = key.toString()
|
|
||||||
|
|
||||||
override fun dumpValue(value: Collection<Int>): String = value.toString()
|
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
fun add(name: String, scope: String, fileId: Int) {
|
fun add(name: String, scope: String, fileId: Int) {
|
||||||
storage.append(LookupSymbolKey(name, scope), fileId)
|
append(LookupSymbolKey(name, scope), fileId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(key: LookupSymbolKey): Collection<Int>? = storage[key]?.toSet()
|
|
||||||
|
|
||||||
operator fun set(key: LookupSymbolKey, fileIds: Set<Int>) {
|
|
||||||
storage[key] = fileIds
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,16 +50,15 @@ interface PersistentStorage<KEY, VALUE> : Closeable {
|
|||||||
override fun close()
|
override fun close()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [PersistentStorage] where a map entry's value is a [Collection]. */
|
/** [PersistentStorage] where a map entry's value is a [Collection] of elements of type [E]. */
|
||||||
interface AppendablePersistentStorage<KEY, E, VALUE : Collection<E>> : PersistentStorage<KEY, VALUE> {
|
interface AppendablePersistentStorage<KEY, E> : PersistentStorage<KEY, Collection<E>> {
|
||||||
|
|
||||||
/** Adds the given [elements] to the collection corresponding to the given [key]. */
|
/** Adds the given [elements] to the collection corresponding to the given [key]. */
|
||||||
fun append(key: KEY, elements: VALUE)
|
fun append(key: KEY, elements: Collection<E>)
|
||||||
|
|
||||||
/** Adds the given [element] to the collection corresponding to the given [key]. */
|
/** Adds the given [element] to the collection corresponding to the given [key]. */
|
||||||
fun append(key: KEY, element: E) {
|
fun append(key: KEY, element: E) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
append(key, listOf(element))
|
||||||
append(key, listOf(element) as VALUE)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,14 +110,14 @@ abstract class PersistentStorageWrapper<KEY, VALUE>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [PersistentStorageWrapper] where a map entry's value is a [Collection]. */
|
/** [PersistentStorageWrapper] where a map entry's value is a [Collection] of elements of type [E]. */
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
abstract class AppendablePersistentStorageWrapper<KEY, E, VALUE : Collection<E>>(
|
abstract class AppendablePersistentStorageWrapper<KEY, E>(
|
||||||
private val appendableStorage: AppendablePersistentStorage<KEY, E, VALUE>,
|
private val appendableStorage: AppendablePersistentStorage<KEY, E>,
|
||||||
) : PersistentStorageWrapper<KEY, VALUE>(appendableStorage), AppendablePersistentStorage<KEY, E, VALUE> {
|
) : PersistentStorageWrapper<KEY, Collection<E>>(appendableStorage), AppendablePersistentStorage<KEY, E> {
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun append(key: KEY, elements: VALUE) {
|
override fun append(key: KEY, elements: Collection<E>) {
|
||||||
appendableStorage.append(key, elements)
|
appendableStorage.append(key, elements)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.utils.ThreadSafe
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [PersistentStorage] which maps [KEY] to [VALUE] as viewed by the users of this class, but delegates operations to another [storage] which
|
|
||||||
* maps [INTERNAL_KEY] to [INTERNAL_VALUE].
|
|
||||||
*
|
|
||||||
* The users of this class need to provide the transformations from [KEY] to [INTERNAL_KEY], [VALUE] to [INTERNAL_VALUE], and vice versa.
|
|
||||||
*/
|
|
||||||
@ThreadSafe
|
|
||||||
abstract class PersistentStorageAdapter<KEY, VALUE, INTERNAL_KEY, INTERNAL_VALUE>(
|
|
||||||
private val storage: PersistentStorage<INTERNAL_KEY, INTERNAL_VALUE>,
|
|
||||||
private val publicToInternalKey: (KEY) -> INTERNAL_KEY,
|
|
||||||
private val internalToPublicKey: (INTERNAL_KEY) -> KEY,
|
|
||||||
private val publicToInternalValue: (VALUE) -> INTERNAL_VALUE,
|
|
||||||
private val internalToPublicValue: (INTERNAL_VALUE) -> VALUE,
|
|
||||||
) : PersistentStorage<KEY, VALUE>, BasicMap<KEY, VALUE> {
|
|
||||||
|
|
||||||
override val storageFile: File = storage.storageFile
|
|
||||||
|
|
||||||
@get:Synchronized
|
|
||||||
override val keys: Set<KEY>
|
|
||||||
get() = storage.keys.mapTo(LinkedHashSet()) { internalToPublicKey(it) }
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun contains(key: KEY): Boolean =
|
|
||||||
storage.contains(publicToInternalKey(key))
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun get(key: KEY): VALUE? =
|
|
||||||
storage[publicToInternalKey(key)]?.let { internalToPublicValue(it) }
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun set(key: KEY, value: VALUE) {
|
|
||||||
storage[publicToInternalKey(key)] = publicToInternalValue(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun remove(key: KEY) {
|
|
||||||
storage.remove(publicToInternalKey(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun flush() {
|
|
||||||
storage.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun close() {
|
|
||||||
storage.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [PersistentStorageAdapter] where a map entry's value is a [Collection]. */
|
|
||||||
@ThreadSafe
|
|
||||||
abstract class AppendablePersistentStorageAdapter<KEY, E, VALUE : Collection<E>, INTERNAL_KEY, INTERNAL_E, INTERNAL_VALUE : Collection<INTERNAL_E>>(
|
|
||||||
private val storage: AppendablePersistentStorage<INTERNAL_KEY, INTERNAL_E, INTERNAL_VALUE>,
|
|
||||||
private val publicToInternalKey: (KEY) -> INTERNAL_KEY,
|
|
||||||
internalToPublicKey: (INTERNAL_KEY) -> KEY,
|
|
||||||
private val publicToInternalValue: (VALUE) -> INTERNAL_VALUE,
|
|
||||||
internalToPublicValue: (INTERNAL_VALUE) -> VALUE,
|
|
||||||
) : PersistentStorageAdapter<KEY, VALUE, INTERNAL_KEY, INTERNAL_VALUE>(
|
|
||||||
storage,
|
|
||||||
publicToInternalKey,
|
|
||||||
internalToPublicKey,
|
|
||||||
publicToInternalValue,
|
|
||||||
internalToPublicValue
|
|
||||||
), AppendablePersistentStorage<KEY, E, VALUE> {
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun append(key: KEY, elements: VALUE) {
|
|
||||||
storage.append(publicToInternalKey(key), publicToInternalValue(elements))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
@@ -17,6 +17,8 @@ import java.io.File
|
|||||||
class RelocatableFileToPathConverter(private val baseDir: File) : FileToPathConverter {
|
class RelocatableFileToPathConverter(private val baseDir: File) : FileToPathConverter {
|
||||||
|
|
||||||
override fun toPath(file: File): String {
|
override fun toPath(file: File): String {
|
||||||
|
check(file.isAbsolute) { "Expected absolute path but found relative path: ${file.path}" }
|
||||||
|
|
||||||
// Note: If the given file is located outside `baseDir`, the relative path will start with "../". It's not "clean", but it can work.
|
// Note: If the given file is located outside `baseDir`, the relative path will start with "../". It's not "clean", but it can work.
|
||||||
// TODO: Re-design the code such that `baseDir` always contains the given file (also add a precondition check here).
|
// TODO: Re-design the code such that `baseDir` always contains the given file (also add a precondition check here).
|
||||||
return file.relativeTo(baseDir).invariantSeparatorsPath
|
return file.relativeTo(baseDir).invariantSeparatorsPath
|
||||||
|
|||||||
@@ -5,44 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
||||||
import org.jetbrains.kotlin.incremental.dumpCollection
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class SourceToJsOutputMap(
|
class SourceToJsOutputMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : AppendableBasicStringMap<String, Collection<String>>(storageFile, EnumeratorStringDescriptor.INSTANCE, icContext) {
|
) : AppendableSetBasicMap<File, File>(
|
||||||
override fun dumpValue(value: Collection<String>): String = value.dumpCollection()
|
storageFile,
|
||||||
|
icContext.fileDescriptorForSourceFiles,
|
||||||
@Synchronized
|
icContext.fileDescriptorForOutputFiles,
|
||||||
fun add(key: File, value: File) {
|
icContext
|
||||||
storage.append(pathConverter.toPath(key), pathConverter.toPath(value))
|
)
|
||||||
}
|
|
||||||
|
|
||||||
operator fun get(sourceFile: File): Collection<File> =
|
|
||||||
storage[pathConverter.toPath(sourceFile)]?.mapTo(mutableSetOf()) { pathConverter.toFile(it) } ?: setOf()
|
|
||||||
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
operator fun set(key: File, values: Collection<File>) {
|
|
||||||
if (values.isEmpty()) {
|
|
||||||
remove(key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
storage[pathConverter.toPath(key)] = values.toSet().map { pathConverter.toPath(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun remove(key: File) {
|
|
||||||
storage.remove(pathConverter.toPath(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun removeValues(key: File, removed: Set<File>) {
|
|
||||||
val notRemoved = this[key].filter { it !in removed }
|
|
||||||
this[key] = notRemoved
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,11 +16,12 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
import com.intellij.util.io.DataExternalizer
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
||||||
import org.jetbrains.kotlin.incremental.dumpCollection
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
|
import java.io.DataInput
|
||||||
|
import java.io.DataOutput
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal class SourceToJvmNameMap(
|
internal class SourceToJvmNameMap(
|
||||||
@@ -37,30 +38,27 @@ internal abstract class AbstractSourceToOutputMap<Name>(
|
|||||||
private val nameTransformer: NameTransformer<Name>,
|
private val nameTransformer: NameTransformer<Name>,
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : AppendableBasicStringMap<String, Collection<String>>(
|
) : AppendableSetBasicMap<File, Name>(
|
||||||
storageFile,
|
storageFile,
|
||||||
PathStringDescriptor,
|
icContext.fileDescriptorForSourceFiles,
|
||||||
EnumeratorStringDescriptor.INSTANCE,
|
NameExternalizer(nameTransformer),
|
||||||
icContext
|
icContext
|
||||||
) {
|
) {
|
||||||
fun clearOutputsForSource(sourceFile: File) {
|
|
||||||
remove(pathConverter.toPath(sourceFile))
|
@Synchronized
|
||||||
|
fun getFqNames(sourceFile: File): Collection<FqName>? =
|
||||||
|
this[sourceFile]?.map { nameTransformer.asFqName(nameTransformer.asString(it)) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NameExternalizer<Name>(private val nameTransformer: NameTransformer<Name>) : DataExternalizer<Name> {
|
||||||
|
|
||||||
|
override fun save(output: DataOutput, name: Name) {
|
||||||
|
StringExternalizer.save(output, nameTransformer.asString(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(sourceFile: File, className: Name) {
|
override fun read(input: DataInput): Name {
|
||||||
storage.append(pathConverter.toPath(sourceFile), nameTransformer.asString(className))
|
return nameTransformer.asName(StringExternalizer.read(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun contains(sourceFile: File): Boolean =
|
|
||||||
pathConverter.toPath(sourceFile) in storage
|
|
||||||
|
|
||||||
operator fun get(sourceFile: File): Collection<Name> =
|
|
||||||
storage[pathConverter.toPath(sourceFile)].orEmpty().toSet().map(nameTransformer::asName)
|
|
||||||
|
|
||||||
fun getFqNames(sourceFile: File): Collection<FqName> =
|
|
||||||
storage[pathConverter.toPath(sourceFile)].orEmpty().toSet().map(nameTransformer::asFqName)
|
|
||||||
|
|
||||||
override fun dumpValue(value: Collection<String>) =
|
|
||||||
value.dumpCollection()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.util.containers.hash.EqualityPolicy
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
|
||||||
import com.intellij.util.io.DataExternalizer
|
import com.intellij.util.io.DataExternalizer
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
|
||||||
import com.intellij.util.io.IOUtil
|
import com.intellij.util.io.IOUtil
|
||||||
import com.intellij.util.io.KeyDescriptor
|
import com.intellij.util.io.KeyDescriptor
|
||||||
import org.jetbrains.kotlin.inline.InlineFunction
|
import org.jetbrains.kotlin.inline.InlineFunction
|
||||||
@@ -31,10 +29,21 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
|
||||||
|
class DefaultEqualityPolicy<T> : EqualityPolicy<T> {
|
||||||
|
override fun getHashCode(value: T): Int = value.hashCode()
|
||||||
|
override fun isEqual(value1: T, value2: T): Boolean = (value1 == value2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> DataExternalizer<T>.toDescriptor(): KeyDescriptor<T> =
|
||||||
|
object : KeyDescriptor<T>,
|
||||||
|
DataExternalizer<T> by this,
|
||||||
|
EqualityPolicy<T> by DefaultEqualityPolicy<T>() {
|
||||||
|
}
|
||||||
|
|
||||||
class LookupSymbolKeyDescriptor(
|
class LookupSymbolKeyDescriptor(
|
||||||
/** If `true`, original values are saved; if `false`, only hashes are saved. */
|
/** If `true`, original values are saved; if `false`, only hashes are saved. */
|
||||||
private val storeFullFqNames: Boolean = false
|
private val storeFullFqNames: Boolean = false
|
||||||
) : KeyDescriptor<LookupSymbolKey> {
|
) : KeyDescriptor<LookupSymbolKey>, EqualityPolicy<LookupSymbolKey> by DefaultEqualityPolicy() {
|
||||||
|
|
||||||
override fun read(input: DataInput): LookupSymbolKey {
|
override fun read(input: DataInput): LookupSymbolKey {
|
||||||
// Note: The value of the storeFullFqNames variable below may or may not be the same as LookupSymbolKeyDescriptor.storeFullFqNames.
|
// Note: The value of the storeFullFqNames variable below may or may not be the same as LookupSymbolKeyDescriptor.storeFullFqNames.
|
||||||
@@ -67,10 +76,6 @@ class LookupSymbolKeyDescriptor(
|
|||||||
output.writeInt(value.scopeHash)
|
output.writeInt(value.scopeHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getHashCode(value: LookupSymbolKey): Int = value.hashCode()
|
|
||||||
|
|
||||||
override fun isEqual(val1: LookupSymbolKey, val2: LookupSymbolKey): Boolean = val1 == val2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object FqNameExternalizer : DataExternalizer<FqName> {
|
object FqNameExternalizer : DataExternalizer<FqName> {
|
||||||
@@ -220,21 +225,6 @@ object StringExternalizer : DataExternalizer<String> {
|
|||||||
override fun read(input: DataInput): String = IOUtil.readString(input)
|
override fun read(input: DataInput): String = IOUtil.readString(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
object PathStringDescriptor : EnumeratorStringDescriptor() {
|
|
||||||
override fun getHashCode(path: String): Int {
|
|
||||||
return if (StringUtil.isEmpty(path)) 0 else FileUtil.toCanonicalPath(path).hashCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEqual(val1: String, val2: String?): Boolean {
|
|
||||||
if (val1 == val2) return true
|
|
||||||
if (val2 == null) return false
|
|
||||||
|
|
||||||
val path1 = FileUtil.toCanonicalPath(val1)
|
|
||||||
val path2 = FileUtil.toCanonicalPath(val2)
|
|
||||||
return path1 == path2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [DataExternalizer] that delegates to another [DataExternalizer] depending on the type of the object to externalize. */
|
/** [DataExternalizer] that delegates to another [DataExternalizer] depending on the type of the object to externalize. */
|
||||||
class DelegateDataExternalizer<T>(
|
class DelegateDataExternalizer<T>(
|
||||||
val types: List<Class<out T>>,
|
val types: List<Class<out T>>,
|
||||||
@@ -328,7 +318,7 @@ private class CollectionExternalizerForPersistentHashMap<T>(
|
|||||||
* (see [CollectionExternalizerForPersistentHashMap]).
|
* (see [CollectionExternalizerForPersistentHashMap]).
|
||||||
*
|
*
|
||||||
* Currently, we can't change the name or implementation of this class because it is still used by the `compiler-reference-index` module in
|
* Currently, we can't change the name or implementation of this class because it is still used by the `compiler-reference-index` module in
|
||||||
* the Kotlin IDEA plugin and that code relies on this name and implementation being unchanged (see KT-62288).
|
* the Kotlin IDEA plugin and that code relies on this name and implementation being unchanged (see KTIJ-27258).
|
||||||
*
|
*
|
||||||
* Once we remove that dependency, we can remove this class.
|
* Once we remove that dependency, we can remove this class.
|
||||||
*/
|
*/
|
||||||
@@ -345,7 +335,7 @@ object IntCollectionExternalizer :
|
|||||||
/** [DataExternalizer] for a [Collection]. */
|
/** [DataExternalizer] for a [Collection]. */
|
||||||
open class CollectionExternalizerV2<T, C : Collection<T>>(
|
open class CollectionExternalizerV2<T, C : Collection<T>>(
|
||||||
private val elementExternalizer: DataExternalizer<T>,
|
private val elementExternalizer: DataExternalizer<T>,
|
||||||
private val newCollection: (size: Int) -> MutableCollection<T>,
|
private val newCollection: (size: Int) -> MutableCollection<T> = { size -> ArrayList(size) },
|
||||||
) : DataExternalizer<C> {
|
) : DataExternalizer<C> {
|
||||||
|
|
||||||
override fun save(output: DataOutput, collection: C) {
|
override fun save(output: DataOutput, collection: C) {
|
||||||
@@ -369,8 +359,6 @@ open class CollectionExternalizerV2<T, C : Collection<T>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object StringCollectionExternalizer : CollectionExternalizerV2<String, Collection<String>>(StringExternalizer, { size -> ArrayList(size) })
|
|
||||||
|
|
||||||
class ListExternalizer<T>(elementExternalizer: DataExternalizer<T>) :
|
class ListExternalizer<T>(elementExternalizer: DataExternalizer<T>) :
|
||||||
CollectionExternalizerV2<T, List<T>>(elementExternalizer, { size -> ArrayList(size) })
|
CollectionExternalizerV2<T, List<T>>(elementExternalizer, { size -> ArrayList(size) })
|
||||||
|
|
||||||
|
|||||||
+1
-8
@@ -50,20 +50,13 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
|
|||||||
|
|
||||||
val closer = Closer.create()
|
val closer = Closer.create()
|
||||||
caches.forEach {
|
caches.forEach {
|
||||||
closer.register(CacheCloser(it))
|
closer.register(it)
|
||||||
}
|
}
|
||||||
closer.close()
|
closer.close()
|
||||||
|
|
||||||
isClosed = true
|
isClosed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CacheCloser(private val cache: BasicMapsOwner) : Closeable {
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
cache.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open class IncrementalJvmCachesManager(
|
open class IncrementalJvmCachesManager(
|
||||||
|
|||||||
+3
-3
@@ -38,8 +38,8 @@ import org.jetbrains.kotlin.config.Services
|
|||||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||||
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
||||||
|
import org.jetbrains.kotlin.incremental.storage.BasicFileToPathConverter
|
||||||
import org.jetbrains.kotlin.incremental.storage.FileLocations
|
import org.jetbrains.kotlin.incremental.storage.FileLocations
|
||||||
import org.jetbrains.kotlin.incremental.storage.FileToAbsolutePathConverter
|
|
||||||
import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector
|
import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector
|
||||||
import org.jetbrains.kotlin.incremental.util.ExceptionLocation
|
import org.jetbrains.kotlin.incremental.util.ExceptionLocation
|
||||||
import org.jetbrains.kotlin.incremental.util.reportException
|
import org.jetbrains.kotlin.incremental.util.reportException
|
||||||
@@ -90,8 +90,8 @@ abstract class IncrementalCompilerRunner<
|
|||||||
fileLocations: FileLocations?,
|
fileLocations: FileLocations?,
|
||||||
transaction: CompilationTransaction,
|
transaction: CompilationTransaction,
|
||||||
) = IncrementalCompilationContext(
|
) = IncrementalCompilationContext(
|
||||||
pathConverterForSourceFiles = fileLocations?.let { it.getRelocatablePathConverterForSourceFiles() } ?: FileToAbsolutePathConverter,
|
pathConverterForSourceFiles = fileLocations?.let { it.getRelocatablePathConverterForSourceFiles() } ?: BasicFileToPathConverter,
|
||||||
pathConverterForOutputFiles = fileLocations?.let { it.getRelocatablePathConverterForOutputFiles() } ?: FileToAbsolutePathConverter,
|
pathConverterForOutputFiles = fileLocations?.let { it.getRelocatablePathConverterForOutputFiles() } ?: BasicFileToPathConverter,
|
||||||
transaction = transaction,
|
transaction = transaction,
|
||||||
reporter = reporter,
|
reporter = reporter,
|
||||||
trackChangesInLookupCache = shouldTrackChangesInLookupCache,
|
trackChangesInLookupCache = shouldTrackChangesInLookupCache,
|
||||||
|
|||||||
+2
-2
@@ -52,7 +52,7 @@ class InputsCache(
|
|||||||
// generatedFiles can contain multiple entries with the same source file
|
// generatedFiles can contain multiple entries with the same source file
|
||||||
// for example Kapt3 IC will generate a .java stub and .class stub for each source file
|
// for example Kapt3 IC will generate a .java stub and .class stub for each source file
|
||||||
fun registerOutputForSourceFiles(generatedFiles: List<GeneratedFile>) {
|
fun registerOutputForSourceFiles(generatedFiles: List<GeneratedFile>) {
|
||||||
val sourceToOutput = MultiMap<File, File>()
|
val sourceToOutput = MultiMap.createLinked<File, File>()
|
||||||
|
|
||||||
for (generatedFile in generatedFiles) {
|
for (generatedFile in generatedFiles) {
|
||||||
for (source in generatedFile.sourceFiles) {
|
for (source in generatedFile.sourceFiles) {
|
||||||
@@ -61,7 +61,7 @@ class InputsCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for ((source, outputs) in sourceToOutput.entrySet()) {
|
for ((source, outputs) in sourceToOutput.entrySet()) {
|
||||||
sourceToOutputMap[source] = outputs
|
sourceToOutputMap[source] = outputs.toSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-17
@@ -18,41 +18,39 @@ package org.jetbrains.kotlin.incremental.snapshots
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.incremental.ChangedFiles
|
import org.jetbrains.kotlin.incremental.ChangedFiles
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
||||||
import org.jetbrains.kotlin.incremental.storage.BasicStringMap
|
import org.jetbrains.kotlin.incremental.storage.AbstractBasicMap
|
||||||
import org.jetbrains.kotlin.incremental.storage.PathStringDescriptor
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class FileSnapshotMap(
|
class FileSnapshotMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : BasicStringMap<FileSnapshot>(storageFile, PathStringDescriptor, FileSnapshotExternalizer, icContext) {
|
) : AbstractBasicMap<File, FileSnapshot>(
|
||||||
|
storageFile,
|
||||||
override fun dumpValue(value: FileSnapshot): String =
|
icContext.fileDescriptorForSourceFiles,
|
||||||
value.toString()
|
FileSnapshotExternalizer,
|
||||||
|
icContext
|
||||||
|
) {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun compareAndUpdate(newFiles: Iterable<File>): ChangedFiles.Known {
|
fun compareAndUpdate(newFiles: Iterable<File>): ChangedFiles.Known {
|
||||||
val snapshotProvider = SimpleFileSnapshotProviderImpl()
|
val snapshotProvider = SimpleFileSnapshotProviderImpl()
|
||||||
val newOrModified = ArrayList<File>()
|
val newOrModified = ArrayList<File>()
|
||||||
val removed = ArrayList<File>()
|
val removed = ArrayList<File>()
|
||||||
|
|
||||||
val newPaths = newFiles.mapTo(HashSet(), transform = pathConverter::toPath)
|
val newFilesSet = newFiles.toSet()
|
||||||
for (oldPath in storage.keys) {
|
for (oldFile in keys) {
|
||||||
if (oldPath !in newPaths) {
|
if (oldFile !in newFilesSet) {
|
||||||
storage.remove(oldPath)
|
remove(oldFile)
|
||||||
removed.add(pathConverter.toFile(oldPath))
|
removed.add(oldFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (path in newPaths) {
|
for (file in newFilesSet) {
|
||||||
val file = pathConverter.toFile(path)
|
val oldSnapshot = this[file]
|
||||||
val oldSnapshot = storage[path]
|
|
||||||
val newSnapshot = snapshotProvider[file]
|
val newSnapshot = snapshotProvider[file]
|
||||||
|
|
||||||
if (oldSnapshot == null || oldSnapshot != newSnapshot) {
|
if (oldSnapshot == null || oldSnapshot != newSnapshot) {
|
||||||
newOrModified.add(file)
|
newOrModified.add(file)
|
||||||
storage[path] = newSnapshot
|
this[file] = newSnapshot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-15
@@ -6,24 +6,21 @@
|
|||||||
package org.jetbrains.kotlin.incremental.storage
|
package org.jetbrains.kotlin.incremental.storage
|
||||||
|
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
|
||||||
import org.jetbrains.kotlin.incremental.dumpCollection
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class SourceToOutputFilesMap(
|
class SourceToOutputFilesMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
icContext: IncrementalCompilationContext,
|
icContext: IncrementalCompilationContext,
|
||||||
) : BasicStringMap<Collection<String>>(storageFile, PathStringDescriptor, StringCollectionExternalizer, icContext) {
|
) : AppendableSetBasicMap<File, File>(
|
||||||
operator fun set(sourceFile: File, outputFiles: Collection<File>) {
|
storageFile,
|
||||||
storage[icContext.pathConverterForSourceFiles.toPath(sourceFile)] =
|
icContext.fileDescriptorForSourceFiles,
|
||||||
outputFiles.toSet().map(icContext.pathConverterForOutputFiles::toPath)
|
icContext.fileDescriptorForOutputFiles,
|
||||||
|
icContext
|
||||||
|
) {
|
||||||
|
@Synchronized
|
||||||
|
fun getAndRemove(sourceFile: File): Set<File>? {
|
||||||
|
return get(sourceFile).also {
|
||||||
|
remove(sourceFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
operator fun get(sourceFile: File): Collection<File>? =
|
|
||||||
storage[icContext.pathConverterForSourceFiles.toPath(sourceFile)]?.map(icContext.pathConverterForOutputFiles::toFile)
|
|
||||||
|
|
||||||
override fun dumpValue(value: Collection<String>) =
|
|
||||||
value.dumpCollection()
|
|
||||||
|
|
||||||
fun getAndRemove(file: File): Collection<File>? =
|
|
||||||
get(file).also { storage.remove(icContext.pathConverterForSourceFiles.toPath(file)) }
|
|
||||||
}
|
|
||||||
|
|||||||
+21
-17
@@ -60,49 +60,53 @@ class SourceToOutputFilesMapTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSetOneGetReturnsOne() {
|
fun testSetOneGetReturnsOne() {
|
||||||
stofMap[fooDotKt] = listOf(fooDotClass)
|
stofMap[fooDotKt] = setOf(fooDotClass)
|
||||||
|
|
||||||
assertEquals(listOf(fooDotClass), stofMap[fooDotKt])
|
assertEquals(setOf(fooDotClass), stofMap[fooDotKt])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSetDupeGetReturnsUnique() {
|
fun testSetDupeGetReturnsUnique() {
|
||||||
stofMap[fooDotKt] = listOf(fooDotClass, fooDotClass)
|
stofMap.append(fooDotKt, fooDotClass)
|
||||||
|
stofMap.append(fooDotKt, fooDotClass)
|
||||||
|
|
||||||
assertEquals(listOf(fooDotClass), stofMap[fooDotKt])
|
assertEquals(setOf(fooDotClass), stofMap[fooDotKt])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSetOverwriteGetReturnsNew() {
|
fun testSetOverwriteGetReturnsNew() {
|
||||||
val fooKtDotClass = classesDir.resolve("FooKt.class")
|
val fooKtDotClass = classesDir.resolve("FooKt.class")
|
||||||
stofMap[fooDotKt] = listOf(fooDotClass)
|
stofMap[fooDotKt] = setOf(fooDotClass)
|
||||||
stofMap[fooDotKt] = listOf(fooKtDotClass)
|
stofMap[fooDotKt] = setOf(fooKtDotClass)
|
||||||
|
|
||||||
assertEquals(listOf(fooKtDotClass), stofMap[fooDotKt])
|
assertEquals(setOf(fooKtDotClass), stofMap[fooDotKt])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSetRelativeFails() {
|
fun testSetRelativePathFails() {
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalStateException> {
|
||||||
stofMap[fooDotKt] = listOf(File("relativePath"))
|
stofMap[fooDotKt] = setOf(File("relativePath"))
|
||||||
|
}
|
||||||
|
assertFailsWith<IllegalStateException> {
|
||||||
|
stofMap[File("relativePath")] = setOf(fooDotClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGetRelativeFails() {
|
fun testGetRelativePathFails() {
|
||||||
stofMap[fooDotKt] = listOf(fooDotClass)
|
stofMap[fooDotKt] = setOf(fooDotClass)
|
||||||
|
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalStateException> {
|
||||||
stofMap[fooDotKt.relativeTo(srcDir)]
|
stofMap[File("relativePath")]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGetAndRemove() {
|
fun testGetAndRemove() {
|
||||||
stofMap[fooDotKt] = listOf(fooDotClass)
|
stofMap[fooDotKt] = setOf(fooDotClass)
|
||||||
|
|
||||||
assertEquals(listOf(fooDotClass), stofMap.getAndRemove(fooDotKt))
|
assertEquals(setOf(fooDotClass), stofMap.getAndRemove(fooDotKt))
|
||||||
assertNull(stofMap[fooDotKt])
|
assertNull(stofMap[fooDotKt])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,6 @@ class CodeConformanceTest : TestCase() {
|
|||||||
"These files are affected:\n%s",
|
"These files are affected:\n%s",
|
||||||
allowedFiles = listOf(
|
allowedFiles = listOf(
|
||||||
"analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt",
|
"analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt",
|
||||||
"build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt",
|
|
||||||
"compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/CliVirtualFileFinder.kt",
|
"compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/CliVirtualFileFinder.kt",
|
||||||
"compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt",
|
"compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt",
|
||||||
"compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl.kt",
|
"compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl.kt",
|
||||||
|
|||||||
Reference in New Issue
Block a user