K/N: Cache library metadata in IDEA plugin

This commit is contained in:
Dmitriy Dolovov
2018-09-10 14:45:24 +03:00
parent 1df91ff7ec
commit 71be94b3e4
17 changed files with 90 additions and 61 deletions
@@ -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
@@ -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)
}
}
@@ -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
}
}
@@ -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)
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<implementation-class>org.jetbrains.kotlin.ide.konan.KotlinNativeApplicationComponent</implementation-class>
</component>
<component>
<implementation-class>org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeDescriptorManager</implementation-class>
<implementation-class>org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeLoadingMetadataCache</implementation-class>
</component>
</application-components>