From c242665cd3c73c130983e543b8f90ae4a9e86ba6 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 6 Nov 2014 19:03:48 +0300 Subject: [PATCH] Extract isCompatibleAbiVersion from kinds enum and store read kinds even for incompatible version --- .../jet/lang/resolve/java/lazy/resolvers.kt | 8 +-- .../DeserializedDescriptorResolver.java | 2 +- .../kotlin/header/KotlinClassHeader.kt | 14 +++-- ...eadKotlinClassHeaderAnnotationVisitor.java | 53 ++++++++++++------- .../jet/plugin/decompiler/DecompiledUtils.kt | 3 +- .../textBuilder/DecompiledTextFactory.kt | 7 ++- .../vfilefinder/KotlinClassFileIndex.java | 2 +- .../jps/incremental/IncrementalCacheImpl.kt | 10 ++-- .../jet/jps/build/classFilesComparison.kt | 8 +-- 9 files changed, 70 insertions(+), 37 deletions(-) diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt index 3e6a4921539..d5aa31ffacc 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt @@ -89,15 +89,15 @@ private fun LazyJavaResolverContext.resolveBinaryClass(kotlinClass: KotlinJvmBin if (kotlinClass == null) return null val header = kotlinClass.getClassHeader() - if (header.kind == KotlinClassHeader.Kind.CLASS) { + if (!header.isCompatibleAbiVersion) { + errorReporter.reportIncompatibleAbiVersion(kotlinClass, header.version) + } + else if (header.kind == KotlinClassHeader.Kind.CLASS) { val descriptor = packageFragmentProvider.resolveKotlinBinaryClass(kotlinClass) if (descriptor != null) { return JavaClassLookupResult(kClass = descriptor) } } - else if (header.kind == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { - errorReporter.reportIncompatibleAbiVersion(kotlinClass, header.version) - } else { // This is a package or trait-impl or something like that return JavaClassLookupResult() diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java index cb80c0c45f3..03ac9298361 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java @@ -78,7 +78,7 @@ public final class DeserializedDescriptorResolver { @Nullable public String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @NotNull KotlinClassHeader.Kind expectedKind) { KotlinClassHeader header = kotlinClass.getClassHeader(); - if (header.getKind() == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { + if (!header.getIsCompatibleAbiVersion()) { errorReporter.reportIncompatibleAbiVersion(kotlinClass, header.getVersion()); } else if (header.getKind() == expectedKind) { diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.kt index cd8e81eebe2..7234885e5c4 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.kt @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve.kotlin.header import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass +import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil public class KotlinClassHeader( public val kind: KotlinClassHeader.Kind, @@ -24,19 +25,24 @@ public class KotlinClassHeader( public val annotationData: Array?, public val syntheticClassKind: KotlinSyntheticClass.Kind? ) { + public val isCompatibleAbiVersion: Boolean get() = AbiVersionUtil.isAbiVersionCompatible(version); + { - assert((annotationData == null) == (kind != Kind.CLASS && kind != Kind.PACKAGE_FACADE)) { + assert(!isCompatibleAbiVersion || (annotationData == null) == (kind != Kind.CLASS && kind != Kind.PACKAGE_FACADE)) { "Annotation data should be not null only for CLASS and PACKAGE_FACADE (kind=" + kind + ")" } - assert((syntheticClassKind == null) == (kind != Kind.SYNTHETIC_CLASS)) { + assert(!isCompatibleAbiVersion || (syntheticClassKind == null) == (kind != Kind.SYNTHETIC_CLASS)) { "Synthetic class kind should be present for SYNTHETIC_CLASS (kind=" + kind + ")" } } public enum class Kind { - INCOMPATIBLE_ABI_VERSION CLASS PACKAGE_FACADE SYNTHETIC_CLASS } -} \ No newline at end of file +} + +public fun KotlinClassHeader.isCompatibleClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.CLASS +public fun KotlinClassHeader.isCompatiblePackageFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.PACKAGE_FACADE +public fun KotlinClassHeader.isCompatibleSyntheticClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS \ No newline at end of file diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java index 9a481621209..6420b212ddd 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.name.ClassId; -import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import java.util.*; @@ -33,21 +32,28 @@ import static org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader.Kin public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor { private static final Map HEADER_KINDS = new HashMap(); + private static final Map OLD_DEPRECATED_ANNOTATIONS_KINDS = new HashMap(); + private int version = AbiVersionUtil.INVALID_VERSION; static { HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_CLASS), CLASS); HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE), PACKAGE_FACADE); HEADER_KINDS.put(KotlinSyntheticClass.CLASS_NAME, SYNTHETIC_CLASS); - @SuppressWarnings("deprecation") - List incompatible = Arrays.asList(OLD_JET_CLASS_ANNOTATION, OLD_JET_PACKAGE_CLASS_ANNOTATION, OLD_KOTLIN_CLASS, - OLD_KOTLIN_PACKAGE, OLD_KOTLIN_PACKAGE_FRAGMENT, OLD_KOTLIN_TRAIT_IMPL); - for (FqName fqName : incompatible) { - HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(fqName), INCOMPATIBLE_ABI_VERSION); - } + initOldAnnotations(); + } + + @SuppressWarnings("deprecation") + private static void initOldAnnotations() { + OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_JET_CLASS_ANNOTATION), CLASS); + OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_JET_PACKAGE_CLASS_ANNOTATION), + KotlinClassHeader.Kind.PACKAGE_FACADE); + OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_KOTLIN_CLASS), CLASS); + OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_KOTLIN_PACKAGE), PACKAGE_FACADE); + OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_KOTLIN_PACKAGE_FRAGMENT), SYNTHETIC_CLASS); + OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_KOTLIN_TRAIT_IMPL), SYNTHETIC_CLASS); } - private int version = AbiVersionUtil.INVALID_VERSION; private String[] annotationData = null; private KotlinClassHeader.Kind headerKind = null; private KotlinSyntheticClass.Kind syntheticClassKind = null; @@ -59,7 +65,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } if (!AbiVersionUtil.isAbiVersionCompatible(version)) { - return new KotlinClassHeader(INCOMPATIBLE_ABI_VERSION, version, null, null); + return new KotlinClassHeader(headerKind, version, null, syntheticClassKind); } if ((headerKind == CLASS || headerKind == PACKAGE_FACADE) && annotationData == null) { @@ -74,22 +80,32 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor @Nullable @Override public AnnotationArgumentVisitor visitAnnotation(@NotNull ClassId classId) { - JvmClassName annotation = JvmClassName.byClassId(classId); - KotlinClassHeader.Kind newKind = HEADER_KINDS.get(annotation); - if (newKind == null) return null; - if (headerKind != null) { // Ignore all Kotlin annotations except the first found return null; } - headerKind = newKind; + JvmClassName annotation = JvmClassName.byClassId(classId); - if (newKind == CLASS || newKind == PACKAGE_FACADE) { - return kotlinClassOrPackageVisitor(annotation); + KotlinClassHeader.Kind newKind = HEADER_KINDS.get(annotation); + if (newKind != null) { + headerKind = newKind; + + switch (newKind) { + case CLASS: + return kotlinClassOrPackageVisitor(annotation); + case PACKAGE_FACADE: + return kotlinClassOrPackageVisitor(annotation); + case SYNTHETIC_CLASS: + return syntheticClassAnnotationVisitor(); + default: + throw new IllegalStateException("Unknown kind: " + newKind); + } } - else if (newKind == SYNTHETIC_CLASS) { - return syntheticClassAnnotationVisitor(); + + KotlinClassHeader.Kind oldAnnotationKind = OLD_DEPRECATED_ANNOTATIONS_KINDS.get(annotation); + if (oldAnnotationKind != null) { + headerKind = oldAnnotationKind; } return null; @@ -145,6 +161,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor @Override public void visitEnd() { + //noinspection SSBasedInspection annotationData = strings.toArray(new String[strings.size()]); } }; diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/DecompiledUtils.kt b/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/DecompiledUtils.kt index a2f262b15a4..ccdffff1ff2 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/DecompiledUtils.kt +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/DecompiledUtils.kt @@ -27,6 +27,7 @@ public fun isKotlinCompiledFile(file: VirtualFile): Boolean { if (isKotlinCompiledFileWithIncompatibleAbiVersion(file)) { return false } + val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader() return header != null && header.syntheticClassKind != KotlinSyntheticClass.Kind.TRAIT_IMPL } @@ -36,7 +37,7 @@ public fun isKotlinCompiledFileWithIncompatibleAbiVersion(file: VirtualFile): Bo return false } val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader() - return header?.kind == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION + return header != null && !header.isCompatibleAbiVersion } public fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean { diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DecompiledTextFactory.kt b/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DecompiledTextFactory.kt index b1a42516b20..b2ecf9ecc08 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DecompiledTextFactory.kt +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DecompiledTextFactory.kt @@ -40,8 +40,13 @@ public fun buildDecompiledText( val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) assert(kotlinClass != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } val classId = kotlinClass!!.getClassId() + val classHeader = kotlinClass.getClassHeader() val kind = kotlinClass.getClassHeader().kind val packageFqName = classId.getPackageFqName() + + if (!classHeader.isCompatibleAbiVersion) { + throw UnsupportedOperationException("Illegal operation for incompatibel header") + } return if (kind == KotlinClassHeader.Kind.PACKAGE_FACADE) { buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInPackage(packageFqName))) @@ -83,7 +88,7 @@ private fun buildDecompiledText(packageFqName: FqName, descriptors: List): List { - val r = ArrayList(input) + val r = ArrayList(input) Collections.sort(r, MemberComparator.INSTANCE) return r } diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java index fe35b7eb200..a62c444dcd0 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java @@ -73,7 +73,7 @@ public final class KotlinClassFileIndex extends ScalarIndexExtension { public Map map(@NotNull FileContent inputData) { try { KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(inputData.getFile()); - if (kotlinClass != null && kotlinClass.getClassHeader().getKind() != KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { + if (kotlinClass != null && kotlinClass.getClassHeader().getIsCompatibleAbiVersion()) { return Collections.singletonMap(kotlinClass.getClassId().asSingleFqName().toSafe(), null); } } diff --git a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt index ee69debef4f..3e449cf1bfa 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt @@ -42,6 +42,8 @@ import org.jetbrains.jps.builders.storage.StorageProvider import java.io.IOException import java.util.Scanner import org.jetbrains.jet.lang.resolve.java.JvmAbi +import org.jetbrains.jet.lang.resolve.kotlin.header.isCompatiblePackageFacadeKind +import org.jetbrains.jet.lang.resolve.kotlin.header.isCompatibleClassKind val INLINE_ANNOTATION_DESC = "Lkotlin/inline;" @@ -106,11 +108,11 @@ public class IncrementalCacheImpl(val baseDir: File): StorageOwner, IncrementalC val annotationDataEncoded = header.annotationData if (annotationDataEncoded != null) { val data = BitEncoding.decodeBytes(annotationDataEncoded) - when (header.kind) { - KotlinClassHeader.Kind.PACKAGE_FACADE -> { + when { + header.isCompatiblePackageFacadeKind() -> { return if (protoMap.put(className, data)) COMPILE_OTHERS else DO_NOTHING } - KotlinClassHeader.Kind.CLASS -> { + header.isCompatibleClassKind() -> { val inlinesChanged = inlineFunctionsMap.process(className, fileBytes) val protoChanged = protoMap.put(className, data) val constantsChanged = constantsMap.process(className, fileBytes) @@ -118,7 +120,7 @@ public class IncrementalCacheImpl(val baseDir: File): StorageOwner, IncrementalC return if (inlinesChanged) RECOMPILE_ALL else if (protoChanged || constantsChanged) COMPILE_OTHERS else DO_NOTHING } else -> { - throw IllegalStateException("Unexpected kind with annotationData: ${header.kind}") + throw IllegalStateException("Unexpected kind with annotationData: ${header.kind}, isCompatible: ${header.isCompatibleAbiVersion}") } } } diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt b/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt index 989a2b78e97..baec706c9a8 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt @@ -36,6 +36,8 @@ import java.io.ByteArrayInputStream import org.jetbrains.jet.descriptors.serialization.DebugProtoBuf import java.util.Arrays import org.jetbrains.jet.jps.incremental.LocalFileKotlinClass +import org.jetbrains.jet.lang.resolve.kotlin.header.isCompatibleClassKind +import org.jetbrains.jet.lang.resolve.kotlin.header.isCompatiblePackageFacadeKind // Set this to true if you want to dump all bytecode (test will fail in this case) val DUMP_ALL = System.getProperty("comparison.dump.all") == "true" @@ -140,11 +142,11 @@ fun classFileToString(classFile: File): String { out.write("\n------ simpleNames proto -----\n${DebugProtoBuf.StringTable.parseDelimitedFrom(input)}") out.write("\n------ qualifiedNames proto -----\n${DebugProtoBuf.QualifiedNameTable.parseDelimitedFrom(input)}") - when (classHeader!!.kind) { - KotlinClassHeader.Kind.PACKAGE_FACADE -> + when { + classHeader!!.isCompatiblePackageFacadeKind() -> out.write("\n------ package proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") - KotlinClassHeader.Kind.CLASS -> + classHeader.isCompatibleClassKind() -> out.write("\n------ class proto -----\n${DebugProtoBuf.Class.parseFrom(input, getExtensionRegistry())}") else -> throw IllegalStateException()