Move Klib-related logic from idea-native module
This commit is contained in:
committed by
Dmitriy Dolovov
parent
417554dca0
commit
26ab9b4fc9
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.ide.konan.decompiler
|
||||
|
||||
import org.jetbrains.kotlin.idea.klib.KlibMetaFileType
|
||||
import org.jetbrains.kotlin.idea.util.KotlinBinaryExtension
|
||||
|
||||
class KlibMetaBinary : KotlinBinaryExtension(KlibMetaFileType)
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.idea.klib
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider
|
||||
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
|
||||
|
||||
class KlibDecompiledFile(
|
||||
provider: KotlinDecompiledFileViewProvider,
|
||||
text: (VirtualFile) -> DecompiledText
|
||||
) : KtDecompiledFile(provider, text)
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.klib
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.BaseComponent
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.containers.ContainerUtil.createConcurrentWeakValueMap
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
|
||||
import org.jetbrains.kotlin.library.metadata.parseModuleHeader
|
||||
import org.jetbrains.kotlin.library.metadata.parsePackageFragment
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class KlibLoadingMetadataCache : BaseComponent {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): KlibLoadingMetadataCache =
|
||||
ApplicationManager.getApplication().getComponent(KlibLoadingMetadataCache::class.java)
|
||||
}
|
||||
|
||||
// Use special CacheKey class instead of VirtualFile for cache keys. Certain types of VirtualFiles (for example, obtained from JarFileSystem)
|
||||
// do not compare path (url) and modification stamp in equals() method.
|
||||
private data class CacheKey(
|
||||
val url: String,
|
||||
val modificationStamp: Long
|
||||
) {
|
||||
constructor(virtualFile: VirtualFile) : this(virtualFile.url, virtualFile.modificationStamp)
|
||||
}
|
||||
|
||||
// ConcurrentWeakValueHashMap does not allow null values.
|
||||
private class CacheValue<T : Any>(val value: T?)
|
||||
|
||||
private val packageFragmentCache = createConcurrentWeakValueMap<CacheKey, CacheValue<ProtoBuf.PackageFragment>>()
|
||||
private val moduleHeaderCache = createConcurrentWeakValueMap<CacheKey, CacheValue<KlibMetadataProtoBuf.Header>>()
|
||||
private val libraryMetadataVersionCache = createConcurrentWeakValueMap<CacheKey, CacheValue<KlibMetadataVersion>>()
|
||||
|
||||
fun getCachedPackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? {
|
||||
check(packageFragmentFile.extension == KLIB_METADATA_FILE_EXTENSION) {
|
||||
"Not a package metadata file: $packageFragmentFile"
|
||||
}
|
||||
|
||||
return packageFragmentCache.computeIfAbsent(
|
||||
CacheKey(packageFragmentFile)
|
||||
) {
|
||||
CacheValue(computePackageFragment(packageFragmentFile))
|
||||
}.value
|
||||
}
|
||||
|
||||
fun getCachedModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? {
|
||||
check(moduleHeaderFile.name == KLIB_MODULE_METADATA_FILE_NAME) {
|
||||
"Not a module header file: $moduleHeaderFile"
|
||||
}
|
||||
|
||||
return moduleHeaderCache.computeIfAbsent(
|
||||
CacheKey(moduleHeaderFile)
|
||||
) {
|
||||
CacheValue(computeModuleHeader(moduleHeaderFile))
|
||||
}.value
|
||||
}
|
||||
|
||||
private fun isMetadataCompatible(libraryRoot: VirtualFile): Boolean {
|
||||
val manifestFile = libraryRoot.findChild(KLIB_MANIFEST_FILE_NAME) ?: return false
|
||||
|
||||
val metadataVersion = libraryMetadataVersionCache.computeIfAbsent(
|
||||
CacheKey(manifestFile)
|
||||
) {
|
||||
CacheValue(computeLibraryMetadataVersion(manifestFile))
|
||||
}.value ?: return false
|
||||
|
||||
return metadataVersion.isCompatible()
|
||||
}
|
||||
|
||||
private fun computePackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? {
|
||||
if (!isMetadataCompatible(packageFragmentFile.parent.parent.parent))
|
||||
return null
|
||||
|
||||
return try {
|
||||
parsePackageFragment(packageFragmentFile.contentsToByteArray(false))
|
||||
} catch (_: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? {
|
||||
if (!isMetadataCompatible(moduleHeaderFile.parent.parent))
|
||||
return null
|
||||
|
||||
return try {
|
||||
parseModuleHeader(moduleHeaderFile.contentsToByteArray(false))
|
||||
} catch (_: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeLibraryMetadataVersion(manifestFile: VirtualFile): KlibMetadataVersion? = try {
|
||||
val versioning = Properties().apply { manifestFile.inputStream.use { load(it) } }.readKonanLibraryVersioning()
|
||||
versioning.metadataVersion?.let(BinaryVersion.Companion::parseVersionArray)?.let(::KlibMetadataVersion)
|
||||
} catch (_: IOException) {
|
||||
// ignore and cache null value
|
||||
null
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// ignore and cache null value
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.idea.klib
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileType
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.ide.konan.KotlinNativeBundle
|
||||
import org.jetbrains.kotlin.library.KLIB_METADATA_FILE_EXTENSION
|
||||
|
||||
object KlibMetaFileType : FileType {
|
||||
override fun getName() = "KNM"
|
||||
override fun getDescription() = KotlinNativeBundle.message("kotlin.native.metadata.short")
|
||||
override fun getDefaultExtension() = KLIB_METADATA_FILE_EXTENSION
|
||||
override fun getIcon(): Nothing? = null
|
||||
override fun isBinary() = true
|
||||
override fun isReadOnly() = true
|
||||
override fun getCharset(file: VirtualFile, content: ByteArray): Nothing? = null
|
||||
|
||||
const val STUB_VERSION = 2
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.klib
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileType
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.compiled.ClassFileDecompilers
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider
|
||||
import org.jetbrains.kotlin.idea.decompiler.common.createIncompatibleAbiVersionDecompiledText
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.IOException
|
||||
|
||||
abstract class KlibMetadataDecompiler<out V : BinaryVersion>(
|
||||
private val fileType: FileType,
|
||||
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||
private val flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||
private val expectedBinaryVersion: () -> V,
|
||||
private val invalidBinaryVersion: () -> V,
|
||||
stubVersion: Int
|
||||
) : ClassFileDecompilers.Full() {
|
||||
|
||||
private val metadataStubBuilder: KlibMetadataStubBuilder =
|
||||
KlibMetadataStubBuilder(
|
||||
stubVersion,
|
||||
fileType,
|
||||
serializerProtocol,
|
||||
::readFileSafely
|
||||
)
|
||||
|
||||
private val renderer: DescriptorRenderer by lazy {
|
||||
DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||
}
|
||||
|
||||
protected abstract fun doReadFile(file: VirtualFile): FileWithMetadata?
|
||||
|
||||
override fun accepts(file: VirtualFile) = file.fileType == fileType
|
||||
|
||||
override fun getStubBuilder() = metadataStubBuilder
|
||||
|
||||
override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean) =
|
||||
KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
|
||||
KlibDecompiledFile(
|
||||
provider,
|
||||
::buildDecompiledText
|
||||
)
|
||||
}
|
||||
|
||||
private fun readFileSafely(file: VirtualFile): FileWithMetadata? {
|
||||
if (!file.isValid) return null
|
||||
|
||||
return try {
|
||||
doReadFile(file)
|
||||
} catch (e: IOException) {
|
||||
// This is needed because sometimes we're given VirtualFile instances that point to non-existent .jar entries.
|
||||
// Such files are valid (isValid() returns true), but an attempt to read their contents results in a FileNotFoundException.
|
||||
// Note that although calling "refresh()" instead of catching an exception would seem more correct here,
|
||||
// it's not always allowed and also is likely to degrade performance
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildDecompiledText(virtualFile: VirtualFile): DecompiledText {
|
||||
assert(virtualFile.fileType == fileType) { "Unexpected file type ${virtualFile.fileType}" }
|
||||
|
||||
val file = readFileSafely(virtualFile)
|
||||
|
||||
return when (file) {
|
||||
is FileWithMetadata.Incompatible -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), file.version)
|
||||
is FileWithMetadata.Compatible -> decompiledText(
|
||||
file,
|
||||
serializerProtocol(),
|
||||
flexibleTypeDeserializer,
|
||||
renderer
|
||||
)
|
||||
null -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), invalidBinaryVersion())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class FileWithMetadata {
|
||||
class Incompatible(val version: BinaryVersion) : FileWithMetadata()
|
||||
|
||||
open class Compatible(
|
||||
val proto: ProtoBuf.PackageFragment,
|
||||
serializerProtocol: SerializerExtensionProtocol // TODO: Is it required?
|
||||
) : FileWithMetadata() {
|
||||
val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames)
|
||||
val packageFqName = FqName(proto.getExtension(KlibMetadataProtoBuf.fqName))
|
||||
|
||||
open val classesToDecompile: List<ProtoBuf.Class> =
|
||||
proto.class_List.filter { proto ->
|
||||
val classId = nameResolver.getClassId(proto.fqName)
|
||||
!classId.isNestedClass && classId !in ClassDeserializer.BLACK_LIST
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//todo: this function is extracted for KotlinNativeMetadataStubBuilder, that's the difference from Big Kotlin.
|
||||
fun decompiledText(
|
||||
file: FileWithMetadata.Compatible,
|
||||
serializerProtocol: SerializerExtensionProtocol,
|
||||
flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||
renderer: DescriptorRenderer
|
||||
): DecompiledText {
|
||||
val packageFqName = file.packageFqName
|
||||
val resolver = KlibMetadataDeserializerForDecompiler(
|
||||
packageFqName, file.proto, file.nameResolver,
|
||||
serializerProtocol, flexibleTypeDeserializer
|
||||
)
|
||||
val declarations = arrayListOf<DeclarationDescriptor>()
|
||||
declarations.addAll(resolver.resolveDeclarationsInFacade(packageFqName))
|
||||
for (classProto in file.classesToDecompile) {
|
||||
val classId = file.nameResolver.getClassId(classProto.fqName)
|
||||
declarations.addIfNotNull(resolver.resolveTopLevelClass(classId))
|
||||
}
|
||||
return buildDecompiledText(packageFqName, declarations, renderer)
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.klib
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DeserializerForDecompilerBase
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolveEverythingToKotlinAnyLocalClassifierResolver
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataClassDataFinder
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.sam.SamConversionResolverImpl
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
|
||||
|
||||
class KlibMetadataDeserializerForDecompiler(
|
||||
packageFqName: FqName,
|
||||
private val proto: ProtoBuf.PackageFragment,
|
||||
private val nameResolver: NameResolver,
|
||||
serializerProtocol: SerializerExtensionProtocol,
|
||||
flexibleTypeDeserializer: FlexibleTypeDeserializer
|
||||
) : DeserializerForDecompilerBase(packageFqName) {
|
||||
override val builtIns: KotlinBuiltIns get() = DefaultBuiltIns.Instance
|
||||
|
||||
override val deserializationComponents: DeserializationComponents
|
||||
|
||||
init {
|
||||
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
|
||||
|
||||
deserializationComponents = DeserializationComponents(
|
||||
storageManager, moduleDescriptor, DeserializationConfiguration.Default,
|
||||
KlibMetadataClassDataFinder(proto, nameResolver),
|
||||
AnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, serializerProtocol), packageFragmentProvider,
|
||||
ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), createLoggingErrorReporter(
|
||||
LOG
|
||||
),
|
||||
LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses, ContractDeserializer.DEFAULT,
|
||||
extensionRegistryLite = serializerProtocol.extensionRegistry,
|
||||
samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList())
|
||||
)
|
||||
}
|
||||
|
||||
override fun resolveDeclarationsInFacade(facadeFqName: FqName): List<DeclarationDescriptor> {
|
||||
assert(facadeFqName == directoryPackageFqName) {
|
||||
"Was called for $facadeFqName; only members of $directoryPackageFqName package are expected."
|
||||
}
|
||||
|
||||
val membersScope = DeserializedPackageMemberScope(
|
||||
createDummyPackageFragment(facadeFqName),
|
||||
proto.`package`,
|
||||
nameResolver,
|
||||
KlibMetadataVersion.INSTANCE,
|
||||
containerSource = null,
|
||||
components = deserializationComponents
|
||||
) { emptyList() }
|
||||
|
||||
return membersScope.getContributedDescriptors().toList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(KlibMetadataDeserializerForDecompiler::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
fun createLoggingErrorReporter(log: Logger) = LoggingErrorReporter(log)
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.klib
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileType
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.compiled.ClsStubBuilder
|
||||
import com.intellij.psi.impl.compiled.ClassFileStubBuilder
|
||||
import com.intellij.psi.stubs.PsiFileStub
|
||||
import com.intellij.util.indexing.FileContent
|
||||
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.createIncompatibleAbiVersionFileStub
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
|
||||
|
||||
open class KlibMetadataStubBuilder(
|
||||
private val version: Int,
|
||||
private val fileType: FileType,
|
||||
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||
private val readFile: (VirtualFile) -> FileWithMetadata?
|
||||
) : ClsStubBuilder() {
|
||||
|
||||
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + version
|
||||
|
||||
override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
|
||||
val virtualFile = content.file
|
||||
assert(virtualFile.fileType == fileType) { "Unexpected file type ${virtualFile.fileType}" }
|
||||
|
||||
val file = readFile(virtualFile) ?: return null
|
||||
|
||||
return when (file) {
|
||||
is FileWithMetadata.Incompatible -> createIncompatibleAbiVersionFileStub()
|
||||
is FileWithMetadata.Compatible -> { //todo: this part is implemented in our own way
|
||||
val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||
val ktFileText = decompiledText(
|
||||
file,
|
||||
serializerProtocol(),
|
||||
DynamicTypeDeserializer,
|
||||
renderer
|
||||
)
|
||||
createFileStub(content.project, ktFileText.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.klib
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
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.stubs.PsiFileStub
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
@@ -13,6 +21,7 @@ import org.jetbrains.kotlin.platform.isCommon
|
||||
import org.jetbrains.kotlin.platform.js.isJs
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.platform.konan.isNative
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
@@ -71,3 +80,13 @@ fun <T> KotlinLibrary.readSafe(defaultValue: T, action: KotlinLibrary.() -> T) =
|
||||
} catch (_: IOException) {
|
||||
defaultValue
|
||||
}
|
||||
|
||||
fun createFileStub(project: Project, text: String): PsiFileStub<*> {
|
||||
val virtualFile = LightVirtualFile("dummy.kt", KotlinFileType.INSTANCE, text)
|
||||
virtualFile.language = KotlinLanguage.INSTANCE
|
||||
SingleRootFileViewProvider.doNotCheckFileSizeLimit(virtualFile)
|
||||
|
||||
val psiFileFactory = PsiFileFactory.getInstance(project) as PsiFileFactoryImpl
|
||||
val file = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, false, false)!!
|
||||
return KtStubElementTypes.FILE.builder.buildStubTree(file) as PsiFileStub<*>
|
||||
}
|
||||
@@ -15,6 +15,9 @@ import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache
|
||||
import org.jetbrains.kotlin.idea.decompiler.builtIns.BuiltInDefinitionFile
|
||||
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType
|
||||
import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileType
|
||||
import org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache
|
||||
import org.jetbrains.kotlin.idea.klib.KlibMetaFileType
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.js.JsProtoBuf
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -139,3 +142,29 @@ object KotlinMetadataFileIndex : KotlinMetadataFileIndexBase<KotlinMetadataFileI
|
||||
object KotlinMetadataFilePackageIndex : KotlinMetadataFileIndexBase<KotlinMetadataFilePackageIndex>(
|
||||
KotlinMetadataFilePackageIndex::class.java, ClassId::getPackageFqName
|
||||
)
|
||||
|
||||
object KlibMetaFileIndex : KotlinFileIndexBase<KlibMetaFileIndex>(KlibMetaFileIndex::class.java) {
|
||||
|
||||
override fun getIndexer() = INDEXER
|
||||
|
||||
override fun getInputFilter() = FileBasedIndex.InputFilter { it.fileType === KlibMetaFileType
|
||||
}
|
||||
|
||||
override fun getVersion() = VERSION
|
||||
|
||||
// This is to express intention to index all Kotlin/Native metadata files irrespectively to file size:
|
||||
override fun getFileTypesWithSizeLimitNotApplicable() = listOf(KlibMetaFileType)
|
||||
|
||||
private const val VERSION = 4
|
||||
|
||||
/*todo: check version?!*/
|
||||
private val INDEXER = indexer { fileContent ->
|
||||
val fragment = KlibLoadingMetadataCache
|
||||
.getInstance().getCachedPackageFragment(fileContent.file)
|
||||
if (fragment != null)
|
||||
FqName(fragment.getExtension(KlibMetadataProtoBuf.fqName))
|
||||
else
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user