Move K/N decompilers and stub builders to kotlin.git
KTIJ-26526
This commit is contained in:
committed by
Space Team
parent
c5637ccc7e
commit
d7356afe1e
@@ -10,6 +10,9 @@ dependencies {
|
|||||||
implementation(project(":analysis:light-classes-base"))
|
implementation(project(":analysis:light-classes-base"))
|
||||||
implementation(project(":analysis:decompiled:decompiler-to-stubs"))
|
implementation(project(":analysis:decompiled:decompiler-to-stubs"))
|
||||||
implementation(project(":analysis:decompiled:decompiler-to-file-stubs"))
|
implementation(project(":analysis:decompiled:decompiler-to-file-stubs"))
|
||||||
|
implementation(project(":kotlin-util-klib-metadata"))
|
||||||
|
implementation(project(":js:js.serializer"))
|
||||||
|
implementation(project(":kotlin-util-klib-metadata"))
|
||||||
implementation(intellijCore())
|
implementation(intellijCore())
|
||||||
|
|
||||||
testImplementation(projectTests(":compiler:tests-common"))
|
testImplementation(projectTests(":compiler:tests-common"))
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
// 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.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.StandardFileSystems
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.util.PathUtil
|
||||||
|
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||||
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
|
import org.jetbrains.kotlin.library.impl.KotlinLibraryImpl
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
|
||||||
|
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
|
||||||
|
object CachingIdeKlibMetadataLoader : PackageAccessHandler {
|
||||||
|
override fun loadModuleHeader(library: KotlinLibrary): KlibMetadataProtoBuf.Header {
|
||||||
|
val virtualFile = getVirtualFile(library, library.moduleHeaderFile)
|
||||||
|
return virtualFile?.let { cache.getCachedModuleHeader(virtualFile) } ?: KlibMetadataProtoBuf.Header.getDefaultInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadPackageFragment(library: KotlinLibrary, packageFqName: String, partName: String): ProtoBuf.PackageFragment {
|
||||||
|
val virtualFile = getVirtualFile(library, library.packageFragmentFile(packageFqName, partName))
|
||||||
|
return virtualFile?.let { cache.getCachedPackageFragment(virtualFile) } ?: ProtoBuf.PackageFragment.getDefaultInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getVirtualFile(library: KotlinLibrary, file: KFile): VirtualFile? =
|
||||||
|
if (library.isZipped) asJarFileSystemFile(library.libraryFile, file) else asLocalFile(file)
|
||||||
|
|
||||||
|
private fun asJarFileSystemFile(jarFile: KFile, localFile: KFile): VirtualFile? {
|
||||||
|
val fullPath = jarFile.absolutePath + "!" + PathUtil.toSystemIndependentName(localFile.path)
|
||||||
|
return StandardFileSystems.jar().findFileByPath(fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun asLocalFile(localFile: KFile): VirtualFile? {
|
||||||
|
val fullPath = localFile.absolutePath
|
||||||
|
return StandardFileSystems.local().findFileByPath(fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val cache
|
||||||
|
get() = KlibLoadingMetadataCache.getInstance()
|
||||||
|
|
||||||
|
private val KotlinLibrary.moduleHeaderFile
|
||||||
|
get() = (this as KotlinLibraryImpl).metadata.access.layout.moduleHeaderFile
|
||||||
|
|
||||||
|
private fun KotlinLibrary.packageFragmentFile(packageFqName: String, partName: String) =
|
||||||
|
(this as KotlinLibraryImpl).metadata.access.layout.packageFragmentFile(packageFqName, partName)
|
||||||
|
|
||||||
|
private val KotlinLibrary.isZipped
|
||||||
|
get() = (this as KotlinLibraryImpl).base.access.layout.isZipped
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.DecompiledText
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.buildDecompiledText
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.defaultDecompilerRendererOptions
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
|
abstract class Fe10KlibMetadataDecompiler<out V : BinaryVersion>(
|
||||||
|
fileType: FileType,
|
||||||
|
serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
|
flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||||
|
expectedBinaryVersion: () -> V,
|
||||||
|
invalidBinaryVersion: () -> V,
|
||||||
|
stubVersion: Int
|
||||||
|
) : KlibMetadataDecompiler<V>(
|
||||||
|
fileType,
|
||||||
|
serializerProtocol,
|
||||||
|
flexibleTypeDeserializer,
|
||||||
|
expectedBinaryVersion,
|
||||||
|
invalidBinaryVersion
|
||||||
|
) {
|
||||||
|
private val renderer: DescriptorRenderer by lazy {
|
||||||
|
DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val metadataStubBuilder: KlibMetadataStubBuilder by lazy {
|
||||||
|
Fe10KlibMetadataStubBuilder(stubVersion, fileType, serializerProtocol, ::readFileSafely)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDecompiledText(
|
||||||
|
file: FileWithMetadata.Compatible,
|
||||||
|
serializerProtocol: SerializerExtensionProtocol,
|
||||||
|
flexibleTypeDeserializer: FlexibleTypeDeserializer
|
||||||
|
): DecompiledText {
|
||||||
|
return decompiledText(file, serializerProtocol, flexibleTypeDeserializer, renderer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is extracted for [Fe10KlibMetadataDecompiler], [Fe10KlibMetadataStubBuilder] and [K2KlibMetadataDecompiler].
|
||||||
|
* TODO: K2 shouldn't use descriptor renderer for building decompiled text.
|
||||||
|
* Note that decompiled text is not used for building stubs in K2.
|
||||||
|
* That's why in K2 it is important to preserve declaration order during deserialization to not get PSI vs. stubs mismatch.
|
||||||
|
*/
|
||||||
|
internal fun decompiledText(
|
||||||
|
file: FileWithMetadata.Compatible,
|
||||||
|
serializerProtocol: SerializerExtensionProtocol,
|
||||||
|
flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||||
|
renderer: DescriptorRenderer,
|
||||||
|
deserializationConfiguration: DeserializationConfiguration = DeserializationConfiguration.Default
|
||||||
|
): DecompiledText {
|
||||||
|
val packageFqName = file.packageFqName
|
||||||
|
val resolver = KlibMetadataDeserializerForDecompiler(
|
||||||
|
packageFqName, file.proto, file.nameResolver,
|
||||||
|
serializerProtocol, flexibleTypeDeserializer,
|
||||||
|
deserializationConfiguration,
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package org.jetbrains.kotlin.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
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 com.intellij.util.indexing.FileContent
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.defaultDecompilerRendererOptions
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||||
|
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
|
||||||
|
|
||||||
|
open class Fe10KlibMetadataStubBuilder(
|
||||||
|
version: Int,
|
||||||
|
fileType: FileType,
|
||||||
|
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
|
readFile: (VirtualFile) -> FileWithMetadata?
|
||||||
|
) : KlibMetadataStubBuilder(version, fileType, readFile) {
|
||||||
|
private val renderer: DescriptorRenderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||||
|
|
||||||
|
override fun buildMetadataFileStub(fileWithMetadata: FileWithMetadata.Compatible, fileContent: FileContent): PsiFileStub<*> {
|
||||||
|
val ktFileText = decompiledText(fileWithMetadata, serializerProtocol(), DynamicTypeDeserializer, renderer)
|
||||||
|
return createFileStub(fileContent.project, ktFileText.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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 KtFileElementType.INSTANCE.builder.buildStubTree(file) as PsiFileStub<*>
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package org.jetbrains.kotlin.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
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.serialization.deserialization.ClassDeserializer
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
|
|
||||||
|
sealed class FileWithMetadata {
|
||||||
|
class Incompatible(val version: BinaryVersion) : FileWithMetadata()
|
||||||
|
|
||||||
|
open class Compatible(val proto: ProtoBuf.PackageFragment, val version: BinaryVersion) : 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun forPackageFragment(packageFragment: VirtualFile): FileWithMetadata? {
|
||||||
|
val klibMetadataLoadingCache = KlibLoadingMetadataCache.getInstance()
|
||||||
|
val (fragment, version) = klibMetadataLoadingCache.getCachedPackageFragmentWithVersion(packageFragment)
|
||||||
|
if (fragment == null || version == null) return null
|
||||||
|
return Compatible(fragment, version) //todo: check version compatibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.DecompiledText
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.defaultDecompilerRendererOptions
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
|
||||||
|
|
||||||
|
abstract class K2KlibMetadataDecompiler<out V : BinaryVersion>(
|
||||||
|
private val fileType: FileType,
|
||||||
|
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
|
flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||||
|
expectedBinaryVersion: () -> V,
|
||||||
|
invalidBinaryVersion: () -> V,
|
||||||
|
private val stubVersion: Int,
|
||||||
|
) : KlibMetadataDecompiler<V>(fileType, serializerProtocol, flexibleTypeDeserializer, expectedBinaryVersion, invalidBinaryVersion) {
|
||||||
|
private val renderer: DescriptorRenderer by lazy {
|
||||||
|
DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val metadataStubBuilder: KlibMetadataStubBuilder by lazy {
|
||||||
|
K2KlibMetadataStubBuilder(stubVersion, fileType, serializerProtocol, ::readFileSafely)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doReadFile(file: VirtualFile): FileWithMetadata? {
|
||||||
|
return FileWithMetadata.forPackageFragment(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDecompiledText(
|
||||||
|
file: FileWithMetadata.Compatible,
|
||||||
|
serializerProtocol: SerializerExtensionProtocol,
|
||||||
|
flexibleTypeDeserializer: FlexibleTypeDeserializer
|
||||||
|
): DecompiledText {
|
||||||
|
val deserializationConfiguration = object : DeserializationConfiguration {
|
||||||
|
// K2 stubs are built from protobuf directly, declarations there are sorted
|
||||||
|
// Breaking the order causes psi vs stub mismatch
|
||||||
|
override val preserveDeclarationsOrdering: Boolean get() = true
|
||||||
|
}
|
||||||
|
return decompiledText(file, serializerProtocol, flexibleTypeDeserializer, renderer, deserializationConfiguration)
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.stubs.PsiFileStub
|
||||||
|
import com.intellij.util.indexing.FileContent
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.stub.ClsStubBuilderComponents
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.stub.createClassStub
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.stub.createFileStub
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.stub.createPackageDeclarationsStubs
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.stub.file.AnnotationLoaderForStubBuilderImpl
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||||
|
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
|
|
||||||
|
class K2KlibMetadataStubBuilder(
|
||||||
|
private val version: Int,
|
||||||
|
fileType: FileType,
|
||||||
|
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
|
readFile: (VirtualFile) -> FileWithMetadata?,
|
||||||
|
) : KlibMetadataStubBuilder(version, fileType, readFile) {
|
||||||
|
override fun getStubVersion(): Int = version
|
||||||
|
|
||||||
|
override fun buildMetadataFileStub(fileWithMetadata: FileWithMetadata.Compatible, fileContent: FileContent): PsiFileStub<*> {
|
||||||
|
val packageProto = fileWithMetadata.proto.`package`
|
||||||
|
val packageFqName = fileWithMetadata.packageFqName
|
||||||
|
val nameResolver = fileWithMetadata.nameResolver
|
||||||
|
val protocol = serializerProtocol()
|
||||||
|
val components = ClsStubBuilderComponents(
|
||||||
|
ProtoBasedClassDataFinder(fileWithMetadata.proto, nameResolver, fileWithMetadata.version),
|
||||||
|
AnnotationLoaderForStubBuilderImpl(protocol),
|
||||||
|
fileContent.file,
|
||||||
|
protocol
|
||||||
|
)
|
||||||
|
val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
|
||||||
|
|
||||||
|
val fileStub = createFileStub(packageFqName, isScript = false)
|
||||||
|
createPackageDeclarationsStubs(
|
||||||
|
fileStub, context,
|
||||||
|
ProtoContainer.Package(packageFqName, context.nameResolver, context.typeTable, source = null),
|
||||||
|
packageProto
|
||||||
|
)
|
||||||
|
for (classProto in fileWithMetadata.classesToDecompile) {
|
||||||
|
createClassStub(
|
||||||
|
fileStub, classProto, nameResolver, nameResolver.getClassId(classProto.fqName), source = null, context = context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return fileStub
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions
|
||||||
|
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
|
||||||
|
|
||||||
|
class K2KotlinNativeMetadataDecompiler : K2KlibMetadataDecompiler<KlibMetadataVersion>(
|
||||||
|
KlibMetaFileType,
|
||||||
|
{ KlibMetadataSerializerProtocol },
|
||||||
|
DynamicTypeDeserializer,
|
||||||
|
{ KlibMetadataVersion.INSTANCE },
|
||||||
|
{ KlibMetadataVersion.INVALID_VERSION },
|
||||||
|
KlibMetaFileType.STUB_VERSION + KotlinStubVersions.BUILTIN_STUB_VERSION
|
||||||
|
)
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// 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.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinDecompiledFileViewProvider
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtDecompiledFile
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.DecompiledText
|
||||||
|
|
||||||
|
class KlibDecompiledFile(
|
||||||
|
provider: KotlinDecompiledFileViewProvider,
|
||||||
|
text: (VirtualFile) -> DecompiledText
|
||||||
|
) : KtDecompiledFile(provider, text)
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
// 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.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.components.Service
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.util.containers.ContainerUtil
|
||||||
|
import org.jetbrains.kotlin.library.KLIB_MANIFEST_FILE_NAME
|
||||||
|
import org.jetbrains.kotlin.library.KLIB_METADATA_FILE_EXTENSION
|
||||||
|
import org.jetbrains.kotlin.library.KLIB_MODULE_METADATA_FILE_NAME
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
|
||||||
|
import org.jetbrains.kotlin.library.metadata.parseModuleHeader
|
||||||
|
import org.jetbrains.kotlin.library.metadata.parsePackageFragment
|
||||||
|
import org.jetbrains.kotlin.library.readKonanLibraryVersioning
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class KlibLoadingMetadataCache {
|
||||||
|
// 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 = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<ProtoBuf.PackageFragment>>()
|
||||||
|
private val moduleHeaderCache = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<KlibMetadataProtoBuf.Header>>()
|
||||||
|
private val libraryMetadataVersionCache = ContainerUtil.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
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCachedPackageFragmentWithVersion(packageFragmentFile: VirtualFile): Pair<ProtoBuf.PackageFragment?, KlibMetadataVersion?> {
|
||||||
|
val packageFragment = getCachedPackageFragment(packageFragmentFile) ?: return null to null
|
||||||
|
val version = getCachedMetadataVersion(getKlibLibraryRootForPackageFragment(packageFragmentFile))
|
||||||
|
return packageFragment to version
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCachedMetadataVersion(libraryRoot: VirtualFile): KlibMetadataVersion? {
|
||||||
|
val manifestFile = libraryRoot.findChild(KLIB_MANIFEST_FILE_NAME) ?: return null
|
||||||
|
|
||||||
|
val metadataVersion = libraryMetadataVersionCache.computeIfAbsent(
|
||||||
|
CacheKey(manifestFile)
|
||||||
|
) {
|
||||||
|
CacheValue(computeLibraryMetadataVersion(manifestFile))
|
||||||
|
}.value
|
||||||
|
|
||||||
|
return metadataVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getKlibLibraryRootForPackageFragment(packageFragmentFile: VirtualFile): VirtualFile {
|
||||||
|
return packageFragmentFile.parent.parent.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isMetadataCompatible(libraryRoot: VirtualFile): Boolean {
|
||||||
|
val metadataVersion = getCachedMetadataVersion(libraryRoot) ?: return false
|
||||||
|
|
||||||
|
return metadataVersion.isCompatibleWithCurrentCompilerVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computePackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? {
|
||||||
|
if (!isMetadataCompatible(getKlibLibraryRootForPackageFragment(packageFragmentFile)))
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun getInstance(): KlibLoadingMetadataCache =
|
||||||
|
ApplicationManager.getApplication().getService(KlibLoadingMetadataCache::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package org.jetbrains.kotlin.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.library.KLIB_METADATA_FILE_EXTENSION
|
||||||
|
|
||||||
|
object KlibMetaFileType : FileType {
|
||||||
|
override fun getName() = "KNM"
|
||||||
|
|
||||||
|
override fun getDescription(): String {
|
||||||
|
return KotlinLabelProviderService.getService()?.getLabelForKlibMetaFileType()
|
||||||
|
?: DEFAULT_DESCRIPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
private const val DEFAULT_DESCRIPTION = "Klib Metadata"
|
||||||
|
}
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
import com.intellij.openapi.fileTypes.FileTypeRegistry
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.compiled.ClassFileDecompilers
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.DecompiledText
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.text.createIncompatibleAbiVersionDecompiledText
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||||
|
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
|
||||||
|
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
|
||||||
|
) : ClassFileDecompilers.Full() {
|
||||||
|
protected abstract val metadataStubBuilder: KlibMetadataStubBuilder
|
||||||
|
|
||||||
|
protected abstract fun doReadFile(file: VirtualFile): FileWithMetadata?
|
||||||
|
|
||||||
|
protected abstract fun getDecompiledText(
|
||||||
|
file: FileWithMetadata.Compatible,
|
||||||
|
serializerProtocol: SerializerExtensionProtocol,
|
||||||
|
flexibleTypeDeserializer: FlexibleTypeDeserializer
|
||||||
|
): DecompiledText
|
||||||
|
|
||||||
|
override fun accepts(file: VirtualFile) = FileTypeRegistry.getInstance().isFileOfType(file, fileType)
|
||||||
|
|
||||||
|
override fun getStubBuilder() = metadataStubBuilder
|
||||||
|
|
||||||
|
override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean) =
|
||||||
|
KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
|
||||||
|
KlibDecompiledFile(
|
||||||
|
provider,
|
||||||
|
::buildDecompiledText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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(FileTypeRegistry.getInstance().isFileOfType(virtualFile, fileType)) { "Unexpected file type ${virtualFile.fileType}" }
|
||||||
|
|
||||||
|
return when (val file = readFileSafely(virtualFile)) {
|
||||||
|
is FileWithMetadata.Incompatible -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), file.version)
|
||||||
|
is FileWithMetadata.Compatible -> getDecompiledText(file, serializerProtocol(), flexibleTypeDeserializer)
|
||||||
|
null -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), invalidBinaryVersion())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.DeserializerForDecompilerBase
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.LoggingErrorReporter
|
||||||
|
import org.jetbrains.kotlin.analysis.decompiler.psi.ResolveEverythingToKotlinAnyLocalClassifierResolver
|
||||||
|
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.incremental.components.LookupTracker
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataClassDataFinder
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.EnumEntriesDeserializationSupportImpl
|
||||||
|
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,
|
||||||
|
deserializationConfiguration: DeserializationConfiguration = DeserializationConfiguration.Default,
|
||||||
|
) : DeserializerForDecompilerBase(packageFqName) {
|
||||||
|
override val builtIns: KotlinBuiltIns get() = DefaultBuiltIns.Instance
|
||||||
|
|
||||||
|
override val deserializationComponents: DeserializationComponents
|
||||||
|
|
||||||
|
init {
|
||||||
|
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
|
||||||
|
|
||||||
|
deserializationComponents = DeserializationComponents(
|
||||||
|
storageManager, moduleDescriptor, deserializationConfiguration,
|
||||||
|
KlibMetadataClassDataFinder(proto, nameResolver),
|
||||||
|
AnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, serializerProtocol), packageFragmentProvider,
|
||||||
|
ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), LoggingErrorReporter(LOG),
|
||||||
|
LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses, ContractDeserializer.DEFAULT,
|
||||||
|
extensionRegistryLite = serializerProtocol.extensionRegistry,
|
||||||
|
samConversionResolver = SamConversionResolverImpl(storageManager, samWithReceiverResolvers = emptyList()),
|
||||||
|
enumEntriesDeserializationSupport = EnumEntriesDeserializationSupportImpl(moduleDescriptor.platform),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
classNames = { emptyList() },
|
||||||
|
debugName = "scope of dummyPackageFragment $facadeFqName in ${deserializationComponents.moduleDescriptor} " +
|
||||||
|
"@KlibMetadataDeserializerForDecompiler"
|
||||||
|
)
|
||||||
|
|
||||||
|
return membersScope.getContributedDescriptors().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOG = Logger.getInstance(KlibMetadataDeserializerForDecompiler::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package org.jetbrains.kotlin.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.fileTypes.FileType
|
||||||
|
import com.intellij.openapi.fileTypes.FileTypeRegistry
|
||||||
|
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.analysis.decompiler.stub.createIncompatibleAbiVersionFileStub
|
||||||
|
|
||||||
|
abstract class KlibMetadataStubBuilder(
|
||||||
|
private val version: Int,
|
||||||
|
private val fileType: FileType,
|
||||||
|
private val readFile: (VirtualFile) -> FileWithMetadata?
|
||||||
|
) : ClsStubBuilder() {
|
||||||
|
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + version
|
||||||
|
|
||||||
|
protected abstract fun buildMetadataFileStub(fileWithMetadata: FileWithMetadata.Compatible, fileContent: FileContent): PsiFileStub<*>
|
||||||
|
|
||||||
|
override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
|
||||||
|
val virtualFile = content.file
|
||||||
|
assert(FileTypeRegistry.getInstance().isFileOfType(virtualFile, fileType)) { "Unexpected file type ${virtualFile.fileType}" }
|
||||||
|
|
||||||
|
val fileWithMetadata = readFile(virtualFile) ?: return null
|
||||||
|
|
||||||
|
return when (fileWithMetadata) {
|
||||||
|
is FileWithMetadata.Incompatible -> createIncompatibleAbiVersionFileStub()
|
||||||
|
is FileWithMetadata.Compatible -> buildMetadataFileStub(fileWithMetadata, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -9,6 +9,7 @@ import com.intellij.openapi.application.ApplicationManager
|
|||||||
|
|
||||||
abstract class KotlinLabelProviderService {
|
abstract class KotlinLabelProviderService {
|
||||||
abstract fun getLabelForBuiltInFileType(): String
|
abstract fun getLabelForBuiltInFileType(): String
|
||||||
|
abstract fun getLabelForKlibMetaFileType(): String
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getService(): KotlinLabelProviderService? =
|
fun getService(): KotlinLabelProviderService? =
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package org.jetbrains.kotlin.analysis.decompiler.psi
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol
|
||||||
|
import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions
|
||||||
|
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
|
||||||
|
|
||||||
|
class KotlinNativeMetadataDecompiler : Fe10KlibMetadataDecompiler<KlibMetadataVersion>(
|
||||||
|
KlibMetaFileType,
|
||||||
|
{ KlibMetadataSerializerProtocol },
|
||||||
|
DynamicTypeDeserializer,
|
||||||
|
{ KlibMetadataVersion.INSTANCE },
|
||||||
|
{ KlibMetadataVersion.INVALID_VERSION },
|
||||||
|
KlibMetaFileType.STUB_VERSION + KotlinStubVersions.BUILTIN_STUB_VERSION
|
||||||
|
) {
|
||||||
|
override fun doReadFile(file: VirtualFile): FileWithMetadata? {
|
||||||
|
return FileWithMetadata.forPackageFragment(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user