From bd47e9d47b5f6aa33d5af4c1ab18996ee8572a38 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 28 Dec 2015 20:01:00 +0300 Subject: [PATCH] Split JVM binary version into two: metadata and bytecode interface Currently all code only uses the first one (JvmMetadataVersion), later the bytecode interface version (JvmBytecodeBinaryVersion) will be used only in codegen and reflection to avoid compiling against or calling methods with unsupported conventions like default method naming and signature, getters/setters naming etc. --- .../load/java/JvmBytecodeBinaryVersion.kt | 4 ++ .../kotlin/load/java/lazy/resolvers.kt | 4 +- .../DeserializedDescriptorResolver.java | 4 +- .../kotlin/load/kotlin/JvmMetadataVersion.kt | 43 ++++++++++++++++ .../load/kotlin/header/KotlinClassHeader.kt | 13 ++--- ...eadKotlinClassHeaderAnnotationVisitor.java | 21 ++++++-- .../classFile/ClassFileDecompilerUtil.kt | 2 +- .../classFile/KotlinClassFileDecompiler.kt | 49 ++++++++++--------- .../classFile/KotlinClsStubBuilder.kt | 14 +++--- .../kotlin/idea/vfilefinder/fileIndexes.kt | 2 +- .../jps/incremental/IncrementalCacheImpl.kt | 19 +++---- .../classFilesComparison.kt | 21 ++++---- .../AbstractProtoComparisonTest.kt | 19 +++---- 13 files changed, 136 insertions(+), 79 deletions(-) create mode 100644 core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmBytecodeBinaryVersion.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmBytecodeBinaryVersion.kt index 1773a963b48..b3b8c61eaec 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmBytecodeBinaryVersion.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmBytecodeBinaryVersion.kt @@ -18,6 +18,10 @@ package org.jetbrains.kotlin.load.java import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion +/** + * The version of conventions used in bytecode of generated .class files, such as default method naming & signatures, + * internal member name mangling specifics, property getter/setter names, etc. + */ class JvmBytecodeBinaryVersion protected constructor( major: Int, minor: Int, patch: Int, rest: List ) : BinaryVersion(major, minor, patch, rest) { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt index cab83407cd1..590697fa71d 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/resolvers.kt @@ -70,8 +70,8 @@ fun LazyJavaResolverContext.resolveKotlinBinaryClass(kotlinClass: KotlinJvmBinar val header = kotlinClass.classHeader return when { - !header.version.isCompatible() -> { - components.errorReporter.reportIncompatibleAbiVersion(kotlinClass.classId, kotlinClass.location, header.version) + !header.metadataVersion.isCompatible() -> { + components.errorReporter.reportIncompatibleAbiVersion(kotlinClass.classId, kotlinClass.location, header.metadataVersion) KotlinClassLookupResult.NotFound } header.kind == KotlinClassHeader.Kind.CLASS -> { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java index 229ce8d2025..c391f2d6c4b 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java @@ -115,8 +115,8 @@ public final class DeserializedDescriptorResolver { @Nullable public String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @NotNull Set expectedKinds) { KotlinClassHeader header = kotlinClass.getClassHeader(); - if (!header.getVersion().isCompatible()) { - errorReporter.reportIncompatibleAbiVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getVersion()); + if (!header.getMetadataVersion().isCompatible()) { + errorReporter.reportIncompatibleAbiVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getMetadataVersion()); } else if (expectedKinds.contains(header.getKind())) { return header.getAnnotationData(); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt new file mode 100644 index 00000000000..0f8acc6b315 --- /dev/null +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.load.kotlin + +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion + +/** + * The version of the metadata serialized by the compiler and deserialized by the compiler and reflection. + * This version includes the version of the core protobuf messages (descriptors.proto) as well as JVM extensions (jvm_descriptors.proto). + */ +class JvmMetadataVersion protected constructor( + major: Int, minor: Int, patch: Int, rest: List +) : BinaryVersion(major, minor, patch, rest) { + override fun isCompatible() = this.isCompatibleTo(INSTANCE) + + companion object { + @JvmField + val INSTANCE = create(1, 0, 2) + + @JvmField + val INVALID_VERSION = JvmMetadataVersion.create(IntArray(0)) + + @JvmStatic + fun create(version: IntArray) = create(version, ::JvmMetadataVersion) + + @JvmStatic + fun create(major: Int, minor: Int, patch: Int) = create(major, minor, patch, ::JvmMetadataVersion) + } +} diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/KotlinClassHeader.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/KotlinClassHeader.kt index 71763c99701..5fb3cc8e433 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/KotlinClassHeader.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/KotlinClassHeader.kt @@ -16,11 +16,13 @@ package org.jetbrains.kotlin.load.kotlin.header -import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion +import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion +import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion class KotlinClassHeader( val kind: KotlinClassHeader.Kind, - val version: BinaryVersion, + val metadataVersion: JvmMetadataVersion, + val bytecodeVersion: JvmBytecodeBinaryVersion, val annotationData: Array?, val strings: Array?, val filePartClassNames: Array?, @@ -36,10 +38,5 @@ class KotlinClassHeader( SYNTHETIC_CLASS } - override fun toString() = "$kind " + (if (isLocalClass) "(local) " else "") + "version=$version" + override fun toString() = "$kind " + (if (isLocalClass) "(local) " else "") + "version=$metadataVersion" } - -fun KotlinClassHeader.isCompatibleClassKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.CLASS -fun KotlinClassHeader.isCompatibleFileFacadeKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.FILE_FACADE -fun KotlinClassHeader.isCompatibleMultifileClassKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS -fun KotlinClassHeader.isCompatibleMultifileClassPartKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java index 779d0c994b1..8cee066627c 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java @@ -20,10 +20,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.SourceElement; import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion; +import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; import java.util.ArrayList; import java.util.HashMap; @@ -45,7 +45,8 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor HEADER_KINDS.put(ClassId.topLevel(KOTLIN_SYNTHETIC_CLASS), SYNTHETIC_CLASS); } - private BinaryVersion version = JvmBytecodeBinaryVersion.INVALID_VERSION; + private JvmMetadataVersion metadataVersion = null; + private JvmBytecodeBinaryVersion bytecodeVersion = null; private String multifileClassName = null; private String[] filePartClassNames = null; private String[] annotationData = null; @@ -60,7 +61,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor return null; } - if (!version.isCompatible()) { + if (metadataVersion == null || !metadataVersion.isCompatible()) { annotationData = null; } else if (shouldHaveData() && annotationData == null) { @@ -70,7 +71,10 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } return new KotlinClassHeader( - headerKind, version, annotationData, strings, filePartClassNames, multifileClassName, isInterfaceDefaultImpls, isLocalClass + headerKind, + metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION, + bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION, + annotationData, strings, filePartClassNames, multifileClassName, isInterfaceDefaultImpls, isLocalClass ); } @@ -118,7 +122,14 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor String string = name.asString(); if (VERSION_FIELD_NAME.equals(string)) { - version = value instanceof int[] ? JvmBytecodeBinaryVersion.create((int[]) value) : JvmBytecodeBinaryVersion.INVALID_VERSION; + if (value instanceof int[]) { + metadataVersion = JvmMetadataVersion.create((int[]) value); + + // If there's no bytecode binary version in the class file, we assume it to be equal to the metadata version + if (bytecodeVersion == null) { + bytecodeVersion = JvmBytecodeBinaryVersion.create((int[]) value); + } + } } else if (MULTIFILE_CLASS_NAME_FIELD_NAME.equals(string)) { multifileClassName = value instanceof String ? (String) value : null; diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt index 9e6c2c48b96..4a1450ff26e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt @@ -54,7 +54,7 @@ fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean { if (!isKotlinJvmCompiledFile(file)) return false val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file) - return kotlinClass != null && kotlinClass.classHeader.version.isCompatible() + return kotlinClass != null && kotlinClass.classHeader.metadataVersion.isCompatible() } /** diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt index 379a9c1f299..8ad7369e4f0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt @@ -29,9 +29,7 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.types.flexibility import org.jetbrains.kotlin.types.isFlexible @@ -79,30 +77,33 @@ fun buildDecompiledTextForClassFile( classFile: VirtualFile, resolver: ResolverForDecompiler = DeserializerForClassfileDecompiler(classFile) ): DecompiledText { - val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile) - assert(kotlinClassHeaderInfo != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } - val classId = kotlinClassHeaderInfo!!.classId - val classHeader = kotlinClassHeaderInfo.classHeader - val packageFqName = classId.packageFqName + val (classHeader, classId) = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile) + ?: error("Decompiled data factory shouldn't be called on an unsupported file: " + classFile) - return when { - !classHeader.version.isCompatible() -> { - DecompiledText( - INCOMPATIBLE_ABI_VERSION_COMMENT - .replace(CURRENT_ABI_VERSION_MARKER, JvmBytecodeBinaryVersion.INSTANCE.toString()) - .replace(FILE_ABI_VERSION_MARKER, classHeader.version.toString()), - mapOf()) - } - classHeader.isCompatibleFileFacadeKind() -> - buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())), decompilerRendererForClassFiles) - classHeader.isCompatibleClassKind() -> - buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), decompilerRendererForClassFiles) - classHeader.isCompatibleMultifileClassKind() -> { + if (!classHeader.metadataVersion.isCompatible()) { + return DecompiledText( + INCOMPATIBLE_ABI_VERSION_COMMENT + .replace(CURRENT_ABI_VERSION_MARKER, JvmBytecodeBinaryVersion.INSTANCE.toString()) + .replace(FILE_ABI_VERSION_MARKER, classHeader.metadataVersion.toString()), + mapOf() + ) + } + + return when (classHeader.kind) { + KotlinClassHeader.Kind.FILE_FACADE -> + buildDecompiledText(classId.packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())), + decompilerRendererForClassFiles) + KotlinClassHeader.Kind.CLASS -> + buildDecompiledText(classId.packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), + decompilerRendererForClassFiles) + KotlinClassHeader.Kind.MULTIFILE_CLASS -> { val partClasses = findMultifileClassParts(classFile, classId, classHeader) - val partMembers = partClasses.flatMap { partClass -> resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) } - buildDecompiledText(packageFqName, partMembers, decompilerRendererForClassFiles) + val partMembers = partClasses.flatMap { partClass -> + resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) + } + buildDecompiledText(classId.packageFqName, partMembers, decompilerRendererForClassFiles) } else -> - throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.version.isCompatible()}") + throw UnsupportedOperationException("Unknown header kind: $classHeader, class $classId") } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt index d9701de9632..f4113bef9d1 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt @@ -30,9 +30,7 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter import org.jetbrains.kotlin.load.kotlin.AbstractBinaryClassAnnotationAndConstantLoader import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile @@ -62,12 +60,12 @@ open class KotlinClsStubBuilder : ClsStubBuilder() { val header = kotlinClassHeaderInfo.classHeader val classId = kotlinClassHeaderInfo.classId val packageFqName = classId.packageFqName - if (!header.version.isCompatible()) { + if (!header.metadataVersion.isCompatible()) { return createIncompatibleAbiVersionFileStub() } val components = createStubBuilderComponents(file, packageFqName) - if (header.isCompatibleMultifileClassKind()) { + if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) { val partFiles = findMultifileClassParts(file, classId, header) return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components) } @@ -82,14 +80,14 @@ open class KotlinClsStubBuilder : ClsStubBuilder() { LOG.error("String table not found in file ${file.name}") return null } - return when { - header.isCompatibleClassKind() -> { + return when (header.kind) { + KotlinClassHeader.Kind.CLASS -> { if (header.isLocalClass) return null val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData, strings) val context = components.createContext(nameResolver, packageFqName, TypeTable(classProto.typeTable)) createTopLevelClassStub(classId, classProto, context) } - header.isCompatibleFileFacadeKind() -> { + KotlinClassHeader.Kind.FILE_FACADE -> { val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings) val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable)) createFileFacadeStub(packageProto, classId.asSingleFqName(), context) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt index 54ac1645835..4ed9782ccc0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt @@ -79,7 +79,7 @@ object KotlinClassFileIndex : KotlinFileIndexBase(KotlinCl private val INDEXER = indexer() { fileContent -> val headerInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(fileContent.file, fileContent.content) - if (headerInfo != null && headerInfo.classHeader.version.isCompatible()) headerInfo.classId.asSingleFqName() else null + if (headerInfo != null && headerInfo.classHeader.metadataVersion.isCompatible()) headerInfo.classId.asSingleFqName() else null } } diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt index 21537fd9d34..afb9f5032c7 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -30,10 +30,7 @@ import org.jetbrains.kotlin.jps.build.GeneratedJvmClass import org.jetbrains.kotlin.jps.build.KotlinBuilder import org.jetbrains.kotlin.jps.incremental.storage.* import org.jetbrains.kotlin.load.kotlin.ModuleMapping -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassPartKind +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto import org.jetbrains.kotlin.name.FqName @@ -147,8 +144,12 @@ open class IncrementalCacheImpl( } val header = kotlinClass.classHeader - val changesInfo = when { - header.isCompatibleFileFacadeKind() -> { + if (header.isLocalClass) { + return CompilationResult.NO_CHANGES + } + + val changesInfo = when (header.kind) { + KotlinClassHeader.Kind.FILE_FACADE -> { assert(sourceFiles.size == 1) { "Package part from several source files: $sourceFiles" } packagePartMap.addPackagePart(className) @@ -156,7 +157,7 @@ open class IncrementalCacheImpl( constantsMap.process(kotlinClass) + additionalProcessChangedClass(kotlinClass, isPackage = true) } - header.isCompatibleMultifileClassKind() -> { + KotlinClassHeader.Kind.MULTIFILE_CLASS -> { val partNames = kotlinClass.classHeader.filePartClassNames?.toList() ?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}") multifileClassFacadeMap.add(className, partNames) @@ -165,7 +166,7 @@ open class IncrementalCacheImpl( constantsMap.process(kotlinClass) + additionalProcessChangedClass(kotlinClass, isPackage = true) } - header.isCompatibleMultifileClassPartKind() -> { + KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> { assert(sourceFiles.size == 1) { "Multifile class part from several source files: $sourceFiles" } packagePartMap.addPackagePart(className) multifileClassPartMap.add(className.internalName, header.multifileClassName!!) @@ -174,7 +175,7 @@ open class IncrementalCacheImpl( constantsMap.process(kotlinClass) + additionalProcessChangedClass(kotlinClass, isPackage = true) } - header.isCompatibleClassKind() && !header.isLocalClass -> { + KotlinClassHeader.Kind.CLASS -> { addToClassStorage(kotlinClass) protoMap.process(kotlinClass, isPackage = false) + diff --git a/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt b/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt index 4fa17591046..a9e51f5b98d 100644 --- a/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt +++ b/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt @@ -22,9 +22,7 @@ import com.google.common.io.Files import com.google.protobuf.ExtensionRegistry import com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.jps.incremental.LocalFileKotlinClass -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassPartKind +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.serialization.DebugProtoBuf import org.jetbrains.kotlin.serialization.jvm.BitEncoding import org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf @@ -141,14 +139,17 @@ fun classFileToString(classFile: File): String { out.write("\n------ string table types proto -----\n${DebugJvmProtoBuf.StringTableTypes.parseDelimitedFrom(input)}") - when { - classHeader!!.isCompatibleFileFacadeKind() -> - out.write("\n------ file facade proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") - classHeader.isCompatibleClassKind() -> - out.write("\n------ class proto -----\n${DebugProtoBuf.Class.parseFrom(input, getExtensionRegistry())}") - classHeader.isCompatibleMultifileClassPartKind() -> - out.write("\n------ multi-file part proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") + if (!classHeader!!.metadataVersion.isCompatible()) { + error("Incompatible class ($classHeader): $classFile") + } + when (classHeader.kind) { + KotlinClassHeader.Kind.FILE_FACADE -> + out.write("\n------ file facade proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") + KotlinClassHeader.Kind.CLASS -> + out.write("\n------ class proto -----\n${DebugProtoBuf.Class.parseFrom(input, getExtensionRegistry())}") + KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> + out.write("\n------ multi-file part proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") else -> throw IllegalStateException() } } diff --git a/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt b/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt index f9ae0e18edc..77fdb5fc752 100644 --- a/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt +++ b/jps-plugin/test/org/jetbrains/kotlin/jps/incremental/AbstractProtoComparisonTest.kt @@ -20,9 +20,7 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.testFramework.UsefulTestCase import com.intellij.util.SmartList import org.jetbrains.kotlin.jps.incremental.storage.ProtoMapValue -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassPartKind +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.serialization.jvm.BitEncoding import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.MockLibraryUtil @@ -93,19 +91,22 @@ abstract class AbstractProtoComparisonTest : UsefulTestCase() { val oldProtoBytes = BitEncoding.decodeBytes(oldClassHeader.annotationData!!) val newProtoBytes = BitEncoding.decodeBytes(newClassHeader.annotationData!!) + assert(oldClassHeader.metadataVersion.isCompatible()) { "Incompatible class ($oldClassHeader): $oldClassFile" } + assert(newClassHeader.metadataVersion.isCompatible()) { "Incompatible class ($newClassHeader): $newClassFile" } + val oldProto = ProtoMapValue( - oldClassHeader.isCompatibleFileFacadeKind() || oldClassHeader.isCompatibleMultifileClassPartKind(), + oldClassHeader.kind == KotlinClassHeader.Kind.FILE_FACADE || + oldClassHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART, oldProtoBytes, oldClassHeader.strings!! ) val newProto = ProtoMapValue( - newClassHeader.isCompatibleFileFacadeKind() || newClassHeader.isCompatibleMultifileClassPartKind(), + newClassHeader.kind == KotlinClassHeader.Kind.FILE_FACADE || + newClassHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART, newProtoBytes, newClassHeader.strings!! ) - val diff = when { - newClassHeader.isCompatibleClassKind() || - newClassHeader.isCompatibleFileFacadeKind() || - newClassHeader.isCompatibleMultifileClassPartKind() -> + val diff = when (newClassHeader.kind) { + KotlinClassHeader.Kind.CLASS, KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> difference(oldProto, newProto) else -> { println("ignore ${oldLocalFileKotlinClass.classId}")