diff --git a/plugins/kotlin/compiler-reference-index/resources/intellij.kotlin.compilerReferenceIndex.xml b/plugins/kotlin/compiler-reference-index/resources/intellij.kotlin.compilerReferenceIndex.xml index 24d614aa0106..3fd1aebaf0fa 100644 --- a/plugins/kotlin/compiler-reference-index/resources/intellij.kotlin.compilerReferenceIndex.xml +++ b/plugins/kotlin/compiler-reference-index/resources/intellij.kotlin.compilerReferenceIndex.xml @@ -22,6 +22,19 @@ implementation="org.jetbrains.kotlin.idea.search.refIndex.KotlinDirectInheritorProvider"/> + + + + + + + + () - - fun open(project: Project, projectPath: String): KotlinCompilerReferenceIndexStorage? { - if (project.isDisposed) return null - val buildDataPaths = project.buildDataPaths - val kotlinDataContainerPath = buildDataPaths.kotlinDataContainer ?: kotlin.run { - LOG.warn("${SettingConstants.KOTLIN_DATA_CONTAINER_ID} is not found") - return null - } - - val lookupStorageReader = LookupStorageReader.create(kotlinDataContainerPath, projectPath) ?: kotlin.run { - LOG.warn("LookupStorage not found or corrupted") - return null - } - - val storage = KotlinCompilerReferenceIndexStorage(kotlinDataContainerPath, lookupStorageReader) - if (!storage.initialize(buildDataPaths)) return null - return storage - } - - fun close(storage: KotlinCompilerReferenceIndexStorage?) { - storage?.close().let { - LOG.info("KCRI storage is closed" + if (it == null) " (didn't exist)" else "") - } - } - - fun hasIndex(project: Project): Boolean = LookupStorageReader.hasStorage(project) - - @TestOnly - fun initializeForTests( - buildDataPaths: BuildDataPaths, - destination: ClassOneToManyStorage, - ) = initializeSubtypeStorage(buildDataPaths, destination) - - internal val Project.buildDataPaths: BuildDataPaths - get() = BuildDataPathsImpl(BuildManager.getInstance().getProjectSystemDir(this)) - - internal val BuildDataPaths.kotlinDataContainer: Path? - get() = targetsDataRoot - .resolve(SettingConstants.KOTLIN_DATA_CONTAINER_ID) - .takeIf { it.exists() && it.isDirectory() } - ?.listDirectoryEntries("${SettingConstants.KOTLIN_DATA_CONTAINER_ID}*") - ?.firstOrNull() - - private fun initializeSubtypeStorage(buildDataPaths: BuildDataPaths, destination: ClassOneToManyStorage): Boolean { - var wasCorrupted = false - val destinationMap = MultiMap.createConcurrentSet() - - val futures = mutableListOf>() - val timeOfFilling = measureTimeMillis { - visitSubtypeStorages(buildDataPaths) { storagePath -> - futures += STORAGE_INDEXING_EXECUTOR.submit { - try { - initializeStorage(destinationMap, storagePath) - } catch (e: CorruptedException) { - wasCorrupted = true - LOG.warn("KCRI storage was corrupted", e) - } - } - } - - try { - for (future in futures) { - future.get() - } - } catch (e: InterruptedException) { - LOG.warn("KCRI initialization was interrupted") - throw e - } - } - - if (wasCorrupted) return false - - val timeOfFlush = measureTimeMillis { - for ((key, values) in destinationMap.entrySet()) { - destination.put(key, values) - } - } - - LOG.info("KCRI storage is opened: took ${timeOfFilling + timeOfFlush} ms for ${futures.size} storages (filling map: $timeOfFilling ms, flush to storage: $timeOfFlush ms)") - return true - } - - private fun visitSubtypeStorages(buildDataPaths: BuildDataPaths, processor: (Path) -> Unit) { - for (buildTargetType in JavaModuleBuildTargetType.ALL_TYPES) { - val buildTargetPath = buildDataPaths.getTargetTypeDataRootDir(buildTargetType) - if (buildTargetPath.notExists() || !buildTargetPath.isDirectory()) continue - buildTargetPath.forEachDirectoryEntry { targetDataRoot -> - val workingPath = targetDataRoot.takeIf { it.isDirectory() } - ?.resolve(KOTLIN_CACHE_DIRECTORY_NAME) - ?.resolve(SUBTYPES_STORAGE_NAME) - ?.takeUnless { it.notExists() } - ?: return@forEachDirectoryEntry - - processor(workingPath) - } - } - } - } - - private val subtypesStorage = ClassOneToManyStorage(kotlinDataContainerPath.resolve(SUBTYPES_STORAGE_NAME)) +/** + * Interface responsible for managing the storage of the Kotlin Compiler Reference Index (KCRI). + * Implementations can choose how the data is retrieved from the CRI data. + * Typically there should be one implementation for each build system that wants to offer CRI capabilities. + */ +@ApiStatus.Experimental +interface KotlinCompilerReferenceIndexStorage { + /** + * Returns the list of [VirtualFile]s that make use of the given [fqName]. + */ + fun getUsages(fqName: FqName): List /** - * @return true if initialization was successful + * Returns subtypes of the class/interface identified by [fqName] stored within this storage. + * When [deep] is true, the returned [Sequence] represents the transitive closure over the subtype relation. */ - private fun initialize(buildDataPaths: BuildDataPaths): Boolean = initializeSubtypeStorage(buildDataPaths, subtypesStorage) + fun getSubtypesOf(fqName: FqName, deep: Boolean): Sequence - private fun close() { - lookupStorageReader.close() - subtypesStorage.closeAndClean() - } + /** + * Closes the storage and releases any held resources. + */ + fun close() - fun getUsages(fqName: FqName): List = lookupStorageReader[fqName].mapNotNull { VfsUtil.findFile(it, false) } + companion object { + /** + * Opens a storage for the given [project] by finding the first [KotlinCompilerReferenceIndexStorageProvider] + * that is applicable for the [project]. + * Returns null if no provider is applicable or if storage creation fails (e.g. index missing or corrupted). + */ + internal fun open(project: Project, projectPath: String): KotlinCompilerReferenceIndexStorage? { + val provider = KotlinCompilerReferenceIndexStorageProvider.getApplicableProvider(project) ?: return null + return provider.createStorage(project, projectPath) + } - fun getSubtypesOf(fqName: FqName, deep: Boolean): Sequence = subtypesStorage[fqName, deep] -} - -private fun initializeStorage(destinationMap: MultiMap, subtypesSourcePath: Path) { - createKotlinDataReader(subtypesSourcePath).use { source -> - source.processKeys { key -> - source[key]?.let { values -> - destinationMap.putValues(key, values) - } - - true + /** + * Returns true if the first applicable [KotlinCompilerReferenceIndexStorageProvider] reports that an index exists for [project]. + */ + internal fun hasIndex(project: Project): Boolean { + return KotlinCompilerReferenceIndexStorageProvider.getApplicableProvider(project)?.hasIndex(project) == true } } -} - -private fun createKotlinDataReader(storagePath: Path): PersistentHashMap> = openReadOnlyPersistentHashMap( - storagePath, - EnumeratorStringDescriptor.INSTANCE, - CollectionExternalizer(EnumeratorStringDescriptor.INSTANCE, ::SmartList), -) +} \ No newline at end of file diff --git a/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/KotlinCompilerReferenceIndexStorageProvider.kt b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/KotlinCompilerReferenceIndexStorageProvider.kt new file mode 100644 index 000000000000..989aa1791985 --- /dev/null +++ b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/KotlinCompilerReferenceIndexStorageProvider.kt @@ -0,0 +1,54 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.search.refIndex + +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.project.Project +import org.jetbrains.annotations.ApiStatus + +/** + * Provider for [KotlinCompilerReferenceIndexStorage] implementations. + * The provider is responsible for checking whether it is applicable for a given project and, if it is the case, + * for creating a [KotlinCompilerReferenceIndexStorage] instance. + * + * Typically, there should be one implementation per build system that wants to offer Kotlin CRI capabilities. + * + * Implementations can register themselves via the `org.jetbrains.kotlin.kotlinCompilerReferenceIndexStorageProvider` EP. + */ +@ApiStatus.Experimental +interface KotlinCompilerReferenceIndexStorageProvider { + /** + * Returns true if this provider can operate in the given [project] environment. + * + * The method should be fast and side‑effect free. It is called on the UI thread during provider selection. + */ + fun isApplicable(project: Project): Boolean + + /** + * Returns true iff the underlying index required by this provider exists for the given [project]. + * Implementations should avoid heavy I/O here; a cheap existence/corruption check is sufficient. + */ + fun hasIndex(project: Project): Boolean + + /** + * Creates a new storage instance or returns null if storage cannot be created (e.g., index absent/corrupted). + * + * The [projectPath] is a base directory used by implementations that rely on relative paths persisted in the + * index. Implementations should perform any required light‑weight initialization here and delay heavy work if + * possible. The returned storage must be closed by the caller. + */ + fun createStorage(project: Project, projectPath: String): KotlinCompilerReferenceIndexStorage? + + + companion object { + val EP_NAME: ExtensionPointName = + ExtensionPointName.create("org.jetbrains.kotlin.kotlinCompilerReferenceIndexStorageProvider") + + /** + * Returns the first provider whose [isApplicable] returns true according to the EP registration order. + * + * To change precedence, adjust the `order` attribute in `intellij.kotlin.compilerReferenceIndex.xml`. + */ + fun getApplicableProvider(project: Project): KotlinCompilerReferenceIndexStorageProvider? = + EP_NAME.extensionList.firstOrNull { it.isApplicable(project) } + } +} \ No newline at end of file diff --git a/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/ClassOneToManyStorage.kt b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsClassOneToManyStorage.kt similarity index 73% rename from plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/ClassOneToManyStorage.kt rename to plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsClassOneToManyStorage.kt index 3a8dcf4992a7..60a291fef87f 100644 --- a/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/ClassOneToManyStorage.kt +++ b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsClassOneToManyStorage.kt @@ -1,8 +1,7 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.kotlin.idea.search.refIndex +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.search.refIndex.jps import com.intellij.openapi.diagnostic.logger -import com.intellij.openapi.util.IntellijInternalApi import com.intellij.util.containers.generateRecursiveSequence import com.intellij.util.io.EnumeratorStringDescriptor import com.intellij.util.io.PersistentMapBuilder @@ -14,8 +13,7 @@ import kotlin.io.path.deleteIfExists import kotlin.io.path.listDirectoryEntries import kotlin.io.path.name -@IntellijInternalApi -class ClassOneToManyStorage(storagePath: Path) { +internal class JpsClassOneToManyStorage(storagePath: Path) { init { val storageName = storagePath.name storagePath.parent.listDirectoryEntries("$storageName*").ifNotEmpty { @@ -25,9 +23,9 @@ class ClassOneToManyStorage(storagePath: Path) { } private val storage = PersistentMapBuilder.newBuilder( - storagePath, - EnumeratorStringDescriptor.INSTANCE, - externalizer, + storagePath, + EnumeratorStringDescriptor.INSTANCE, + externalizer, ).build() fun closeAndClean(): Unit = storage.closeAndClean() @@ -42,12 +40,12 @@ class ClassOneToManyStorage(storagePath: Path) { if (!deep) return values return generateRecursiveSequence(values) { - storage[it]?.asSequence() ?: emptySequence() + storage[it]?.asSequence() ?: emptySequence() } } companion object { private val externalizer = StringCollectionExternalizer>(::ArrayList) - private val LOG = logger() + private val LOG = logger() } } \ No newline at end of file diff --git a/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsKotlinCompilerReferenceIndexStorage.kt b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsKotlinCompilerReferenceIndexStorage.kt new file mode 100644 index 000000000000..bf5a619bdd05 --- /dev/null +++ b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsKotlinCompilerReferenceIndexStorage.kt @@ -0,0 +1,143 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.search.refIndex.jps + +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.SmartList +import com.intellij.util.concurrency.AppExecutorUtil +import com.intellij.util.containers.MultiMap +import com.intellij.util.indexing.UnindexedFilesUpdater +import com.intellij.util.io.CorruptedException +import com.intellij.util.io.EnumeratorStringDescriptor +import com.intellij.util.io.PersistentHashMap +import org.jetbrains.annotations.TestOnly +import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType +import org.jetbrains.jps.builders.storage.BuildDataPaths +import org.jetbrains.kotlin.idea.search.refIndex.KotlinCompilerReferenceIndexStorage +import org.jetbrains.kotlin.incremental.KOTLIN_CACHE_DIRECTORY_NAME +import org.jetbrains.kotlin.incremental.storage.BasicMapsOwner +import org.jetbrains.kotlin.incremental.storage.CollectionExternalizer +import org.jetbrains.kotlin.name.FqName +import java.nio.file.Path +import java.util.concurrent.Future +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.io.path.forEachDirectoryEntry +import kotlin.io.path.isDirectory +import kotlin.io.path.notExists +import kotlin.system.measureTimeMillis + +internal class JpsKotlinCompilerReferenceIndexStorageImpl( + private val lookupStorageReader: JpsLookupStorageReader, + private val subtypesStorage: JpsClassOneToManyStorage, +) : KotlinCompilerReferenceIndexStorage { + companion object { + /** + * [org.jetbrains.kotlin.incremental.AbstractIncrementalCache.SUBTYPES] + */ + internal val SUBTYPES_STORAGE_NAME = "subtypes.${BasicMapsOwner.CACHE_EXTENSION}" + + private val STORAGE_INDEXING_EXECUTOR = AppExecutorUtil.createBoundedApplicationPoolExecutor( + "Kotlin compiler references indexing", UnindexedFilesUpdater.getMaxNumberOfIndexingThreads() + ) + + private val LOG = logger() + } + + override fun getUsages(fqName: FqName): List = + lookupStorageReader[fqName].mapNotNull { VfsUtil.findFile(it, false) } + + override fun getSubtypesOf(fqName: FqName, deep: Boolean): Sequence = + subtypesStorage[fqName, deep] + + override fun close() { + lookupStorageReader.close() + subtypesStorage.closeAndClean() + } + + private fun visitSubtypeStorages(buildDataPaths: BuildDataPaths, processor: (Path) -> Unit) { + for (buildTargetType in JavaModuleBuildTargetType.ALL_TYPES) { + val buildTargetPath = buildDataPaths.getTargetTypeDataRootDir(buildTargetType) + if (buildTargetPath.notExists() || !buildTargetPath.isDirectory()) continue + buildTargetPath.forEachDirectoryEntry { targetDataRoot -> + val workingPath = targetDataRoot.takeIf { it.isDirectory() } + ?.resolve(KOTLIN_CACHE_DIRECTORY_NAME) + ?.resolve(SUBTYPES_STORAGE_NAME) + ?.takeUnless { it.notExists() } + ?: return@forEachDirectoryEntry + + processor(workingPath) + } + } + } + + private fun initializeSubtypeStorage(buildDataPaths: BuildDataPaths, destination: JpsClassOneToManyStorage): Boolean { + var wasCorrupted = false + val destinationMap = MultiMap.createConcurrentSet() + + val futures = mutableListOf>() + val timeOfFilling = measureTimeMillis { + visitSubtypeStorages(buildDataPaths) { storagePath -> + futures += STORAGE_INDEXING_EXECUTOR.submit { + try { + initializeStorage(destinationMap, storagePath) + } catch (e: CorruptedException) { + wasCorrupted = true + LOG.warn("KCRI storage was corrupted", e) + } + } + } + + try { + for (future in futures) { + future.get() + } + } catch (e: InterruptedException) { + LOG.warn("KCRI initialization was interrupted") + throw e + } + } + + if (wasCorrupted) return false + + val timeOfFlush = measureTimeMillis { + for ((key, values) in destinationMap.entrySet()) { + destination.put(key, values) + } + } + + LOG.info("KCRI storage is opened: took ${timeOfFilling + timeOfFlush} ms for ${futures.size} storages (filling map: $timeOfFilling ms, flush to storage: $timeOfFlush ms)") + return true + } + + @TestOnly + fun initializeForTests( + buildDataPaths: BuildDataPaths, + destination: JpsClassOneToManyStorage, + ) = initializeSubtypeStorage(buildDataPaths, destination) + + /** + * @return true if initialization was successful + */ + internal fun initialize(buildDataPaths: BuildDataPaths): Boolean = + initializeSubtypeStorage(buildDataPaths, subtypesStorage) +} + +private fun initializeStorage(destinationMap: MultiMap, subtypesSourcePath: Path) { + createKotlinDataReader(subtypesSourcePath).use { source -> + source.processKeys { key -> + source[key]?.let { values -> + destinationMap.putValues(key, values) + } + + true + } + } +} + +private fun createKotlinDataReader(storagePath: Path): PersistentHashMap> = openReadOnlyPersistentHashMap( + storagePath, + EnumeratorStringDescriptor.INSTANCE, + CollectionExternalizer(EnumeratorStringDescriptor.INSTANCE, ::SmartList), +) diff --git a/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsKotlinCompilerReferenceIndexStorageProvider.kt b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsKotlinCompilerReferenceIndexStorageProvider.kt new file mode 100644 index 000000000000..72ce24481fbb --- /dev/null +++ b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsKotlinCompilerReferenceIndexStorageProvider.kt @@ -0,0 +1,61 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.search.refIndex.jps + +import com.intellij.compiler.server.BuildManager +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.project.Project +import org.jetbrains.jps.builders.impl.BuildDataPathsImpl +import org.jetbrains.jps.builders.storage.BuildDataPaths +import org.jetbrains.kotlin.config.SettingConstants +import org.jetbrains.kotlin.idea.search.refIndex.KotlinCompilerReferenceIndexStorage +import org.jetbrains.kotlin.idea.search.refIndex.KotlinCompilerReferenceIndexStorageProvider +import java.nio.file.Path +import kotlin.io.path.exists +import kotlin.io.path.isDirectory +import kotlin.io.path.listDirectoryEntries + +internal class JpsKotlinCompilerReferenceIndexStorageProvider : KotlinCompilerReferenceIndexStorageProvider { + companion object { + private val LOG = logger() + } + + override fun isApplicable(project: Project): Boolean { + val buildDataPaths = project.buildDataPaths + return buildDataPaths.kotlinDataContainer != null + } + + override fun hasIndex(project: Project): Boolean { + return JpsLookupStorageReader.hasStorage(project) + } + + override fun createStorage(project: Project, projectPath: String): KotlinCompilerReferenceIndexStorage? { + if (project.isDisposed) return null + val buildDataPaths = project.buildDataPaths + val kotlinDataContainerPath = buildDataPaths.kotlinDataContainer ?: run { + LOG.warn("${SettingConstants.KOTLIN_DATA_CONTAINER_ID} is not found") + return null + } + + val lookupStorageReader = JpsLookupStorageReader.create(kotlinDataContainerPath, projectPath) ?: run { + LOG.warn("LookupStorage not found or corrupted") + return null + } + val classOneToManyStorage = JpsClassOneToManyStorage( + kotlinDataContainerPath.resolve(JpsKotlinCompilerReferenceIndexStorageImpl.SUBTYPES_STORAGE_NAME)) + + + val storage = JpsKotlinCompilerReferenceIndexStorageImpl(lookupStorageReader, classOneToManyStorage) + if (!storage.initialize(buildDataPaths)) return null + return storage + } +} + +internal val Project.buildDataPaths: BuildDataPaths + get() = BuildDataPathsImpl(BuildManager.getInstance().getProjectSystemDir(this)) + +internal val BuildDataPaths.kotlinDataContainer: Path? + get() = targetsDataRoot + .resolve(SettingConstants.KOTLIN_DATA_CONTAINER_ID) + .takeIf { it.exists() && it.isDirectory() } + ?.listDirectoryEntries("${SettingConstants.KOTLIN_DATA_CONTAINER_ID}*") + ?.firstOrNull() \ No newline at end of file diff --git a/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/LookupStorageReader.kt b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsLookupStorageReader.kt similarity index 68% rename from plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/LookupStorageReader.kt rename to plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsLookupStorageReader.kt index 1a84af44f3e9..76d917c9dece 100644 --- a/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/LookupStorageReader.kt +++ b/plugins/kotlin/compiler-reference-index/src/org/jetbrains/kotlin/idea/search/refIndex/jps/JpsLookupStorageReader.kt @@ -1,17 +1,27 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.kotlin.idea.search.refIndex +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.search.refIndex.jps import com.intellij.openapi.project.Project -import com.intellij.util.io.* -import org.jetbrains.kotlin.idea.search.refIndex.KotlinCompilerReferenceIndexStorage.Companion.buildDataPaths -import org.jetbrains.kotlin.idea.search.refIndex.KotlinCompilerReferenceIndexStorage.Companion.kotlinDataContainer -import org.jetbrains.kotlin.incremental.storage.* +import com.intellij.util.io.DataExternalizer +import com.intellij.util.io.EnumeratorStringDescriptor +import com.intellij.util.io.ExternalIntegerKeyDescriptor +import com.intellij.util.io.KeyDescriptor +import com.intellij.util.io.PersistentHashMap +import com.intellij.util.io.PersistentMapBuilder +import org.jetbrains.kotlin.incremental.storage.BasicMapsOwner +import org.jetbrains.kotlin.incremental.storage.IntCollectionExternalizer +import org.jetbrains.kotlin.incremental.storage.LookupSymbolKey +import org.jetbrains.kotlin.incremental.storage.LookupSymbolKeyDescriptor +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import org.jetbrains.kotlin.name.FqName import java.io.File import java.nio.file.Path +import kotlin.collections.mapNotNull +import kotlin.collections.orEmpty import kotlin.io.path.exists -class LookupStorageReader private constructor( + +internal class JpsLookupStorageReader private constructor( private val lookupStorage: PersistentHashMap>, private val idToFileStorage: PersistentHashMap, projectPath: String, @@ -33,7 +43,7 @@ class LookupStorageReader private constructor( } companion object { - fun create(kotlinDataContainerPath: Path, projectPath: String): LookupStorageReader? { + fun create(kotlinDataContainerPath: Path, projectPath: String): JpsLookupStorageReader? { val lookupStoragePath = kotlinDataContainerPath.resolve(LOOKUP_STORAGE_NAME).takeIf { it.exists() } ?: return null val idToFileStoragePath = kotlinDataContainerPath.resolve(ID_TO_FILE_STORAGE_NAME).takeIf { it.exists() } ?: return null val lookupStorage = openReadOnlyPersistentHashMap( @@ -48,7 +58,7 @@ class LookupStorageReader private constructor( EnumeratorStringDescriptor.INSTANCE, ) - return LookupStorageReader(lookupStorage, idToFileStorage, projectPath) + return JpsLookupStorageReader(lookupStorage, idToFileStorage, projectPath) } fun hasStorage(project: Project): Boolean = project.buildDataPaths