Deserialization/class reading: pass chosen JvmMetadataVersion whenever possible
This commit is contained in:
+5
-1
@@ -11,6 +11,7 @@ import com.intellij.psi.ClassFileViewProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@@ -20,7 +21,10 @@ object ClsClassFinder {
|
||||
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
|
||||
|
||||
return partNames.mapNotNull {
|
||||
partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it.substringAfterLast('/'))))
|
||||
partsFinder.findKotlinClass(
|
||||
ClassId(packageFqName, Name.identifier(it.substringAfterLast('/'))),
|
||||
JvmMetadataVersion.INSTANCE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-5
@@ -45,7 +45,7 @@ class ClsKotlinBinaryClassCache {
|
||||
getKotlinBinaryFromCache(file)?.let {
|
||||
return it.isKotlinBinary
|
||||
}
|
||||
return kotlinJvmBinaryClass(file, fileContent) != null
|
||||
return kotlinJvmBinaryClass(file, fileContent, JvmMetadataVersion.INSTANCE) != null
|
||||
}
|
||||
|
||||
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||
@@ -54,16 +54,19 @@ class ClsKotlinBinaryClassCache {
|
||||
return null
|
||||
}
|
||||
|
||||
return kotlinJvmBinaryClass(file, fileContent)
|
||||
return kotlinJvmBinaryClass(file, fileContent, cached?.headerData?.metadataVersion ?: JvmMetadataVersion.INSTANCE)
|
||||
}
|
||||
|
||||
private fun kotlinJvmBinaryClass(
|
||||
file: VirtualFile,
|
||||
fileContent: ByteArray?
|
||||
fileContent: ByteArray?,
|
||||
jvmMetadataVersion: JvmMetadataVersion
|
||||
): KotlinJvmBinaryClass? {
|
||||
if (ModelBranch.getFileBranch(file) != null) return null
|
||||
val classFileContent = try {
|
||||
KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file, fileContent)
|
||||
KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(
|
||||
file, jvmMetadataVersion, fileContent = fileContent
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
if (e is ControlFlowException) throw e
|
||||
return null
|
||||
@@ -94,7 +97,7 @@ class ClsKotlinBinaryClassCache {
|
||||
}
|
||||
}
|
||||
|
||||
val kotlinBinaryClass = kotlinJvmBinaryClass(file, fileContent) ?: return null
|
||||
val kotlinBinaryClass = kotlinJvmBinaryClass(file, fileContent, JvmMetadataVersion.INSTANCE) ?: return null
|
||||
return createHeaderInfo(kotlinBinaryClass)
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.classId
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.io.InputStream
|
||||
@@ -18,15 +19,16 @@ class DirectoryBasedClassFinder(
|
||||
val packageDirectory: VirtualFile,
|
||||
val directoryPackageFqName: FqName
|
||||
) : KotlinClassFinder {
|
||||
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? = findKotlinClassOrContent(javaClass.classId!!)
|
||||
override fun findKotlinClassOrContent(javaClass: JavaClass, jvmMetadataVersion: JvmMetadataVersion): KotlinClassFinder.Result? =
|
||||
findKotlinClassOrContent(javaClass.classId!!, jvmMetadataVersion)
|
||||
|
||||
override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? {
|
||||
override fun findKotlinClassOrContent(classId: ClassId, jvmMetadataVersion: JvmMetadataVersion): KotlinClassFinder.Result? {
|
||||
if (classId.packageFqName != directoryPackageFqName) {
|
||||
return null
|
||||
}
|
||||
val targetName = classId.relativeClassName.pathSegments().joinToString("$", postfix = ".class")
|
||||
val virtualFile = packageDirectory.findChild(targetName)
|
||||
if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) {
|
||||
if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile, jvmMetadataVersion)) {
|
||||
return ClsKotlinBinaryClassCache.getInstance().getKotlinBinaryClass(virtualFile)?.let(::KotlinClass)
|
||||
}
|
||||
return null
|
||||
@@ -45,12 +47,12 @@ class DirectoryBasedClassFinder(
|
||||
/**
|
||||
* Checks if this file is a compiled Kotlin class file ABI-compatible with the current plugin
|
||||
*/
|
||||
private fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean {
|
||||
private fun isKotlinWithCompatibleAbiVersion(file: VirtualFile, jvmMetadataVersion: JvmMetadataVersion): Boolean {
|
||||
val clsKotlinBinaryClassCache = ClsKotlinBinaryClassCache.getInstance()
|
||||
if (!clsKotlinBinaryClassCache.isKotlinJvmCompiledFile(file)) return false
|
||||
|
||||
val kotlinClass = clsKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)
|
||||
return kotlinClass != null && kotlinClass.metadataVersion.isCompatible()
|
||||
return kotlinClass != null && kotlinClass.metadataVersion.isCompatible(jvmMetadataVersion)
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-2
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.decompiler.stub.file
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassData
|
||||
@@ -15,10 +16,11 @@ import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
|
||||
|
||||
class DirectoryBasedDataFinder(
|
||||
val classFinder: DirectoryBasedClassFinder,
|
||||
val log: Logger
|
||||
val log: Logger,
|
||||
private val jvmMetadataVersion: JvmMetadataVersion
|
||||
) : ClassDataFinder {
|
||||
override fun findClassData(classId: ClassId): ClassData? {
|
||||
val binaryClass = classFinder.findKotlinClass(classId) ?: return null
|
||||
val binaryClass = classFinder.findKotlinClass(classId, jvmMetadataVersion) ?: return null
|
||||
val classHeader = binaryClass.classHeader
|
||||
val data = classHeader.data
|
||||
if (data == null) {
|
||||
|
||||
+13
-7
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -32,7 +33,6 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
open class KotlinClsStubBuilder : ClsStubBuilder() {
|
||||
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + KotlinStubVersions.CLASSFILE_STUB_VERSION
|
||||
@@ -60,11 +60,11 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
|
||||
val classId = kotlinClass.classId
|
||||
val packageFqName = header.packageName?.let { FqName(it) } ?: classId.packageFqName
|
||||
|
||||
if (!header.metadataVersion.isCompatible()) {
|
||||
if (!header.metadataVersion.isCompatibleWithCurrentCompilerVersion()) {
|
||||
return createIncompatibleAbiVersionFileStub()
|
||||
}
|
||||
|
||||
val components = createStubBuilderComponents(file, packageFqName, fileContent)
|
||||
val components = createStubBuilderComponents(file, packageFqName, fileContent, header.metadataVersion)
|
||||
if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) {
|
||||
val partFiles = ClsClassFinder.findMultifileClassParts(file, classId, header.multifilePartNames)
|
||||
return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components)
|
||||
@@ -105,10 +105,15 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName, fileContent: ByteArray): ClsStubBuilderComponents {
|
||||
private fun createStubBuilderComponents(
|
||||
file: VirtualFile,
|
||||
packageFqName: FqName,
|
||||
fileContent: ByteArray,
|
||||
jvmMetadataVersion: JvmMetadataVersion
|
||||
): ClsStubBuilderComponents {
|
||||
val classFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
|
||||
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
|
||||
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, file, fileContent)
|
||||
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG, jvmMetadataVersion)
|
||||
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, file, fileContent, jvmMetadataVersion)
|
||||
return ClsStubBuilderComponents(classDataFinder, annotationLoader, file)
|
||||
}
|
||||
|
||||
@@ -127,7 +132,8 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
|
||||
private class AnnotationLoaderForClassFileStubBuilder(
|
||||
kotlinClassFinder: KotlinClassFinder,
|
||||
private val cachedFile: VirtualFile,
|
||||
private val cachedFileContent: ByteArray
|
||||
private val cachedFileContent: ByteArray,
|
||||
override val jvmMetadataVersion: JvmMetadataVersion
|
||||
) : AbstractBinaryClassAnnotationLoader<ClassId, AnnotationLoaderForClassFileStubBuilder.AnnotationsClassIdContainer>(kotlinClassFinder) {
|
||||
|
||||
private val storage =
|
||||
|
||||
+10
-10
@@ -16,10 +16,8 @@ import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.kotlin.BinaryClassAnnotationAndConstantLoaderImpl
|
||||
import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeDeserializer
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.*
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -33,12 +31,13 @@ fun DeserializerForClassfileDecompiler(classFile: VirtualFile): DeserializerForC
|
||||
ClsKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(classFile)
|
||||
?: error("Decompiled data factory shouldn't be called on an unsupported file: $classFile")
|
||||
val packageFqName = kotlinClassHeaderInfo.classId.packageFqName
|
||||
return DeserializerForClassfileDecompiler(classFile.parent!!, packageFqName)
|
||||
return DeserializerForClassfileDecompiler(classFile.parent!!, packageFqName, kotlinClassHeaderInfo.metadataVersion)
|
||||
}
|
||||
|
||||
class DeserializerForClassfileDecompiler(
|
||||
packageDirectory: VirtualFile,
|
||||
directoryPackageFqName: FqName
|
||||
directoryPackageFqName: FqName,
|
||||
private val jvmMetadataVersion: JvmMetadataVersion
|
||||
) : DeserializerForDecompilerBase(directoryPackageFqName) {
|
||||
override val builtIns: KotlinBuiltIns get() = DefaultBuiltIns.Instance
|
||||
|
||||
@@ -47,10 +46,11 @@ class DeserializerForClassfileDecompiler(
|
||||
override val deserializationComponents: DeserializationComponents
|
||||
|
||||
init {
|
||||
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
|
||||
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG, jvmMetadataVersion)
|
||||
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
|
||||
val annotationAndConstantLoader =
|
||||
BinaryClassAnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, storageManager, classFinder)
|
||||
val annotationAndConstantLoader = createBinaryClassAnnotationAndConstantLoader(
|
||||
moduleDescriptor, notFoundClasses, storageManager, classFinder, jvmMetadataVersion
|
||||
)
|
||||
|
||||
val configuration = object : DeserializationConfiguration {
|
||||
override val readDeserializedContracts: Boolean = true
|
||||
@@ -72,7 +72,7 @@ class DeserializerForClassfileDecompiler(
|
||||
assert(packageFqName == directoryPackageFqName) {
|
||||
"Was called for $facadeFqName; only members of $directoryPackageFqName package are expected."
|
||||
}
|
||||
val binaryClassForPackageClass = classFinder.findKotlinClass(ClassId.topLevel(facadeFqName))
|
||||
val binaryClassForPackageClass = classFinder.findKotlinClass(ClassId.topLevel(facadeFqName), jvmMetadataVersion)
|
||||
val header = binaryClassForPackageClass?.classHeader
|
||||
val annotationData = header?.data
|
||||
val strings = header?.strings
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ fun buildDecompiledTextForClassFile(
|
||||
|
||||
val classId = classHeader.classId
|
||||
|
||||
if (!classHeader.metadataVersion.isCompatible()) {
|
||||
if (!classHeader.metadataVersion.isCompatibleWithCurrentCompilerVersion()) {
|
||||
return createIncompatibleAbiVersionDecompiledText(JvmMetadataVersion.INSTANCE, classHeader.metadataVersion)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user