Deserialization/class reading: pass chosen JvmMetadataVersion whenever possible

This commit is contained in:
Mikhail Glukhikh
2022-12-02 16:38:59 +01:00
parent 52ab565cc6
commit 0c4a0360ac
67 changed files with 399 additions and 163 deletions
@@ -11,6 +11,7 @@ import com.intellij.psi.ClassFileViewProvider
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.findKotlinClass import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader 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.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -20,7 +21,10 @@ object ClsClassFinder {
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName) val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
return partNames.mapNotNull { return partNames.mapNotNull {
partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it.substringAfterLast('/')))) partsFinder.findKotlinClass(
ClassId(packageFqName, Name.identifier(it.substringAfterLast('/'))),
JvmMetadataVersion.INSTANCE
)
} }
} }
@@ -45,7 +45,7 @@ class ClsKotlinBinaryClassCache {
getKotlinBinaryFromCache(file)?.let { getKotlinBinaryFromCache(file)?.let {
return it.isKotlinBinary return it.isKotlinBinary
} }
return kotlinJvmBinaryClass(file, fileContent) != null return kotlinJvmBinaryClass(file, fileContent, JvmMetadataVersion.INSTANCE) != null
} }
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? { fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
@@ -54,16 +54,19 @@ class ClsKotlinBinaryClassCache {
return null return null
} }
return kotlinJvmBinaryClass(file, fileContent) return kotlinJvmBinaryClass(file, fileContent, cached?.headerData?.metadataVersion ?: JvmMetadataVersion.INSTANCE)
} }
private fun kotlinJvmBinaryClass( private fun kotlinJvmBinaryClass(
file: VirtualFile, file: VirtualFile,
fileContent: ByteArray? fileContent: ByteArray?,
jvmMetadataVersion: JvmMetadataVersion
): KotlinJvmBinaryClass? { ): KotlinJvmBinaryClass? {
if (ModelBranch.getFileBranch(file) != null) return null if (ModelBranch.getFileBranch(file) != null) return null
val classFileContent = try { val classFileContent = try {
KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file, fileContent) KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(
file, jvmMetadataVersion, fileContent = fileContent
)
} catch (e: Exception) { } catch (e: Exception) {
if (e is ControlFlowException) throw e if (e is ControlFlowException) throw e
return null 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) return createHeaderInfo(kotlinBinaryClass)
} }
@@ -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.java.structure.classId
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass 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.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import java.io.InputStream import java.io.InputStream
@@ -18,15 +19,16 @@ class DirectoryBasedClassFinder(
val packageDirectory: VirtualFile, val packageDirectory: VirtualFile,
val directoryPackageFqName: FqName val directoryPackageFqName: FqName
) : KotlinClassFinder { ) : 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) { if (classId.packageFqName != directoryPackageFqName) {
return null return null
} }
val targetName = classId.relativeClassName.pathSegments().joinToString("$", postfix = ".class") val targetName = classId.relativeClassName.pathSegments().joinToString("$", postfix = ".class")
val virtualFile = packageDirectory.findChild(targetName) val virtualFile = packageDirectory.findChild(targetName)
if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) { if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile, jvmMetadataVersion)) {
return ClsKotlinBinaryClassCache.getInstance().getKotlinBinaryClass(virtualFile)?.let(::KotlinClass) return ClsKotlinBinaryClassCache.getInstance().getKotlinBinaryClass(virtualFile)?.let(::KotlinClass)
} }
return null return null
@@ -45,12 +47,12 @@ class DirectoryBasedClassFinder(
/** /**
* Checks if this file is a compiled Kotlin class file ABI-compatible with the current plugin * 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() val clsKotlinBinaryClassCache = ClsKotlinBinaryClassCache.getInstance()
if (!clsKotlinBinaryClassCache.isKotlinJvmCompiledFile(file)) return false if (!clsKotlinBinaryClassCache.isKotlinJvmCompiledFile(file)) return false
val kotlinClass = clsKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file) val kotlinClass = clsKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)
return kotlinClass != null && kotlinClass.metadataVersion.isCompatible() return kotlinClass != null && kotlinClass.metadataVersion.isCompatible(jvmMetadataVersion)
} }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.decompiler.stub.file
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.findKotlinClass 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.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData import org.jetbrains.kotlin.serialization.deserialization.ClassData
@@ -15,10 +16,11 @@ import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
class DirectoryBasedDataFinder( class DirectoryBasedDataFinder(
val classFinder: DirectoryBasedClassFinder, val classFinder: DirectoryBasedClassFinder,
val log: Logger val log: Logger,
private val jvmMetadataVersion: JvmMetadataVersion
) : ClassDataFinder { ) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassData? { 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 classHeader = binaryClass.classHeader
val data = classHeader.data val data = classHeader.data
if (data == null) { if (data == null) {
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable 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.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName 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.resolve.constants.KClassValue
import org.jetbrains.kotlin.serialization.deserialization.getClassId import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
open class KotlinClsStubBuilder : ClsStubBuilder() { open class KotlinClsStubBuilder : ClsStubBuilder() {
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + KotlinStubVersions.CLASSFILE_STUB_VERSION override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + KotlinStubVersions.CLASSFILE_STUB_VERSION
@@ -60,11 +60,11 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
val classId = kotlinClass.classId val classId = kotlinClass.classId
val packageFqName = header.packageName?.let { FqName(it) } ?: classId.packageFqName val packageFqName = header.packageName?.let { FqName(it) } ?: classId.packageFqName
if (!header.metadataVersion.isCompatible()) { if (!header.metadataVersion.isCompatibleWithCurrentCompilerVersion()) {
return createIncompatibleAbiVersionFileStub() return createIncompatibleAbiVersionFileStub()
} }
val components = createStubBuilderComponents(file, packageFqName, fileContent) val components = createStubBuilderComponents(file, packageFqName, fileContent, header.metadataVersion)
if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) { if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) {
val partFiles = ClsClassFinder.findMultifileClassParts(file, classId, header.multifilePartNames) val partFiles = ClsClassFinder.findMultifileClassParts(file, classId, header.multifilePartNames)
return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components) 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 classFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG) val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG, jvmMetadataVersion)
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, file, fileContent) val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, file, fileContent, jvmMetadataVersion)
return ClsStubBuilderComponents(classDataFinder, annotationLoader, file) return ClsStubBuilderComponents(classDataFinder, annotationLoader, file)
} }
@@ -127,7 +132,8 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
private class AnnotationLoaderForClassFileStubBuilder( private class AnnotationLoaderForClassFileStubBuilder(
kotlinClassFinder: KotlinClassFinder, kotlinClassFinder: KotlinClassFinder,
private val cachedFile: VirtualFile, private val cachedFile: VirtualFile,
private val cachedFileContent: ByteArray private val cachedFileContent: ByteArray,
override val jvmMetadataVersion: JvmMetadataVersion
) : AbstractBinaryClassAnnotationLoader<ClassId, AnnotationLoaderForClassFileStubBuilder.AnnotationsClassIdContainer>(kotlinClassFinder) { ) : AbstractBinaryClassAnnotationLoader<ClassId, AnnotationLoaderForClassFileStubBuilder.AnnotationsClassIdContainer>(kotlinClassFinder) {
private val storage = private val storage =
@@ -16,10 +16,8 @@ import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.NotFoundClasses import org.jetbrains.kotlin.descriptors.NotFoundClasses
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.kotlin.BinaryClassAnnotationAndConstantLoaderImpl import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeDeserializer import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -33,12 +31,13 @@ fun DeserializerForClassfileDecompiler(classFile: VirtualFile): DeserializerForC
ClsKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(classFile) ClsKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(classFile)
?: error("Decompiled data factory shouldn't be called on an unsupported file: $classFile") ?: error("Decompiled data factory shouldn't be called on an unsupported file: $classFile")
val packageFqName = kotlinClassHeaderInfo.classId.packageFqName val packageFqName = kotlinClassHeaderInfo.classId.packageFqName
return DeserializerForClassfileDecompiler(classFile.parent!!, packageFqName) return DeserializerForClassfileDecompiler(classFile.parent!!, packageFqName, kotlinClassHeaderInfo.metadataVersion)
} }
class DeserializerForClassfileDecompiler( class DeserializerForClassfileDecompiler(
packageDirectory: VirtualFile, packageDirectory: VirtualFile,
directoryPackageFqName: FqName directoryPackageFqName: FqName,
private val jvmMetadataVersion: JvmMetadataVersion
) : DeserializerForDecompilerBase(directoryPackageFqName) { ) : DeserializerForDecompilerBase(directoryPackageFqName) {
override val builtIns: KotlinBuiltIns get() = DefaultBuiltIns.Instance override val builtIns: KotlinBuiltIns get() = DefaultBuiltIns.Instance
@@ -47,10 +46,11 @@ class DeserializerForClassfileDecompiler(
override val deserializationComponents: DeserializationComponents override val deserializationComponents: DeserializationComponents
init { init {
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG) val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG, jvmMetadataVersion)
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor) val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
val annotationAndConstantLoader = val annotationAndConstantLoader = createBinaryClassAnnotationAndConstantLoader(
BinaryClassAnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, storageManager, classFinder) moduleDescriptor, notFoundClasses, storageManager, classFinder, jvmMetadataVersion
)
val configuration = object : DeserializationConfiguration { val configuration = object : DeserializationConfiguration {
override val readDeserializedContracts: Boolean = true override val readDeserializedContracts: Boolean = true
@@ -72,7 +72,7 @@ class DeserializerForClassfileDecompiler(
assert(packageFqName == directoryPackageFqName) { assert(packageFqName == directoryPackageFqName) {
"Was called for $facadeFqName; only members of $directoryPackageFqName package are expected." "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 header = binaryClassForPackageClass?.classHeader
val annotationData = header?.data val annotationData = header?.data
val strings = header?.strings val strings = header?.strings
@@ -27,7 +27,7 @@ fun buildDecompiledTextForClassFile(
val classId = classHeader.classId val classId = classHeader.classId
if (!classHeader.metadataVersion.isCompatible()) { if (!classHeader.metadataVersion.isCompatibleWithCurrentCompilerVersion()) {
return createIncompatibleAbiVersionDecompiledText(JvmMetadataVersion.INSTANCE, classHeader.metadataVersion) return createIncompatibleAbiVersionDecompiledText(JvmMetadataVersion.INSTANCE, classHeader.metadataVersion)
} }
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.build package org.jetbrains.kotlin.build
import org.jetbrains.kotlin.incremental.LocalFileKotlinClass import org.jetbrains.kotlin.incremental.LocalFileKotlinClass
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.sure
import java.io.File import java.io.File
@@ -32,9 +33,10 @@ open class GeneratedFile(
class GeneratedJvmClass( class GeneratedJvmClass(
sourceFiles: Collection<File>, sourceFiles: Collection<File>,
outputFile: File outputFile: File,
jvmMetadataVersionFromLanguageVersion: JvmMetadataVersion
) : GeneratedFile(sourceFiles, outputFile) { ) : GeneratedFile(sourceFiles, outputFile) {
val outputClass = LocalFileKotlinClass.create(outputFile).sure { val outputClass = LocalFileKotlinClass.create(outputFile, jvmMetadataVersionFromLanguageVersion).sure {
"Couldn't load KotlinClass from $outputFile; it may happen because class doesn't have valid Kotlin annotations" "Couldn't load KotlinClass from $outputFile; it may happen because class doesn't have valid Kotlin annotations"
} }
} }
@@ -18,15 +18,16 @@ package org.jetbrains.kotlin.compilerRunner
import org.jetbrains.kotlin.build.GeneratedFile import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.build.GeneratedJvmClass import org.jetbrains.kotlin.build.GeneratedJvmClass
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import java.io.File import java.io.File
data class SimpleOutputItem(val sourceFiles: Collection<File>, val outputFile: File) { data class SimpleOutputItem(val sourceFiles: Collection<File>, val outputFile: File) {
override fun toString(): String = override fun toString(): String =
"$sourceFiles->$outputFile" "$sourceFiles->$outputFile"
} }
fun SimpleOutputItem.toGeneratedFile(): GeneratedFile = fun SimpleOutputItem.toGeneratedFile(jvmMetadataVersionFromLanguageVersion: JvmMetadataVersion): GeneratedFile =
when { when {
outputFile.name.endsWith(".class") -> GeneratedJvmClass(sourceFiles, outputFile) outputFile.name.endsWith(".class") -> GeneratedJvmClass(sourceFiles, outputFile, jvmMetadataVersionFromLanguageVersion)
else -> GeneratedFile(sourceFiles, outputFile) else -> GeneratedFile(sourceFiles, outputFile)
} }
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader 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.ClassId
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import java.io.File import java.io.File
@@ -32,10 +33,12 @@ class LocalFileKotlinClass private constructor(
) : FileBasedKotlinClass(className, classVersion, classHeader, innerClasses) { ) : FileBasedKotlinClass(className, classVersion, classHeader, innerClasses) {
companion object { companion object {
fun create(file: File): LocalFileKotlinClass? { fun create(file: File, jvmMetadataVersionFromLanguageVersion: JvmMetadataVersion): LocalFileKotlinClass? {
val fileContents = file.readBytes() val fileContents = file.readBytes()
return FileBasedKotlinClass.create(fileContents) { return FileBasedKotlinClass.create(
className, classVersion, classHeader, innerClasses -> fileContents,
jvmMetadataVersionFromLanguageVersion
) { className, classVersion, classHeader, innerClasses ->
LocalFileKotlinClass(file, fileContents, className, classVersion, classHeader, innerClasses) LocalFileKotlinClass(file, fileContents, className, classVersion, classHeader, innerClasses)
} }
} }
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.metadata.DebugProtoBuf
import org.jetbrains.kotlin.metadata.js.DebugJsProtoBuf import org.jetbrains.kotlin.metadata.js.DebugJsProtoBuf
import org.jetbrains.kotlin.metadata.jvm.DebugJvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.DebugJvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.BitEncoding import org.jetbrains.kotlin.metadata.jvm.deserialization.BitEncoding
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.protobuf.ExtensionRegistry import org.jetbrains.kotlin.protobuf.ExtensionRegistry
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
@@ -151,8 +152,8 @@ private fun classFileToString(classFile: File): String {
val traceVisitor = TraceClassVisitor(PrintWriter(out)) val traceVisitor = TraceClassVisitor(PrintWriter(out))
ClassReader(classFile.readBytes()).accept(traceVisitor, 0) ClassReader(classFile.readBytes()).accept(traceVisitor, 0)
val classHeader = LocalFileKotlinClass.create(classFile)?.classHeader ?: return "" val classHeader = LocalFileKotlinClass.create(classFile, JvmMetadataVersion.INSTANCE)?.classHeader ?: return ""
if (!classHeader.metadataVersion.isCompatible()) { if (!classHeader.metadataVersion.isCompatibleWithCurrentCompilerVersion()) {
error("Incompatible class ($classHeader): $classFile") error("Incompatible class ($classHeader): $classFile")
} }
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
import org.jetbrains.kotlin.utils.toMetadataVersion
import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.*
@@ -122,7 +123,7 @@ class AnonymousObjectTransformer(
override fun visitEnd() {} override fun visitEnd() {}
}, ClassReader.SKIP_FRAMES) }, ClassReader.SKIP_FRAMES)
val header = metadataReader.createHeader() val header = metadataReader.createHeader(inliningContext.state.languageVersionSettings.languageVersion.toMetadataVersion())
assert(isSameModule || (header != null && isPublicAbi(header))) { assert(isSameModule || (header != null && isPublicAbi(header))) {
"Trying to inline an anonymous object which is not part of the public ABI: ${oldObjectType.className}" "Trying to inline an anonymous object which is not part of the public ABI: ${oldObjectType.className}"
} }
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.diagnostics.OnDemandSuppressCache import org.jetbrains.kotlin.resolve.diagnostics.OnDemandSuppressCache
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
@@ -184,7 +185,7 @@ class GenerationState private constructor(
val packagesWithObsoleteParts: Set<FqName> val packagesWithObsoleteParts: Set<FqName>
val obsoleteMultifileClasses: List<FqName> val obsoleteMultifileClasses: List<FqName>
val deserializationConfiguration: DeserializationConfiguration = val deserializationConfiguration: DeserializationConfiguration =
CompilerDeserializationConfiguration(languageVersionSettings) JvmCompilerDeserializationConfiguration(languageVersionSettings)
val deprecationProvider = DeprecationResolver( val deprecationProvider = DeprecationResolver(
LockBasedStorageManager.NO_LOCKS, languageVersionSettings, JavaDeprecationSettings LockBasedStorageManager.NO_LOCKS, languageVersionSettings, JavaDeprecationSettings
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.EOFException import java.io.EOFException
import java.io.PrintStream import java.io.PrintStream
@@ -38,7 +39,7 @@ class JvmPackagePartProvider(
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
private val scope: GlobalSearchScope private val scope: GlobalSearchScope
) : JvmPackagePartProviderBase<VirtualFile>() { ) : JvmPackagePartProviderBase<VirtualFile>() {
override val deserializationConfiguration = CompilerDeserializationConfiguration(languageVersionSettings) override val deserializationConfiguration = JvmCompilerDeserializationConfiguration(languageVersionSettings)
override val loadedModules: MutableList<ModuleMappingInfo<VirtualFile>> = SmartList() override val loadedModules: MutableList<ModuleMappingInfo<VirtualFile>> = SmartList()
@@ -33,8 +33,8 @@ import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.CommonPlatforms import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
@@ -232,7 +232,7 @@ private class KlibMetadataDependencyContainer(
packageFragmentNames = packageFragmentNames, packageFragmentNames = packageFragmentNames,
storageManager = LockBasedStorageManager("KlibMetadataPackageFragmentProvider"), storageManager = LockBasedStorageManager("KlibMetadataPackageFragmentProvider"),
moduleDescriptor = libraryModuleDescriptor, moduleDescriptor = libraryModuleDescriptor,
configuration = CompilerDeserializationConfiguration(languageVersionSettings), configuration = JvmCompilerDeserializationConfiguration(languageVersionSettings),
compositePackageFragmentAddend = null, compositePackageFragmentAddend = null,
lookupTracker = LookupTracker.DO_NOTHING lookupTracker = LookupTracker.DO_NOTHING
).also { ).also {
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.java.createConstantOrError import org.jetbrains.kotlin.fir.java.createConstantOrError
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.constants.ClassLiteralValue import org.jetbrains.kotlin.resolve.constants.ClassLiteralValue
import org.jetbrains.kotlin.utils.toMetadataVersion
internal class AnnotationsLoader(private val session: FirSession, private val kotlinClassFinder: KotlinClassFinder) { internal class AnnotationsLoader(private val session: FirSession, private val kotlinClassFinder: KotlinClassFinder) {
private fun loadAnnotation( private fun loadAnnotation(
@@ -190,7 +192,7 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
classId.shortClassName.asString() != JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME classId.shortClassName.asString() != JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME
) return false ) return false
val klass = kotlinClassFinder.findKotlinClass(classId) val klass = kotlinClassFinder.findKotlinClass(classId, session.languageVersionSettings.languageVersion.toMetadataVersion())
return klass != null && SpecialJvmAnnotations.isAnnotatedWithContainerMetaAnnotation(klass) return klass != null && SpecialJvmAnnotations.isAnnotatedWithContainerMetaAnnotation(klass)
} }
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.deserialization.AbstractAnnotationDeserializer import org.jetbrains.kotlin.fir.deserialization.AbstractAnnotationDeserializer
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.toMetadataVersion
class JvmBinaryAnnotationDeserializer( class JvmBinaryAnnotationDeserializer(
val session: FirSession, val session: FirSession,
@@ -37,8 +39,9 @@ class JvmBinaryAnnotationDeserializer(
private val annotationInfoForDefaultImpls by lazy(LazyThreadSafetyMode.PUBLICATION) { private val annotationInfoForDefaultImpls by lazy(LazyThreadSafetyMode.PUBLICATION) {
val defaultImplsClassId = kotlinBinaryClass.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)) val defaultImplsClassId = kotlinBinaryClass.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME))
val (defaultImplsClass, defaultImplsByteContent) = kotlinClassFinder.findKotlinClassOrContent(defaultImplsClassId) as? KotlinClassFinder.Result.KotlinClass val (defaultImplsClass, defaultImplsByteContent) = kotlinClassFinder.findKotlinClassOrContent(
?: return@lazy null defaultImplsClassId, session.languageVersionSettings.languageVersion.toMetadataVersion()
) as? KotlinClassFinder.Result.KotlinClass ?: return@lazy null
session.loadMemberAnnotations(defaultImplsClass, defaultImplsByteContent, kotlinClassFinder) session.loadMemberAnnotations(defaultImplsClass, defaultImplsByteContent, kotlinClassFinder)
} }
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.deserialization.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.java.FirJavaFacade import org.jetbrains.kotlin.fir.java.FirJavaFacade
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.load.kotlin.*
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.* import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.utils.toMetadataVersion
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
@@ -60,12 +62,16 @@ class JvmClassFileBasedSymbolProvider(
if (partName in kotlinBuiltins) return@mapNotNull null if (partName in kotlinBuiltins) return@mapNotNull null
val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars) val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars)
if (!javaFacade.hasTopLevelClassOf(classId)) return@mapNotNull null if (!javaFacade.hasTopLevelClassOf(classId)) return@mapNotNull null
val (kotlinJvmBinaryClass, byteContent) = val jvmMetadataVersion = session.languageVersionSettings.languageVersion.toMetadataVersion()
kotlinClassFinder.findKotlinClassOrContent(classId) as? KotlinClassFinder.Result.KotlinClass ?: return@mapNotNull null val (kotlinJvmBinaryClass, byteContent) = kotlinClassFinder.findKotlinClassOrContent(
classId, jvmMetadataVersion
) as? KotlinClassFinder.Result.KotlinClass ?: return@mapNotNull null
val facadeName = kotlinJvmBinaryClass.classHeader.multifileClassName?.takeIf { it.isNotEmpty() } val facadeName = kotlinJvmBinaryClass.classHeader.multifileClassName?.takeIf { it.isNotEmpty() }
val facadeFqName = facadeName?.let { JvmClassName.byInternalName(it).fqNameForTopLevelClassMaybeWithDollars } val facadeFqName = facadeName?.let { JvmClassName.byInternalName(it).fqNameForTopLevelClassMaybeWithDollars }
val facadeBinaryClass = facadeFqName?.let { kotlinClassFinder.findKotlinClass(ClassId.topLevel(it)) } val facadeBinaryClass = facadeFqName?.let {
kotlinClassFinder.findKotlinClass(ClassId.topLevel(it), jvmMetadataVersion)
}
val moduleData = moduleDataProvider.getModuleData(kotlinJvmBinaryClass.containingLibrary.toPath()) ?: return@mapNotNull null val moduleData = moduleDataProvider.getModuleData(kotlinJvmBinaryClass.containingLibrary.toPath()) ?: return@mapNotNull null
@@ -94,8 +100,11 @@ class JvmClassFileBasedSymbolProvider(
private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>?
get() { get() {
// TODO: skipMetadataVersionCheck // TODO: skipMetadataVersionCheck
if (classHeader.metadataVersion.isCompatible()) return null val expectedMetadataVersion = session.languageVersionSettings.languageVersion.toMetadataVersion()
return IncompatibleVersionErrorData(classHeader.metadataVersion, JvmMetadataVersion.INSTANCE, location, classId) if (classHeader.metadataVersion.isCompatible(expectedMetadataVersion)) return null
return IncompatibleVersionErrorData(
classHeader.metadataVersion, maxOf(expectedMetadataVersion, JvmMetadataVersion.INSTANCE.next()), location, classId
)
} }
private val KotlinJvmBinaryClass.isPreReleaseInvisible: Boolean private val KotlinJvmBinaryClass.isPreReleaseInvisible: Boolean
@@ -105,7 +114,9 @@ class JvmClassFileBasedSymbolProvider(
// Kotlin classes are annotated Java classes, so this check also looks for them. // Kotlin classes are annotated Java classes, so this check also looks for them.
if (!javaFacade.hasTopLevelClassOf(classId)) return null if (!javaFacade.hasTopLevelClassOf(classId)) return null
val result = kotlinClassFinder.findKotlinClassOrContent(classId) val result = kotlinClassFinder.findKotlinClassOrContent(
classId, session.languageVersionSettings.languageVersion.toMetadataVersion()
)
if (result !is KotlinClassFinder.Result.KotlinClass) { if (result !is KotlinClassFinder.Result.KotlinClass) {
if (parentContext != null || (classId.isNestedClass && getClass(classId.outermostClassId)?.fir !is FirJavaClass)) { if (parentContext != null || (classId.isNestedClass && getClass(classId.outermostClassId)?.fir !is FirJavaClass)) {
// Nested class of Kotlin class should have been a Kotlin class. // Nested class of Kotlin class should have been a Kotlin class.
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap;
import org.jetbrains.kotlin.descriptors.SourceElement; import org.jetbrains.kotlin.descriptors.SourceElement;
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor; import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor;
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion;
import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
@@ -76,6 +77,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
@Nullable @Nullable
public static <T> T create( public static <T> T create(
@NotNull byte[] fileContents, @NotNull byte[] fileContents,
@NotNull JvmMetadataVersion jvmMetadataVersionFromLanguageVersion,
@NotNull Function4<ClassId, Integer, KotlinClassHeader, InnerClassesInfo, T> factory @NotNull Function4<ClassId, Integer, KotlinClassHeader, InnerClassesInfo, T> factory
) { ) {
ReadKotlinClassHeaderAnnotationVisitor readHeaderVisitor = new ReadKotlinClassHeaderAnnotationVisitor(); ReadKotlinClassHeaderAnnotationVisitor readHeaderVisitor = new ReadKotlinClassHeaderAnnotationVisitor();
@@ -108,7 +110,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
String className = classNameRef.get(); String className = classNameRef.get();
if (className == null) return null; if (className == null) return null;
KotlinClassHeader header = readHeaderVisitor.createHeader(); KotlinClassHeader header = readHeaderVisitor.createHeader(jvmMetadataVersionFromLanguageVersion);
if (header == null) return null; if (header == null) return null;
ClassId id = resolveNameByInternalName(className, innerClasses); ClassId id = resolveNameByInternalName(className, innerClasses);
@@ -12,7 +12,7 @@ import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.util.Computable import com.intellij.openapi.util.Computable
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiJavaModule
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
@@ -59,8 +59,19 @@ class KotlinBinaryClassCache : Disposable {
} }
companion object { companion object {
@Deprecated(
"Please pass jvmMetadataVersion explicitly",
ReplaceWith(
"getKotlinBinaryClassOrClassFileContent(file, JvmMetadataVersion.INSTANCE, fileContent = fileContent)",
"org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion"
)
)
fun getKotlinBinaryClassOrClassFileContent( fun getKotlinBinaryClassOrClassFileContent(
file: VirtualFile, fileContent: ByteArray? = null file: VirtualFile, fileContent: ByteArray?
) = getKotlinBinaryClassOrClassFileContent(file, jvmMetadataVersion = JvmMetadataVersion.INSTANCE, fileContent = fileContent)
fun getKotlinBinaryClassOrClassFileContent(
file: VirtualFile, jvmMetadataVersion: JvmMetadataVersion, fileContent: ByteArray? = null
): KotlinClassFinder.Result? { ): KotlinClassFinder.Result? {
if (file.extension != JavaClassFileType.INSTANCE.defaultExtension && if (file.extension != JavaClassFileType.INSTANCE.defaultExtension &&
file.fileType !== JavaClassFileType.INSTANCE file.fileType !== JavaClassFileType.INSTANCE
@@ -76,7 +87,7 @@ class KotlinBinaryClassCache : Disposable {
} }
val aClass = ApplicationManager.getApplication().runReadAction(Computable { val aClass = ApplicationManager.getApplication().runReadAction(Computable {
VirtualFileKotlinClass.create(file, fileContent) VirtualFileKotlinClass.create(file, jvmMetadataVersion, fileContent)
}) })
return requestCache.cache(file, aClass) return requestCache.cache(file, aClass)
@@ -11,6 +11,7 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader 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.ClassId
import org.jetbrains.kotlin.util.PerformanceCounter import org.jetbrains.kotlin.util.PerformanceCounter
import java.io.FileNotFoundException import java.io.FileNotFoundException
@@ -46,14 +47,14 @@ class VirtualFileKotlinClass private constructor(
private val LOG = Logger.getInstance(VirtualFileKotlinClass::class.java) private val LOG = Logger.getInstance(VirtualFileKotlinClass::class.java)
private val perfCounter = PerformanceCounter.create("Binary class from Kotlin file") private val perfCounter = PerformanceCounter.create("Binary class from Kotlin file")
internal fun create(file: VirtualFile, fileContent: ByteArray?): KotlinClassFinder.Result? { internal fun create(file: VirtualFile, jvmMetadataVersion: JvmMetadataVersion, fileContent: ByteArray?): KotlinClassFinder.Result? {
return perfCounter.time { return perfCounter.time {
assert(file.extension == JavaClassFileType.INSTANCE.defaultExtension || file.fileType == JavaClassFileType.INSTANCE) { "Trying to read binary data from a non-class file $file" } assert(file.extension == JavaClassFileType.INSTANCE.defaultExtension || file.fileType == JavaClassFileType.INSTANCE) { "Trying to read binary data from a non-class file $file" }
try { try {
val byteContent = fileContent ?: file.contentsToByteArray(false) val byteContent = fileContent ?: file.contentsToByteArray(false)
if (byteContent.isNotEmpty()) { if (byteContent.isNotEmpty()) {
val kotlinJvmBinaryClass = create(byteContent) { name, classVersion, header, innerClasses -> val kotlinJvmBinaryClass = create(byteContent, jvmMetadataVersion) { name, classVersion, header, innerClasses ->
VirtualFileKotlinClass(file, name, classVersion, header, innerClasses) VirtualFileKotlinClass(file, name, classVersion, header, innerClasses)
} }
@@ -21,9 +21,9 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.sure
@@ -32,12 +32,12 @@ abstract class VirtualFileFinder : KotlinClassFinder {
abstract fun findSourceOrBinaryVirtualFile(classId: ClassId): VirtualFile? abstract fun findSourceOrBinaryVirtualFile(classId: ClassId): VirtualFile?
override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? { override fun findKotlinClassOrContent(classId: ClassId, jvmMetadataVersion: JvmMetadataVersion): KotlinClassFinder.Result? {
val file = findVirtualFileWithHeader(classId) ?: return null val file = findVirtualFileWithHeader(classId) ?: return null
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file) return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file, jvmMetadataVersion)
} }
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? { override fun findKotlinClassOrContent(javaClass: JavaClass, jvmMetadataVersion: JvmMetadataVersion): KotlinClassFinder.Result? {
var file = (javaClass as? VirtualFileBoundJavaClass)?.virtualFile ?: return null var file = (javaClass as? VirtualFileBoundJavaClass)?.virtualFile ?: return null
if (javaClass.outerClass != null) { if (javaClass.outerClass != null) {
@@ -46,7 +46,7 @@ abstract class VirtualFileFinder : KotlinClassFinder {
file = file.parent!!.findChild(classFileName(javaClass) + ".class").sure { "Virtual file not found for $javaClass" } file = file.parent!!.findChild(classFileName(javaClass) + ".class").sure { "Virtual file not found for $javaClass" }
} }
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file) return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file, jvmMetadataVersion)
} }
private fun classFileName(jClass: JavaClass): String { private fun classFileName(jClass: JavaClass): String {
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.serialization.deserialization.DeserializationCompone
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
class IncrementalPackageFragmentProvider( class IncrementalPackageFragmentProvider(
@@ -94,7 +95,10 @@ class IncrementalPackageFragmentProvider(
val partName = JvmClassName.byInternalName(internalName) val partName = JvmClassName.byInternalName(internalName)
val jvmBinaryClass = val jvmBinaryClass =
kotlinClassFinder.findKotlinClass(ClassId.topLevel(partName.fqNameForTopLevelClassMaybeWithDollars)) kotlinClassFinder.findKotlinClass(
ClassId.topLevel(partName.fqNameForTopLevelClassMaybeWithDollars),
deserializationComponents.configuration.jvmMetadataVersionOrDefault()
)
val metadataVersion = val metadataVersion =
jvmBinaryClass?.classHeader?.metadataVersion jvmBinaryClass?.classHeader?.metadataVersion
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2022 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.resolve.jvm
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.utils.toMetadataVersion
class JvmCompilerDeserializationConfiguration(
languageVersionSettings: LanguageVersionSettings
) : CompilerDeserializationConfiguration(languageVersionSettings) {
override val binaryVersion: JvmMetadataVersion
get() = languageVersionSettings.languageVersion.toMetadataVersion()
}
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
import org.jetbrains.kotlin.resolve.sam.SamConversionResolver import org.jetbrains.kotlin.resolve.sam.SamConversionResolver
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -49,7 +49,7 @@ class OptionalAnnotationPackageFragmentProvider(
val classDataFinder = OptionalAnnotationClassDataFinder(optionalAnnotationClasses) val classDataFinder = OptionalAnnotationClassDataFinder(optionalAnnotationClasses)
val components = storageManager.createLazyValue { val components = storageManager.createLazyValue {
DeserializationComponents( DeserializationComponents(
storageManager, module, CompilerDeserializationConfiguration(languageVersionSettings), storageManager, module, JvmCompilerDeserializationConfiguration(languageVersionSettings),
classDataFinder, classDataFinder,
AnnotationAndConstantLoaderImpl(module, notFoundClasses, serializerProtocol), AnnotationAndConstantLoaderImpl(module, notFoundClasses, serializerProtocol),
this, this,
@@ -5,24 +5,26 @@
package org.jetbrains.kotlin.resolve package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
class CompilerDeserializationConfiguration(languageVersionSettings: LanguageVersionSettings) : DeserializationConfiguration { open class CompilerDeserializationConfiguration(
override val skipMetadataVersionCheck = languageVersionSettings.getFlag(AnalysisFlags.skipMetadataVersionCheck) protected val languageVersionSettings: LanguageVersionSettings
) : DeserializationConfiguration {
override val skipPrereleaseCheck = languageVersionSettings.getFlag(AnalysisFlags.skipPrereleaseCheck) final override val skipMetadataVersionCheck = languageVersionSettings.getFlag(AnalysisFlags.skipMetadataVersionCheck)
override val reportErrorsOnPreReleaseDependencies = final override val skipPrereleaseCheck = languageVersionSettings.getFlag(AnalysisFlags.skipPrereleaseCheck)
final override val reportErrorsOnPreReleaseDependencies =
!skipPrereleaseCheck && !languageVersionSettings.isPreRelease() !skipPrereleaseCheck && !languageVersionSettings.isPreRelease()
override val allowUnstableDependencies = languageVersionSettings.getFlag(AnalysisFlags.allowUnstableDependencies) final override val allowUnstableDependencies = languageVersionSettings.getFlag(AnalysisFlags.allowUnstableDependencies)
override val typeAliasesAllowed = languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases) final override val typeAliasesAllowed = languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases)
override val isJvmPackageNameSupported = languageVersionSettings.supportsFeature(LanguageFeature.JvmPackageName) final override val isJvmPackageNameSupported = languageVersionSettings.supportsFeature(LanguageFeature.JvmPackageName)
override val readDeserializedContracts: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.ReadDeserializedContracts) final override val readDeserializedContracts: Boolean =
languageVersionSettings.supportsFeature(LanguageFeature.ReadDeserializedContracts)
} }
@@ -32,8 +32,8 @@ import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.compilerRunner.MessageCollectorToOutputItemsCollectorAdapter import org.jetbrains.kotlin.compilerRunner.MessageCollectorToOutputItemsCollectorAdapter
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.compilerRunner.SimpleOutputItem
import org.jetbrains.kotlin.compilerRunner.toGeneratedFile import org.jetbrains.kotlin.compilerRunner.toGeneratedFile
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
@@ -41,9 +41,11 @@ import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector
import org.jetbrains.kotlin.incremental.util.ExceptionLocation import org.jetbrains.kotlin.incremental.util.ExceptionLocation
import org.jetbrains.kotlin.incremental.util.reportException import org.jetbrains.kotlin.incremental.util.reportException
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import org.jetbrains.kotlin.util.removeSuffixIfPresent import org.jetbrains.kotlin.util.removeSuffixIfPresent
import org.jetbrains.kotlin.utils.toMetadataVersion
import java.io.File import java.io.File
abstract class IncrementalCompilerRunner< abstract class IncrementalCompilerRunner<
@@ -411,6 +413,10 @@ abstract class IncrementalCompilerRunner<
var exitCode = ExitCode.OK var exitCode = ExitCode.OK
// TODO: ideally we should read arguments not here but at earlier stages
val jvmMetadataVersionFromLanguageVersion =
LanguageVersion.fromVersionString(args.languageVersion)?.toMetadataVersion() ?: JvmMetadataVersion.INSTANCE
while (dirtySources.any() || runWithNoDirtyKotlinSources(caches)) { while (dirtySources.any() || runWithNoDirtyKotlinSources(caches)) {
val complementaryFiles = caches.platformCache.getComplementaryFilesRecursive(dirtySources) val complementaryFiles = caches.platformCache.getComplementaryFilesRecursive(dirtySources)
dirtySources.addAll(complementaryFiles) dirtySources.addAll(complementaryFiles)
@@ -447,8 +453,9 @@ abstract class IncrementalCompilerRunner<
val text = allDirtySources.joinToString(separator = System.getProperty("line.separator")) { it.normalize().absolutePath } val text = allDirtySources.joinToString(separator = System.getProperty("line.separator")) { it.normalize().absolutePath }
dirtySourcesSinceLastTimeFile.writeText(text) dirtySourcesSinceLastTimeFile.writeText(text)
val generatedFiles = outputItemsCollector.outputs.map {
val generatedFiles = outputItemsCollector.outputs.map(SimpleOutputItem::toGeneratedFile) it.toGeneratedFile(jvmMetadataVersionFromLanguageVersion)
}
if (compilationMode is CompilationMode.Incremental) { if (compilationMode is CompilationMode.Incremental) {
// todo: feels dirty, can this be refactored? // todo: feels dirty, can this be refactored?
val dirtySourcesSet = dirtySources.toHashSet() val dirtySourcesSet = dirtySources.toHashSet()
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.IncrementalCompilation import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled
import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.IncrementalRun.NoChanges import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotEnabled.IncrementalRun.NoChanges
@@ -85,8 +86,9 @@ fun makeIncrementally(
val buildReporter = BuildReporter(icReporter = reporter, buildMetricsReporter = DoNothingBuildMetricsReporter) val buildReporter = BuildReporter(icReporter = reporter, buildMetricsReporter = DoNothingBuildMetricsReporter)
withIC(args) { withIC(args) {
val useK2 = args.useK2 || LanguageVersion.fromVersionString(args.languageVersion)?.usesK2 == true
val compiler = val compiler =
if (args.useK2 && args.useFirIC && args.useFirLT /* TODO: move LT check into runner */ ) if (useK2 && args.useFirIC && args.useFirLT /* TODO: move LT check into runner */)
IncrementalFirJvmCompilerRunner( IncrementalFirJvmCompilerRunner(
cachesDir, cachesDir,
buildReporter, buildReporter,
@@ -101,7 +103,7 @@ fun makeIncrementally(
cachesDir, cachesDir,
buildReporter, buildReporter,
// Use precise setting in case of non-Gradle build // Use precise setting in case of non-Gradle build
usePreciseJavaTracking = !args.useK2, // TODO: add fir-based java classes tracker when available and set this to true usePreciseJavaTracking = !useK2, // TODO: add fir-based java classes tracker when available and set this to true
buildHistoryFile = buildHistoryFile, buildHistoryFile = buildHistoryFile,
outputDirs = null, outputDirs = null,
modulesApiHistory = EmptyModulesApiHistory, modulesApiHistory = EmptyModulesApiHistory,
@@ -107,5 +107,5 @@ private class KotlinClassHeaderClassVisitor : ClassVisitor(Opcodes.API_VERSION)
) )
} }
fun getKotlinClassHeader(): KotlinClassHeader? = kotlinClassHeaderAnnotationVisitor.createHeader() fun getKotlinClassHeader(): KotlinClassHeader? = kotlinClassHeaderAnnotationVisitor.createHeaderWithDefaultMetadataVersion()
} }
@@ -13,6 +13,7 @@ abstract class AbstractIncrementalFirICLightTreeJvmCompilerRunnerTest : Abstract
override fun createCompilerArguments(destinationDir: File, testDir: File): K2JVMCompilerArguments = override fun createCompilerArguments(destinationDir: File, testDir: File): K2JVMCompilerArguments =
super.createCompilerArguments(destinationDir, testDir).apply { super.createCompilerArguments(destinationDir, testDir).apply {
useK2 = true useK2 = true
languageVersion = "2.0"
useIR = true useIR = true
useFirIC = true useFirIC = true
useFirLT = true useFirLT = true
@@ -24,6 +24,7 @@ abstract class AbstractIncrementalFirJvmCompilerRunnerTest : AbstractIncremental
override fun createCompilerArguments(destinationDir: File, testDir: File): K2JVMCompilerArguments = override fun createCompilerArguments(destinationDir: File, testDir: File): K2JVMCompilerArguments =
super.createCompilerArguments(destinationDir, testDir).apply { super.createCompilerArguments(destinationDir, testDir).apply {
useK2 = true useK2 = true
languageVersion = "2.0"
useIR = true useIR = true
} }
@@ -13,6 +13,7 @@ abstract class AbstractIncrementalFirLightTreeJvmCompilerRunnerTest : AbstractIn
override fun createCompilerArguments(destinationDir: File, testDir: File): K2JVMCompilerArguments = override fun createCompilerArguments(destinationDir: File, testDir: File): K2JVMCompilerArguments =
super.createCompilerArguments(destinationDir, testDir).apply { super.createCompilerArguments(destinationDir, testDir).apply {
useK2 = true useK2 = true
languageVersion = "2.0"
useIR = true useIR = true
useFirIC = false useFirIC = false
useFirLT = true useFirLT = true
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMemberSignature import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMemberSignature
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.tree.MethodNode import org.jetbrains.org.objectweb.asm.tree.MethodNode
@@ -213,7 +214,9 @@ object InlineTestUtil {
} }
private fun loadBinaryClass(file: OutputFile): KotlinJvmBinaryClass = private fun loadBinaryClass(file: OutputFile): KotlinJvmBinaryClass =
FileBasedKotlinClass.create<FileBasedKotlinClass>(file.asByteArray()) { className, classVersion, classHeader, innerClasses -> FileBasedKotlinClass.create<FileBasedKotlinClass>(
file.asByteArray(), JvmMetadataVersion.INSTANCE
) { className, classVersion, classHeader, innerClasses ->
object : FileBasedKotlinClass(className, classVersion, classHeader, innerClasses) { object : FileBasedKotlinClass(className, classVersion, classHeader, innerClasses) {
override val location: String override val location: String
get() = throw UnsupportedOperationException() get() = throw UnsupportedOperationException()
@@ -0,0 +1,5 @@
package lib
class Box(val value: String)
inline fun <T> get(block: () -> T): T = block()
@@ -0,0 +1,2 @@
warning: compiler flag -Xuse-k2 is deprecated, please use -language-version 2.0 instead
OK
@@ -0,0 +1,5 @@
import lib.*
fun main() {
get { Box("OK").value }
}
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.load.kotlin.loadModuleMapping import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
import org.jetbrains.kotlin.test.CompilerTestUtil import org.jetbrains.kotlin.test.CompilerTestUtil
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
@@ -51,7 +51,7 @@ class JvmModuleProtoBufTest : KtUsefulTestCase() {
val mapping = ModuleMapping.loadModuleMapping( val mapping = ModuleMapping.loadModuleMapping(
File(tmpdir, "META-INF/$moduleName.${ModuleMapping.MAPPING_FILE_EXT}").readBytes(), "test", File(tmpdir, "META-INF/$moduleName.${ModuleMapping.MAPPING_FILE_EXT}").readBytes(), "test",
CompilerDeserializationConfiguration(LanguageVersionSettingsImpl(loadWith, ApiVersion.createByLanguageVersion(loadWith))), JvmCompilerDeserializationConfiguration(LanguageVersionSettingsImpl(loadWith, ApiVersion.createByLanguageVersion(loadWith))),
::error ::error
) )
val result = buildString { val result = buildString {
@@ -143,7 +143,7 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
int[] version = (int[]) CodegenTestUtil.getAnnotationAttribute(annotation, METADATA_VERSION_FIELD_NAME); int[] version = (int[]) CodegenTestUtil.getAnnotationAttribute(annotation, METADATA_VERSION_FIELD_NAME);
assertNotNull(version); assertNotNull(version);
assertTrue("Annotation " + annotationFqName + " is written with an unsupported format", assertTrue("Annotation " + annotationFqName + " is written with an unsupported format",
new JvmMetadataVersion(version).isCompatible()); new JvmMetadataVersion(version).isCompatibleWithCurrentCompilerVersion());
} }
@NotNull @NotNull
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.MockLibraryUtil import org.jetbrains.kotlin.test.MockLibraryUtil
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparatorAdaptor.validateAndCompareDescriptorWithFile import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparatorAdaptor.validateAndCompareDescriptorWithFile
import org.jetbrains.kotlin.utils.toMetadataVersion
import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.tree.ClassNode import org.jetbrains.org.objectweb.asm.tree.ClassNode
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@@ -388,7 +389,7 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
} }
fun testStrictMetadataVersionSemanticsOldVersion() { fun testStrictMetadataVersionSemanticsOldVersion() {
val nextMetadataVersion = JvmMetadataVersion(JvmMetadataVersion.INSTANCE.major, JvmMetadataVersion.INSTANCE.minor + 1, 0) val nextMetadataVersion = JvmMetadataVersion.INSTANCE.next()
val library = compileLibrary( val library = compileLibrary(
"library", additionalOptions = listOf("-Xgenerate-strict-metadata-version", "-Xmetadata-version=$nextMetadataVersion") "library", additionalOptions = listOf("-Xgenerate-strict-metadata-version", "-Xmetadata-version=$nextMetadataVersion")
) )
@@ -409,7 +410,7 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
val expectedMajor = if (languageVersion.usesK2) 2 else 1 val expectedMajor = if (languageVersion.usesK2) 2 else 1
val expectedMinor = if (languageVersion < LanguageVersion.KOTLIN_1_4) 1 else languageVersion.minor val expectedMinor = if (languageVersion < LanguageVersion.KOTLIN_1_4) 1 else languageVersion.minor
val topLevelClass = LocalFileKotlinClass.create(File(tmpdir.absolutePath, "Foo.class"))!! val topLevelClass = LocalFileKotlinClass.create(File(tmpdir.absolutePath, "Foo.class"), languageVersion.toMetadataVersion())!!
val classVersion = topLevelClass.classHeader.metadataVersion val classVersion = topLevelClass.classHeader.metadataVersion
assertEquals("Actual version: $classVersion", expectedMajor, classVersion.major) assertEquals("Actual version: $classVersion", expectedMajor, classVersion.major)
assertEquals("Actual version: $classVersion", expectedMinor, classVersion.minor) assertEquals("Actual version: $classVersion", expectedMinor, classVersion.minor)
@@ -641,6 +642,11 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
} }
} }
fun testFirAgainstFirUsingFlag() {
val library = compileLibrary("library", additionalOptions = listOf("-language-version", "2.0"))
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xuse-k2"))
}
fun testFirAgainstFir() { fun testFirAgainstFir() {
val library = compileLibrary("library", additionalOptions = listOf("-language-version", "2.0")) val library = compileLibrary("library", additionalOptions = listOf("-language-version", "2.0"))
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-language-version", "2.0")) compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-language-version", "2.0"))
@@ -691,6 +697,8 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
} }
fun testOldJvmAgainstFirWithStableAbi() { fun testOldJvmAgainstFirWithStableAbi() {
// TODO: looks like now it's not possible to compile library with version 2.0 to be able to compile against it without additional flags
// Should we delete this test?
val library = compileLibrary("library", additionalOptions = listOf("-language-version", "2.0", "-Xabi-stability=stable")) val library = compileLibrary("library", additionalOptions = listOf("-language-version", "2.0", "-Xabi-stability=stable"))
compileKotlin("source.kt", tmpdir, listOf(library)) compileKotlin("source.kt", tmpdir, listOf(library))
} }
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.load.kotlin.findKotlinClass import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -49,7 +50,7 @@ class KotlinClassFinderTest : KotlinTestWithEnvironmentManagement() {
fun testNestedClass() { fun testNestedClass() {
val tmpdir = KotlinTestUtils.tmpDirForTest(this) val tmpdir = KotlinTestUtils.tmpDirForTest(this)
KotlinTestUtils.compileKotlinWithJava( KotlinTestUtils.compileKotlinWithJava(
listOf(), listOf(File("compiler/testData/kotlinClassFinder/nestedClass.kt")), tmpdir, testRootDisposable, null listOf(), listOf(File("compiler/testData/kotlinClassFinder/nestedClass.kt")), tmpdir, testRootDisposable, null
) )
val environment = createEnvironment(tmpdir) val environment = createEnvironment(tmpdir)
@@ -60,7 +61,9 @@ class KotlinClassFinderTest : KotlinTestWithEnvironmentManagement() {
assertNotNull(psiClass, "Psi class not found for $className") assertNotNull(psiClass, "Psi class not found for $className")
assertTrue(psiClass !is KtLightClass, "Kotlin light classes are not not expected") assertTrue(psiClass !is KtLightClass, "Kotlin light classes are not not expected")
val binaryClass = VirtualFileFinder.SERVICE.getInstance(project).findKotlinClass(JavaClassImpl(psiClass)) val binaryClass = VirtualFileFinder.SERVICE.getInstance(project).findKotlinClass(
JavaClassImpl(psiClass), JvmMetadataVersion.INSTANCE
)
assertNotNull(binaryClass, "No binary class for $className") assertNotNull(binaryClass, "No binary class for $className")
assertEquals("test/A.B.C", binaryClass.classId.toString()) assertEquals("test/A.B.C", binaryClass.classId.toString())
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.javac.components.JavacBasedClassFinder import org.jetbrains.kotlin.javac.components.JavacBasedClassFinder
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.load.kotlin.findKotlinClass import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
@@ -66,7 +67,7 @@ class KotlinJavacBasedClassFinderTest : KotlinTestWithEnvironmentManagement() {
val found = classFinder.findClass(classId) val found = classFinder.findClass(classId)
assertNotNull(found, "Class not found for $className") assertNotNull(found, "Class not found for $className")
val binaryClass = VirtualFileFinder.SERVICE.getInstance(project).findKotlinClass(found) val binaryClass = VirtualFileFinder.SERVICE.getInstance(project).findKotlinClass(found, JvmMetadataVersion.INSTANCE)
assertNotNull(binaryClass, "No binary class for $className") assertNotNull(binaryClass, "No binary class for $className")
assertEquals("test/A.B.C", binaryClass.classId.toString()) assertEquals("test/A.B.C", binaryClass.classId.toString())
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
class LazyJavaPackageFragment( class LazyJavaPackageFragment(
outerContext: LazyJavaResolverContext, outerContext: LazyJavaResolverContext,
@@ -39,10 +40,13 @@ class LazyJavaPackageFragment(
) : PackageFragmentDescriptorImpl(outerContext.module, jPackage.fqName) { ) : PackageFragmentDescriptorImpl(outerContext.module, jPackage.fqName) {
private val c = outerContext.childForClassOrPackage(this) private val c = outerContext.childForClassOrPackage(this)
private val jvmMetadataVersion =
outerContext.components.deserializedDescriptorResolver.components.configuration.jvmMetadataVersionOrDefault()
internal val binaryClasses by c.storageManager.createLazyValue { internal val binaryClasses by c.storageManager.createLazyValue {
c.components.packagePartProvider.findPackageParts(fqName.asString()).mapNotNull { partName -> c.components.packagePartProvider.findPackageParts(fqName.asString()).mapNotNull { partName ->
val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars) val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars)
c.components.kotlinClassFinder.findKotlinClass(classId)?.let { partName to it } c.components.kotlinClassFinder.findKotlinClass(classId, jvmMetadataVersion)?.let { partName to it }
}.toMap() }.toMap()
} }
@@ -30,12 +30,14 @@ import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.findKotlinClass import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader 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.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.storage.NullableLazyValue import org.jetbrains.kotlin.storage.NullableLazyValue
import org.jetbrains.kotlin.utils.alwaysTrue import org.jetbrains.kotlin.utils.alwaysTrue
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
import java.util.* import java.util.*
class LazyJavaPackageScope( class LazyJavaPackageScope(
@@ -49,6 +51,10 @@ class LazyJavaPackageScope(
c.components.finder.knownClassNamesInPackage(ownerDescriptor.fqName) c.components.finder.knownClassNamesInPackage(ownerDescriptor.fqName)
} }
private val jvmMetadataVersion: JvmMetadataVersion
get() = c.components.deserializedDescriptorResolver.components.configuration.jvmMetadataVersionOrDefault()
private val classes = private val classes =
c.storageManager.createMemoizedFunctionWithNullableValues<FindClassRequest, ClassDescriptor> classByRequest@{ request -> c.storageManager.createMemoizedFunctionWithNullableValues<FindClassRequest, ClassDescriptor> classByRequest@{ request ->
val requestClassId = ClassId(ownerDescriptor.fqName, request.name) val requestClassId = ClassId(ownerDescriptor.fqName, request.name)
@@ -56,9 +62,9 @@ class LazyJavaPackageScope(
val kotlinClassOrClassFileContent = val kotlinClassOrClassFileContent =
// These branches should be semantically equal, but the first one could be faster // These branches should be semantically equal, but the first one could be faster
if (request.javaClass != null) if (request.javaClass != null)
c.components.kotlinClassFinder.findKotlinClassOrContent(request.javaClass) c.components.kotlinClassFinder.findKotlinClassOrContent(request.javaClass, jvmMetadataVersion)
else else
c.components.kotlinClassFinder.findKotlinClassOrContent(requestClassId) c.components.kotlinClassFinder.findKotlinClassOrContent(requestClassId, jvmMetadataVersion)
val kotlinBinaryClass = kotlinClassOrClassFileContent?.toKotlinJvmBinaryClass() val kotlinBinaryClass = kotlinClassOrClassFileContent?.toKotlinJvmBinaryClass()
@@ -84,8 +90,8 @@ class LazyJavaPackageScope(
"Couldn't find kotlin binary class for light class created by kotlin binary file\n" + "Couldn't find kotlin binary class for light class created by kotlin binary file\n" +
"JavaClass: $javaClass\n" + "JavaClass: $javaClass\n" +
"ClassId: $requestClassId\n" + "ClassId: $requestClassId\n" +
"findKotlinClass(JavaClass) = ${c.components.kotlinClassFinder.findKotlinClass(javaClass)}\n" + "findKotlinClass(JavaClass) = ${c.components.kotlinClassFinder.findKotlinClass(javaClass, jvmMetadataVersion)}\n" +
"findKotlinClass(ClassId) = ${c.components.kotlinClassFinder.findKotlinClass(requestClassId)}\n" "findKotlinClass(ClassId) = ${c.components.kotlinClassFinder.findKotlinClass(requestClassId, jvmMetadataVersion)}\n"
) )
} }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -33,6 +34,8 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
) { ) {
private val annotationDeserializer = AnnotationDeserializer(module, notFoundClasses) private val annotationDeserializer = AnnotationDeserializer(module, notFoundClasses)
override var jvmMetadataVersion: JvmMetadataVersion = JvmMetadataVersion.INSTANCE
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationDescriptor = override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationDescriptor =
annotationDeserializer.deserializeAnnotation(proto, nameResolver) annotationDeserializer.deserializeAnnotation(proto, nameResolver)
@@ -224,3 +227,18 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses) return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses)
} }
} }
// Note: this function is needed because we cannot pass JvmMetadataVersion
// directly to the BinaryClassAnnotationAndConstantLoaderImpl constructor.
// This constructor is used by dependency injection.
fun createBinaryClassAnnotationAndConstantLoader(
module: ModuleDescriptor,
notFoundClasses: NotFoundClasses,
storageManager: StorageManager,
kotlinClassFinder: KotlinClassFinder,
jvmMetadataVersion: JvmMetadataVersion
): BinaryClassAnnotationAndConstantLoaderImpl = BinaryClassAnnotationAndConstantLoaderImpl(
module, notFoundClasses, storageManager, kotlinClassFinder
).apply {
this.jvmMetadataVersion = jvmMetadataVersion
}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeEnhancement import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeEnhancement
import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -122,7 +123,7 @@ class DeserializationComponentsForJava(
val deserializationComponentsForJava = val deserializationComponentsForJava =
makeDeserializationComponentsForJava( makeDeserializationComponentsForJava(
module, storageManager, notFoundClasses, lazyJavaPackageFragmentProvider, module, storageManager, notFoundClasses, lazyJavaPackageFragmentProvider,
kotlinClassFinder, deserializedDescriptorResolver, errorReporter kotlinClassFinder, deserializedDescriptorResolver, errorReporter, JvmMetadataVersion.INSTANCE
) )
deserializedDescriptorResolver.setComponents(deserializationComponentsForJava) deserializedDescriptorResolver.setComponents(deserializationComponentsForJava)
@@ -183,11 +184,12 @@ fun makeDeserializationComponentsForJava(
lazyJavaPackageFragmentProvider: LazyJavaPackageFragmentProvider, lazyJavaPackageFragmentProvider: LazyJavaPackageFragmentProvider,
reflectKotlinClassFinder: KotlinClassFinder, reflectKotlinClassFinder: KotlinClassFinder,
deserializedDescriptorResolver: DeserializedDescriptorResolver, deserializedDescriptorResolver: DeserializedDescriptorResolver,
errorReporter: ErrorReporter errorReporter: ErrorReporter,
jvmMetadataVersion: JvmMetadataVersion
): DeserializationComponentsForJava { ): DeserializationComponentsForJava {
val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver) val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver)
val binaryClassAnnotationAndConstantLoader = BinaryClassAnnotationAndConstantLoaderImpl( val binaryClassAnnotationAndConstantLoader = createBinaryClassAnnotationAndConstantLoader(
module, notFoundClasses, storageManager, reflectKotlinClassFinder module, notFoundClasses, storageManager, reflectKotlinClassFinder, jvmMetadataVersion
) )
return DeserializationComponentsForJava( return DeserializationComponentsForJava(
storageManager, module, DeserializationConfiguration.Default, javaClassDataFinder, storageManager, module, DeserializationConfiguration.Default, javaClassDataFinder,
@@ -28,11 +28,14 @@ import org.jetbrains.kotlin.serialization.deserialization.DeserializationCompone
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
import javax.inject.Inject import javax.inject.Inject
class DeserializedDescriptorResolver { class DeserializedDescriptorResolver {
lateinit var components: DeserializationComponents lateinit var components: DeserializationComponents
private val ownMetadataVersion: JvmMetadataVersion get() = components.configuration.jvmMetadataVersionOrDefault()
// component dependency cycle // component dependency cycle
@Inject @Inject
fun setComponents(components: DeserializationComponentsForJava) { fun setComponents(components: DeserializationComponentsForJava) {
@@ -80,8 +83,10 @@ class DeserializedDescriptorResolver {
private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>?
get() { get() {
if (skipMetadataVersionCheck || classHeader.metadataVersion.isCompatible()) return null if (skipMetadataVersionCheck || classHeader.metadataVersion.isCompatible(ownMetadataVersion)) return null
return IncompatibleVersionErrorData(classHeader.metadataVersion, JvmMetadataVersion.INSTANCE, location, classId) return IncompatibleVersionErrorData(
classHeader.metadataVersion, maxOf(ownMetadataVersion.prev(), JvmMetadataVersion.INSTANCE), location, classId
)
} }
/** /**
@@ -120,7 +125,7 @@ class DeserializedDescriptorResolver {
throw IllegalStateException("Could not read data from ${klass.location}", e) throw IllegalStateException("Could not read data from ${klass.location}", e)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
if (skipMetadataVersionCheck || klass.classHeader.metadataVersion.isCompatible()) { if (skipMetadataVersionCheck || klass.classHeader.metadataVersion.isCompatible(ownMetadataVersion)) {
throw e throw e
} }
@@ -19,13 +19,16 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData import org.jetbrains.kotlin.serialization.deserialization.ClassData
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
class JavaClassDataFinder( class JavaClassDataFinder(
internal val kotlinClassFinder: KotlinClassFinder, internal val kotlinClassFinder: KotlinClassFinder,
private val deserializedDescriptorResolver: DeserializedDescriptorResolver private val deserializedDescriptorResolver: DeserializedDescriptorResolver
) : ClassDataFinder { ) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassData? { override fun findClassData(classId: ClassId): ClassData? {
val kotlinClass = kotlinClassFinder.findKotlinClass(classId) ?: return null val kotlinClass = kotlinClassFinder.findKotlinClass(
classId, deserializedDescriptorResolver.components.configuration.jvmMetadataVersionOrDefault()
) ?: return null
assert(kotlinClass.classId == classId) { assert(kotlinClass.classId == classId) {
"Class with incorrect id found: expected $classId, actual ${kotlinClass.classId}" "Class with incorrect id found: expected $classId, actual ${kotlinClass.classId}"
} }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
fun ModuleMapping.Companion.loadModuleMapping( fun ModuleMapping.Companion.loadModuleMapping(
bytes: ByteArray?, bytes: ByteArray?,
@@ -20,5 +21,6 @@ fun ModuleMapping.Companion.loadModuleMapping(
debugName, debugName,
configuration.skipMetadataVersionCheck, configuration.skipMetadataVersionCheck,
configuration.isJvmPackageNameSupported, configuration.isJvmPackageNameSupported,
configuration.jvmMetadataVersionOrDefault(),
reportIncompatibleVersionError reportIncompatibleVersionError
) )
@@ -61,7 +61,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
private String[] serializedIrFields = null; private String[] serializedIrFields = null;
@Nullable @Nullable
public KotlinClassHeader createHeader() { public KotlinClassHeader createHeaderWithDefaultMetadataVersion() {
return createHeader(JvmMetadataVersion.INSTANCE);
}
@Nullable
public KotlinClassHeader createHeader(JvmMetadataVersion metadataVersionFromLanguageVersion) {
if (headerKind == null || metadataVersionArray == null) { if (headerKind == null || metadataVersionArray == null) {
return null; return null;
} }
@@ -69,7 +74,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
JvmMetadataVersion metadataVersion = JvmMetadataVersion metadataVersion =
new JvmMetadataVersion(metadataVersionArray, (extraInt & JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0); new JvmMetadataVersion(metadataVersionArray, (extraInt & JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0);
if (!metadataVersion.isCompatible()) { if (!metadataVersion.isCompatible(metadataVersionFromLanguageVersion)) {
incompatibleData = data; incompatibleData = data;
data = null; data = null;
} }
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2022 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.utils
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
fun DeserializationConfiguration.jvmMetadataVersionOrDefault(): JvmMetadataVersion =
binaryVersion as? JvmMetadataVersion ?: JvmMetadataVersion.INSTANCE
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.scopes.ChainedMemberScope import org.jetbrains.kotlin.resolve.scopes.ChainedMemberScope
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
class PackagePartScopeCache(private val resolver: DeserializedDescriptorResolver, private val kotlinClassFinder: ReflectKotlinClassFinder) { class PackagePartScopeCache(private val resolver: DeserializedDescriptorResolver, private val kotlinClassFinder: ReflectKotlinClassFinder) {
@@ -25,7 +26,7 @@ class PackagePartScopeCache(private val resolver: DeserializedDescriptorResolver
if (fileClass.classHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) if (fileClass.classHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS)
fileClass.classHeader.multifilePartNames.mapNotNull { partName -> fileClass.classHeader.multifilePartNames.mapNotNull { partName ->
val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars) val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars)
kotlinClassFinder.findKotlinClass(classId) kotlinClassFinder.findKotlinClass(classId, resolver.components.configuration.jvmMetadataVersionOrDefault())
} }
else listOf(fileClass) else listOf(fileClass)
@@ -54,7 +54,7 @@ class ReflectKotlinClass private constructor(
fun create(klass: Class<*>): ReflectKotlinClass? { fun create(klass: Class<*>): ReflectKotlinClass? {
val headerReader = ReadKotlinClassHeaderAnnotationVisitor() val headerReader = ReadKotlinClassHeaderAnnotationVisitor()
ReflectClassStructure.loadClassAnnotations(klass, headerReader) ReflectClassStructure.loadClassAnnotations(klass, headerReader)
return ReflectKotlinClass(klass, headerReader.createHeader() ?: return null) return ReflectKotlinClass(klass, headerReader.createHeaderWithDefaultMetadataVersion() ?: return null)
} }
} }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass 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.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
@@ -33,9 +34,10 @@ class ReflectKotlinClassFinder(private val classLoader: ClassLoader) : KotlinCla
return classLoader.tryLoadClass(fqName)?.let { ReflectKotlinClass.create(it) }?.let(::KotlinClass) return classLoader.tryLoadClass(fqName)?.let { ReflectKotlinClass.create(it) }?.let(::KotlinClass)
} }
override fun findKotlinClassOrContent(classId: ClassId) = findKotlinClass(classId.toRuntimeFqName()) override fun findKotlinClassOrContent(classId: ClassId, jvmMetadataVersion: JvmMetadataVersion) =
findKotlinClass(classId.toRuntimeFqName())
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? { override fun findKotlinClassOrContent(javaClass: JavaClass, jvmMetadataVersion: JvmMetadataVersion): KotlinClassFinder.Result? {
// TODO: go through javaClass's class loader // TODO: go through javaClass's class loader
return findKotlinClass(javaClass.fqName?.asString() ?: return null) return findKotlinClass(javaClass.fqName?.asString() ?: return null)
} }
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.propertySignature import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.propertySignature
import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -25,6 +26,8 @@ import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryClassAnnotationLoader.AnnotationsContainer<A>>( abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryClassAnnotationLoader.AnnotationsContainer<A>>(
protected val kotlinClassFinder: KotlinClassFinder protected val kotlinClassFinder: KotlinClassFinder
) : AnnotationLoader<A> { ) : AnnotationLoader<A> {
abstract val jvmMetadataVersion: JvmMetadataVersion
protected abstract fun getAnnotationsContainer(binaryClass: KotlinJvmBinaryClass): S protected abstract fun getAnnotationsContainer(binaryClass: KotlinJvmBinaryClass): S
protected abstract fun loadAnnotation( protected abstract fun loadAnnotation(
@@ -220,7 +223,8 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
checkNotNull(isConst) { "isConst should not be null for property (container=$container)" } checkNotNull(isConst) { "isConst should not be null for property (container=$container)" }
if (container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.INTERFACE) { if (container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.INTERFACE) {
return kotlinClassFinder.findKotlinClass( return kotlinClassFinder.findKotlinClass(
container.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)) container.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)),
jvmMetadataVersion
) )
} }
if (isConst && container is ProtoContainer.Package) { if (isConst && container is ProtoContainer.Package) {
@@ -228,7 +232,10 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
val facadeClassName = (container.source as? JvmPackagePartSource)?.facadeClassName val facadeClassName = (container.source as? JvmPackagePartSource)?.facadeClassName
if (facadeClassName != null) { if (facadeClassName != null) {
// Converting '/' to '.' is fine here because the facade class has a top level ClassId // Converting '/' to '.' is fine here because the facade class has a top level ClassId
return kotlinClassFinder.findKotlinClass(ClassId.topLevel(FqName(facadeClassName.internalName.replace('/', '.')))) return kotlinClassFinder.findKotlinClass(
ClassId.topLevel(FqName(facadeClassName.internalName.replace('/', '.'))),
jvmMetadataVersion
)
} }
} }
} }
@@ -248,7 +255,7 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
val jvmPackagePartSource = container.source as JvmPackagePartSource val jvmPackagePartSource = container.source as JvmPackagePartSource
return jvmPackagePartSource.knownJvmBinaryClass return jvmPackagePartSource.knownJvmBinaryClass
?: kotlinClassFinder.findKotlinClass(jvmPackagePartSource.classId) ?: kotlinClassFinder.findKotlinClass(jvmPackagePartSource.classId, jvmMetadataVersion)
} }
return null return null
} }
@@ -290,7 +297,7 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
classId.shortClassName.asString() != JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME classId.shortClassName.asString() != JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME
) return false ) return false
val klass = kotlinClassFinder.findKotlinClass(classId) val klass = kotlinClassFinder.findKotlinClass(classId, jvmMetadataVersion)
return klass != null && SpecialJvmAnnotations.isAnnotatedWithContainerMetaAnnotation(klass) return klass != null && SpecialJvmAnnotations.isAnnotatedWithContainerMetaAnnotation(klass)
} }
@@ -17,13 +17,14 @@
package org.jetbrains.kotlin.load.kotlin package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.KotlinMetadataFinder import org.jetbrains.kotlin.serialization.deserialization.KotlinMetadataFinder
interface KotlinClassFinder : KotlinMetadataFinder { interface KotlinClassFinder : KotlinMetadataFinder {
fun findKotlinClassOrContent(classId: ClassId): Result? fun findKotlinClassOrContent(classId: ClassId, jvmMetadataVersion: JvmMetadataVersion): Result?
fun findKotlinClassOrContent(javaClass: JavaClass): Result? fun findKotlinClassOrContent(javaClass: JavaClass, jvmMetadataVersion: JvmMetadataVersion): Result?
sealed class Result { sealed class Result {
fun toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? = (this as? KotlinClass)?.kotlinJvmBinaryClass fun toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? = (this as? KotlinClass)?.kotlinJvmBinaryClass
@@ -33,15 +34,12 @@ interface KotlinClassFinder : KotlinMetadataFinder {
operator fun component2(): ByteArray? = byteContent operator fun component2(): ByteArray? = byteContent
} }
class ClassFileContent( class ClassFileContent(val content: ByteArray) : Result()
@Suppress("ArrayInDataClass")
val content: ByteArray
) : Result()
} }
} }
fun KotlinClassFinder.findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? = fun KotlinClassFinder.findKotlinClass(classId: ClassId, jvmMetadataVersion: JvmMetadataVersion): KotlinJvmBinaryClass? =
findKotlinClassOrContent(classId)?.toKotlinJvmBinaryClass() findKotlinClassOrContent(classId, jvmMetadataVersion)?.toKotlinJvmBinaryClass()
fun KotlinClassFinder.findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? = fun KotlinClassFinder.findKotlinClass(javaClass: JavaClass, jvmMetadataVersion: JvmMetadataVersion): KotlinJvmBinaryClass? =
findKotlinClassOrContent(javaClass)?.toKotlinJvmBinaryClass() findKotlinClassOrContent(javaClass, jvmMetadataVersion)?.toKotlinJvmBinaryClass()
@@ -5,7 +5,13 @@
package org.jetbrains.kotlin.serialization.deserialization package org.jetbrains.kotlin.serialization.deserialization
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
interface DeserializationConfiguration { interface DeserializationConfiguration {
val binaryVersion: BinaryVersion?
get() = null
val skipMetadataVersionCheck: Boolean val skipMetadataVersionCheck: Boolean
get() = false get() = false
@@ -14,24 +14,43 @@ import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
class JvmMetadataVersion(versionArray: IntArray, val isStrictSemantics: Boolean) : BinaryVersion(*versionArray) { class JvmMetadataVersion(versionArray: IntArray, val isStrictSemantics: Boolean) : BinaryVersion(*versionArray) {
constructor(vararg numbers: Int) : this(numbers, isStrictSemantics = false) constructor(vararg numbers: Int) : this(numbers, isStrictSemantics = false)
override fun isCompatibleWithCurrentCompilerVersion(): Boolean = override fun isCompatibleWithCurrentCompilerVersion(): Boolean {
return isCompatibleInternal(INSTANCE_NEXT)
}
fun isCompatible(metadataVersionFromLanguageVersion: JvmMetadataVersion): Boolean {
// * Compiler of deployVersion X (INSTANCE) with LV Y (metadataVersionFromLanguageVersion)
// * can read metadata with version <= max(X+1, Y)
val forwardCompatibility = if (isStrictSemantics) INSTANCE else INSTANCE_NEXT
val limitVersion = maxOf(forwardCompatibility, metadataVersionFromLanguageVersion)
return isCompatibleInternal(limitVersion)
}
private fun isCompatibleInternal(limitVersion: JvmMetadataVersion): Boolean {
// NOTE: 1.0 is a pre-Kotlin-1.0 metadata version, with which the current compiler is incompatible // NOTE: 1.0 is a pre-Kotlin-1.0 metadata version, with which the current compiler is incompatible
(major != 1 || minor != 0) && if (major == 1 && minor == 0) return false
if (isStrictSemantics) { // The same for 0.*
isCompatibleTo(INSTANCE) if (major == 0) return false
} else { // Otherwise we just compare with the given limitVersion
// Kotlin 1.N is able to read metadata of versions up to Kotlin 1.{N+1} (unless the version has strict semantics). return this <= limitVersion
// Kotlin 1.9 is able to read Kotlin 2.0 }
// Kotlin K.* is able to read Kotlin M.* if K > M
major == INSTANCE.major && minor <= INSTANCE.minor + 1 || fun next(): JvmMetadataVersion {
major == 2 && INSTANCE.major == 1 && minor == 9 || if (minor < 9 || major > 1) return JvmMetadataVersion(major, minor + 1, 0)
major < INSTANCE.major return JvmMetadataVersion(2, 0, 0)
} }
fun prev(): JvmMetadataVersion {
if (minor > 0) return JvmMetadataVersion(major, minor - 1, 0)
return JvmMetadataVersion(major - 1, 9, 0)
}
companion object { companion object {
@JvmField @JvmField
val INSTANCE = JvmMetadataVersion(1, 8, 0) val INSTANCE = JvmMetadataVersion(1, 8, 0)
private val INSTANCE_NEXT = INSTANCE.next()
@JvmField @JvmField
val INVALID_VERSION = JvmMetadataVersion() val INVALID_VERSION = JvmMetadataVersion()
} }
@@ -53,6 +53,7 @@ class ModuleMapping private constructor(
debugName: String, debugName: String,
skipMetadataVersionCheck: Boolean, skipMetadataVersionCheck: Boolean,
isJvmPackageNameSupported: Boolean, isJvmPackageNameSupported: Boolean,
metadataVersionFromLanguageVersion: JvmMetadataVersion,
reportIncompatibleVersionError: (JvmMetadataVersion) -> Unit, reportIncompatibleVersionError: (JvmMetadataVersion) -> Unit,
): ModuleMapping { ): ModuleMapping {
if (bytes == null) { if (bytes == null) {
@@ -63,7 +64,7 @@ class ModuleMapping private constructor(
val versionNumber = readVersionNumber(stream) ?: return CORRUPTED val versionNumber = readVersionNumber(stream) ?: return CORRUPTED
val preVersion = JvmMetadataVersion(*versionNumber) val preVersion = JvmMetadataVersion(*versionNumber)
if (!skipMetadataVersionCheck && !preVersion.isCompatible()) { if (!skipMetadataVersionCheck && !preVersion.isCompatible(metadataVersionFromLanguageVersion)) {
reportIncompatibleVersionError(preVersion) reportIncompatibleVersionError(preVersion)
return EMPTY return EMPTY
} }
@@ -72,7 +73,7 @@ class ModuleMapping private constructor(
val flags = if (isKotlin1Dot4OrLater(preVersion)) stream.readInt() else 0 val flags = if (isKotlin1Dot4OrLater(preVersion)) stream.readInt() else 0
val version = JvmMetadataVersion(versionNumber, (flags and STRICT_METADATA_VERSION_SEMANTICS_FLAG) != 0) val version = JvmMetadataVersion(versionNumber, (flags and STRICT_METADATA_VERSION_SEMANTICS_FLAG) != 0)
if (!skipMetadataVersionCheck && !version.isCompatible()) { if (!skipMetadataVersionCheck && !version.isCompatible(metadataVersionFromLanguageVersion)) {
reportIncompatibleVersionError(version) reportIncompatibleVersionError(version)
return EMPTY return EMPTY
} }
@@ -14,7 +14,7 @@ package org.jetbrains.kotlin.metadata.deserialization
* - Patch version can be increased freely and is only supposed to be used for debugging. Increase the patch version when you * - Patch version can be increased freely and is only supposed to be used for debugging. Increase the patch version when you
* make a change to binaries which is both forward- and backward compatible. * make a change to binaries which is both forward- and backward compatible.
*/ */
abstract class BinaryVersion(private vararg val numbers: Int) { abstract class BinaryVersion(private vararg val numbers: Int) : Comparable<BinaryVersion> {
val major: Int = numbers.getOrNull(0) ?: UNKNOWN val major: Int = numbers.getOrNull(0) ?: UNKNOWN
val minor: Int = numbers.getOrNull(1) ?: UNKNOWN val minor: Int = numbers.getOrNull(1) ?: UNKNOWN
val patch: Int = numbers.getOrNull(2) ?: UNKNOWN val patch: Int = numbers.getOrNull(2) ?: UNKNOWN
@@ -87,6 +87,18 @@ abstract class BinaryVersion(private vararg val numbers: Int) {
return result return result
} }
override fun compareTo(other: BinaryVersion): Int {
return when {
major > other.major -> 1
major < other.major -> -1
minor > other.minor -> 1
minor < other.minor -> -1
patch > other.patch -> 1
patch < other.patch -> -1
else -> 0
}
}
companion object { companion object {
const val MAX_LENGTH = 1024 const val MAX_LENGTH = 1024
private const val UNKNOWN = -1 private const val UNKNOWN = -1
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.incremental.storage.ProtoMapValue
import org.jetbrains.kotlin.incremental.toProtoData import org.jetbrains.kotlin.incremental.toProtoData
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.BitEncoding import org.jetbrains.kotlin.metadata.jvm.deserialization.BitEncoding
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.test.MockLibraryUtil import org.jetbrains.kotlin.test.MockLibraryUtil
import java.io.File import java.io.File
@@ -31,12 +32,12 @@ abstract class AbstractJvmProtoComparisonTest : AbstractProtoComparisonTest<Loca
MockLibraryUtil.compileKotlin(sourceDir.path, outputDir, extraOptions = listOf("-Xdisable-default-scripting-plugin")) MockLibraryUtil.compileKotlin(sourceDir.path, outputDir, extraOptions = listOf("-Xdisable-default-scripting-plugin"))
val classFiles = outputDir.walkMatching { it.name.endsWith(".class") } val classFiles = outputDir.walkMatching { it.name.endsWith(".class") }
val localClassFiles = classFiles.map { LocalFileKotlinClass.create(it)!! } val localClassFiles = classFiles.map { LocalFileKotlinClass.create(it, JvmMetadataVersion.INSTANCE)!! }
return localClassFiles.associateBy { it.classId } return localClassFiles.associateBy { it.classId }
} }
override fun LocalFileKotlinClass.toProtoData(): ProtoData? { override fun LocalFileKotlinClass.toProtoData(): ProtoData? {
assert(classHeader.metadataVersion.isCompatible()) { "Incompatible class ($classHeader): $location" } assert(classHeader.metadataVersion.isCompatibleWithCurrentCompilerVersion()) { "Incompatible class ($classHeader): $location" }
val bytes by lazy { BitEncoding.decodeBytes(classHeader.data!!) } val bytes by lazy { BitEncoding.decodeBytes(classHeader.data!!) }
val strings by lazy { classHeader.strings!! } val strings by lazy { classHeader.strings!! }
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.jps.model.kotlinKind
import org.jetbrains.kotlin.jps.targets.KotlinJvmModuleBuildTarget import org.jetbrains.kotlin.jps.targets.KotlinJvmModuleBuildTarget
import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.preloading.ClassCondition import org.jetbrains.kotlin.preloading.ClassCondition
import org.jetbrains.kotlin.utils.KotlinPaths import org.jetbrains.kotlin.utils.KotlinPaths
@@ -690,7 +691,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
return outputItemCollector.outputs return outputItemCollector.outputs
.sortedBy { it.outputFile } .sortedBy { it.outputFile }
.groupBy(SimpleOutputItem::target, SimpleOutputItem::toGeneratedFile) .groupBy(SimpleOutputItem::target) { it.toGeneratedFile(JvmMetadataVersion.INSTANCE) }
} }
private fun updateLookupStorage( private fun updateLookupStorage(
@@ -1366,7 +1366,7 @@ public final class kotlinx/metadata/jvm/KotlinClassMetadata$Unknown : kotlinx/me
public final class kotlinx/metadata/jvm/KotlinModuleMetadata { public final class kotlinx/metadata/jvm/KotlinModuleMetadata {
public static final field Companion Lkotlinx/metadata/jvm/KotlinModuleMetadata$Companion; public static final field Companion Lkotlinx/metadata/jvm/KotlinModuleMetadata$Companion;
public fun <init> ([B)V public fun <init> ([BLkotlinx/metadata/internal/metadata/jvm/deserialization/JvmMetadataVersion;)V
public final fun accept (Lkotlinx/metadata/jvm/KmModuleVisitor;)V public final fun accept (Lkotlinx/metadata/jvm/KmModuleVisitor;)V
public final fun getBytes ()[B public final fun getBytes ()[B
public static final fun read ([B)Lkotlinx/metadata/jvm/KotlinModuleMetadata; public static final fun read ([B)Lkotlinx/metadata/jvm/KotlinModuleMetadata;
@@ -445,7 +445,7 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) {
if (!JvmMetadataVersion( if (!JvmMetadataVersion(
annotationData.metadataVersion, annotationData.metadataVersion,
(annotationData.extraInt and (1 shl 3)/* see JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG */) != 0 (annotationData.extraInt and (1 shl 3)/* see JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG */) != 0
).isCompatible() ).isCompatibleWithCurrentCompilerVersion()
) return null ) return null
return try { return try {
@@ -25,9 +25,13 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.serializeToByteArray
* *
* @property bytes the byte array representing the contents of a `.kotlin_module` file * @property bytes the byte array representing the contents of a `.kotlin_module` file
*/ */
class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePrivate") val bytes: ByteArray) { class KotlinModuleMetadata(@Suppress("MemberVisibilityCanBePrivate") val bytes: ByteArray, jvmMetadataVersion: JvmMetadataVersion) {
@get:IgnoreInApiDump internal val data: ModuleMapping = ModuleMapping.loadModuleMapping( @get:IgnoreInApiDump
bytes, javaClass.name, skipMetadataVersionCheck = false, isJvmPackageNameSupported = true internal val data: ModuleMapping = ModuleMapping.loadModuleMapping(
bytes, javaClass.name,
skipMetadataVersionCheck = false,
isJvmPackageNameSupported = true,
metadataVersionFromLanguageVersion = jvmMetadataVersion
) { ) {
// TODO: report incorrect versions of modules // TODO: report incorrect versions of modules
} }
@@ -86,7 +90,7 @@ class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePri
*/ */
@Deprecated("Writer API is deprecated as excessive and cumbersome. Please use KotlinModuleMetadata.write(kmModule, metadataVersion)") @Deprecated("Writer API is deprecated as excessive and cumbersome. Please use KotlinModuleMetadata.write(kmModule, metadataVersion)")
fun write(metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata = fun write(metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata =
KotlinModuleMetadata(b.build().serializeToByteArray(JvmMetadataVersion(*metadataVersion), 0)) KotlinModuleMetadata(b.build().serializeToByteArray(JvmMetadataVersion(*metadataVersion), 0), jvmMetadataVersion)
} }
/** /**
@@ -125,7 +129,7 @@ class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePri
@JvmStatic @JvmStatic
fun read(bytes: ByteArray): KotlinModuleMetadata? { fun read(bytes: ByteArray): KotlinModuleMetadata? {
try { try {
val result = KotlinModuleMetadata(bytes) val result = KotlinModuleMetadata(bytes, JvmMetadataVersion.INSTANCE)
if (result.data == ModuleMapping.EMPTY) return null if (result.data == ModuleMapping.EMPTY) return null
if (result.data == ModuleMapping.CORRUPTED) { if (result.data == ModuleMapping.CORRUPTED) {
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.compilerRunner.OutputItemsCollector
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.incremental.isClassFile import org.jetbrains.kotlin.incremental.isClassFile
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.utils.toMetadataVersion
import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.ClassWriter import org.jetbrains.org.objectweb.asm.ClassWriter
@@ -124,7 +126,7 @@ class JvmAbiAnalysisHandlerExtension(
for (output in outputs) { for (output in outputs) {
if (!output.file.isClassFile()) continue if (!output.file.isClassFile()) continue
val classData = output.classData() ?: continue val classData = output.classData(compilerConfiguration) ?: continue
val header = classData.classHeader val header = classData.classHeader
val isNeededForAbi = when (header.kind) { val isNeededForAbi = when (header.kind) {
KotlinClassHeader.Kind.CLASS -> { KotlinClassHeader.Kind.CLASS -> {
@@ -198,11 +200,13 @@ class JvmAbiAnalysisHandlerExtension(
// null bytes means that file should not be written // null bytes means that file should not be written
private var bytes: ByteArray? private var bytes: ByteArray?
) { ) {
fun classData(): ClassData? = fun classData(compilerConfiguration: CompilerConfiguration): ClassData? =
when { when {
bytes == null -> null bytes == null -> null
!file.isClassFile() -> null !file.isClassFile() -> null
else -> FileBasedKotlinClass.create(bytes!!) { classId, classVersion, classHeader, _ -> else -> FileBasedKotlinClass.create(
bytes!!, compilerConfiguration.languageVersionSettings.languageVersion.toMetadataVersion()
) { classId, classVersion, classHeader, _ ->
ClassData(classId, classVersion, classHeader) ClassData(classId, classVersion, classHeader)
} }
} }
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.toMetadataVersion
import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.jvm.ClassLoaderByConfiguration import kotlin.script.experimental.jvm.ClassLoaderByConfiguration
@@ -45,10 +46,11 @@ class PackageFragmentFromClassLoaderProviderExtension(
val deserializedDescriptorResolver = DeserializedDescriptorResolver() val deserializedDescriptorResolver = DeserializedDescriptorResolver()
val singleModuleClassResolver = SingleModuleClassResolver() val singleModuleClassResolver = SingleModuleClassResolver()
val notFoundClasses = NotFoundClasses(storageManager, module) val notFoundClasses = NotFoundClasses(storageManager, module)
val languageVersionSettings = compilerConfiguration.languageVersionSettings
val packagePartProvider = val packagePartProvider =
PackagePartFromClassLoaderProvider( PackagePartFromClassLoaderProvider(
classLoader, classLoader,
compilerConfiguration.languageVersionSettings, languageVersionSettings,
compilerConfiguration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]!! compilerConfiguration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]!!
) )
@@ -63,7 +65,8 @@ class PackageFragmentFromClassLoaderProviderExtension(
val deserializationComponentsForJava = val deserializationComponentsForJava =
makeDeserializationComponentsForJava( makeDeserializationComponentsForJava(
module, storageManager, notFoundClasses, lazyJavaPackageFragmentProvider, module, storageManager, notFoundClasses, lazyJavaPackageFragmentProvider,
reflectKotlinClassFinder, deserializedDescriptorResolver, RuntimeErrorReporter reflectKotlinClassFinder, deserializedDescriptorResolver, RuntimeErrorReporter,
languageVersionSettings.languageVersion.toMetadataVersion()
) )
deserializedDescriptorResolver.setComponents(deserializationComponentsForJava) deserializedDescriptorResolver.setComponents(deserializationComponentsForJava)
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.tryLoadModuleMapping
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartProviderBase import org.jetbrains.kotlin.load.kotlin.JvmPackagePartProviderBase
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
import kotlin.script.experimental.jvm.util.forAllMatchingFiles import kotlin.script.experimental.jvm.util.forAllMatchingFiles
class PackagePartFromClassLoaderProvider( class PackagePartFromClassLoaderProvider(
@@ -19,7 +19,7 @@ class PackagePartFromClassLoaderProvider(
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
messageCollector: MessageCollector messageCollector: MessageCollector
) : JvmPackagePartProviderBase<String>() { ) : JvmPackagePartProviderBase<String>() {
override val deserializationConfiguration = CompilerDeserializationConfiguration(languageVersionSettings) override val deserializationConfiguration = JvmCompilerDeserializationConfiguration(languageVersionSettings)
override val loadedModules: MutableList<ModuleMappingInfo<String>> = SmartList() override val loadedModules: MutableList<ModuleMappingInfo<String>> = SmartList()