K/N: Cache library metadata in IDEA plugin
This commit is contained in:
@@ -7,33 +7,32 @@ package org.jetbrains.kotlin.ide.konan
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.psi.SingleRootFileViewProvider
|
||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.stubs.PsiFileStub
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeLoadingMetadataCache
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
|
||||
import org.jetbrains.kotlin.konan.library.MetadataReader
|
||||
import org.jetbrains.kotlin.konan.library.createKonanLibrary
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.util.KonanFactories.DefaultPackageFragmentsFactory
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
|
||||
import org.jetbrains.kotlin.resolve.konan.platform.KonanPlatform
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.serialization.konan.parseModuleHeader
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
const val KOTLIN_NATIVE_CURRENT_ABI_VERSION = 1
|
||||
@@ -51,25 +50,22 @@ fun createFileStub(project: Project, text: String): PsiFileStub<*> {
|
||||
fun createLoggingErrorReporter(log: Logger) = LoggingErrorReporter(log)
|
||||
|
||||
fun LibraryInfo.createPackageFragmentProviderForLibraryModule(
|
||||
project: Project,
|
||||
storageManager: StorageManager,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
): List<PackageFragmentProvider> {
|
||||
|
||||
// This is to preserve "capabilities" from the original IntelliJ LibraryInfo:
|
||||
if (this.platform != KonanPlatform) return emptyList()
|
||||
|
||||
val libraryRoots = this.getLibraryRoots()
|
||||
|
||||
|
||||
return libraryRoots.map { root ->
|
||||
return libraryRoots.mapNotNull { libraryRoot -> File(libraryRoot).takeIf { it.exists } }.map { libraryRoot ->
|
||||
val konanLibrary =
|
||||
createKonanLibrary(
|
||||
File(root),
|
||||
libraryRoot,
|
||||
KOTLIN_NATIVE_CURRENT_ABI_VERSION,
|
||||
HostManager.host, /* TODO: Inlined from KonanPaths, and looks like a bit incorrect */
|
||||
isDefault = false /* TODO: Is it ok? */
|
||||
HostManager.host /* TODO: Inlined from KonanPaths, and looks like a bit incorrect */,
|
||||
metadataReader = CachingIdeMetadataReaderImpl
|
||||
)
|
||||
konanLibrary.createPackageFragmentProvider(storageManager, languageVersionSettings, moduleDescriptor)
|
||||
}
|
||||
@@ -80,8 +76,10 @@ private fun KonanLibrary.createPackageFragmentProvider(
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
): PackageFragmentProvider {
|
||||
|
||||
val library = this
|
||||
val libraryProto = parseModuleHeader(library.moduleHeaderData)
|
||||
|
||||
val libraryProto = library.moduleHeaderData
|
||||
|
||||
//TODO: Is it required somehow?
|
||||
//val moduleName = Name.special(libraryProto.moduleName)
|
||||
@@ -98,3 +96,21 @@ private fun KonanLibrary.createPackageFragmentProvider(
|
||||
deserializationConfiguration
|
||||
)
|
||||
}
|
||||
|
||||
internal object CachingIdeMetadataReaderImpl : MetadataReader {
|
||||
|
||||
override fun loadSerializedModule(libraryLayout: KonanLibraryLayout): KonanProtoBuf.LinkDataLibrary =
|
||||
cache.getCachedModuleHeader(libraryLayout.moduleHeaderFile.virtualFile)
|
||||
|
||||
override fun loadSerializedPackageFragment(
|
||||
libraryLayout: KonanLibraryLayout,
|
||||
packageFqName: String
|
||||
): KonanProtoBuf.LinkDataPackageFragment =
|
||||
cache.getCachedPackageFragment(libraryLayout.packageFragmentFile(packageFqName).virtualFile)
|
||||
|
||||
private val File.virtualFile: VirtualFile
|
||||
get() = LocalFileSystem.getInstance().refreshAndFindFileByPath(path) ?: error("File not found: $path")
|
||||
|
||||
private val cache
|
||||
get() = KotlinNativeLoadingMetadataCache.getInstance()
|
||||
}
|
||||
|
||||
@@ -67,7 +67,11 @@ private fun createKotlinNativeBuiltIns(projectContext: ProjectContext): KotlinBu
|
||||
if (stdlib != null) {
|
||||
|
||||
val (path, libraryInfo) = stdlib
|
||||
val library = createKonanLibrary(File(path), KOTLIN_NATIVE_CURRENT_ABI_VERSION)
|
||||
val library = createKonanLibrary(
|
||||
File(path),
|
||||
KOTLIN_NATIVE_CURRENT_ABI_VERSION,
|
||||
metadataReader = CachingIdeMetadataReaderImpl
|
||||
)
|
||||
|
||||
val builtInsModule = DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(
|
||||
library,
|
||||
|
||||
@@ -62,7 +62,6 @@ object NativeAnalyzerFacade : ResolverForModuleFactory() {
|
||||
|
||||
if (moduleInfo is LibraryInfo) {
|
||||
val libPackageFragmentProviders = moduleInfo.createPackageFragmentProviderForLibraryModule(
|
||||
moduleContext.project,
|
||||
moduleContext.storageManager,
|
||||
languageVersionSettings,
|
||||
moduleDescriptor
|
||||
|
||||
+17
-11
@@ -8,26 +8,31 @@ package org.jetbrains.kotlin.ide.konan.decompiler
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ApplicationComponent
|
||||
import com.intellij.openapi.vfs.*
|
||||
import com.intellij.util.containers.ContainerUtil.createConcurrentWeakValueMap
|
||||
import com.intellij.util.containers.ContainerUtil.createConcurrentSoftValueMap
|
||||
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.konan.parseModuleHeader
|
||||
import org.jetbrains.kotlin.serialization.konan.parsePackageFragment
|
||||
|
||||
class KotlinNativeDescriptorManager : ApplicationComponent {
|
||||
class KotlinNativeLoadingMetadataCache : ApplicationComponent {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): KotlinNativeDescriptorManager =
|
||||
ApplicationManager.getApplication().getComponent(KotlinNativeDescriptorManager::class.java)
|
||||
fun getInstance(): KotlinNativeLoadingMetadataCache =
|
||||
ApplicationManager.getApplication().getComponent(KotlinNativeLoadingMetadataCache::class.java)
|
||||
}
|
||||
|
||||
private val protoCache = createConcurrentWeakValueMap<VirtualFile, KonanProtoBuf.LinkDataPackageFragment>()
|
||||
private val packageFragmentCache = createConcurrentSoftValueMap<VirtualFile, KonanProtoBuf.LinkDataPackageFragment>()
|
||||
private val moduleHeaderCache = createConcurrentSoftValueMap<VirtualFile, KonanProtoBuf.LinkDataLibrary>()
|
||||
|
||||
fun getCachedPackageFragment(virtualFile: VirtualFile): KonanProtoBuf.LinkDataPackageFragment {
|
||||
return protoCache.computeIfAbsent(virtualFile) {
|
||||
val bytes = virtualFile.contentsToByteArray(false)
|
||||
parsePackageFragment(bytes)
|
||||
fun getCachedPackageFragment(virtualFile: VirtualFile): KonanProtoBuf.LinkDataPackageFragment =
|
||||
packageFragmentCache.computeIfAbsent(virtualFile) {
|
||||
parsePackageFragment(virtualFile.contentsToByteArray(false))
|
||||
}
|
||||
|
||||
fun getCachedModuleHeader(virtualFile: VirtualFile): KonanProtoBuf.LinkDataLibrary =
|
||||
moduleHeaderCache.computeIfAbsent(virtualFile) {
|
||||
parseModuleHeader(virtualFile.contentsToByteArray(false))
|
||||
}
|
||||
}
|
||||
|
||||
override fun initComponent() {
|
||||
VirtualFileManager.getInstance().addVirtualFileListener(object : VirtualFileListener {
|
||||
@@ -40,6 +45,7 @@ class KotlinNativeDescriptorManager : ApplicationComponent {
|
||||
}
|
||||
|
||||
private fun invalidateCaches(virtualFile: VirtualFile) {
|
||||
protoCache.remove(virtualFile)
|
||||
packageFragmentCache.remove(virtualFile)
|
||||
moduleHeaderCache.remove(virtualFile)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@ class KotlinNativeMetadataDecompiler : KotlinNativeMetadataDecompilerBase<Kotlin
|
||||
) {
|
||||
|
||||
override fun doReadFile(file: VirtualFile): FileWithMetadata? {
|
||||
val proto = KotlinNativeDescriptorManager.getInstance().getCachedPackageFragment(file)
|
||||
val proto = KotlinNativeLoadingMetadataCache.getInstance().getCachedPackageFragment(file)
|
||||
return FileWithMetadata.Compatible(proto, KonanSerializerProtocol) //todo: check version compatibility
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
package org.jetbrains.kotlin.ide.konan.index
|
||||
|
||||
import com.intellij.util.indexing.FileBasedIndex
|
||||
import org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeDescriptorManager
|
||||
import org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeLoadingMetadataCache
|
||||
import org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeMetaFileType
|
||||
import org.jetbrains.kotlin.idea.vfilefinder.KotlinFileIndexBase
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -26,7 +26,7 @@ object KotlinNativeMetaFileIndex : KotlinFileIndexBase<KotlinNativeMetaFileIndex
|
||||
|
||||
/*todo: check version?!*/
|
||||
private val INDEXER = indexer { fileContent ->
|
||||
val fragment = KotlinNativeDescriptorManager.getInstance().getCachedPackageFragment(fileContent.file)
|
||||
val fragment = KotlinNativeLoadingMetadataCache.getInstance().getCachedPackageFragment(fileContent.file)
|
||||
FqName(fragment.fqName)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user