From 9552accaec233b03363d2896ec4000970791a365 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 28 Dec 2015 16:39:17 +0300 Subject: [PATCH] Introduce BinaryVersion.isCompatible() To decrease the chance to mix up the receiver and the first argument when checking version compatibility --- .../KotlinSyntheticClassAnnotationTest.java | 3 +- .../utils/KotlinJavascriptMetadataUtils.kt | 2 ++ .../kotlin/load/java/AbiVersionUtil.java | 29 ------------------- .../load/java/JvmBytecodeBinaryVersion.kt | 2 ++ .../kotlin/load/java/lazy/resolvers.kt | 2 +- .../DeserializedDescriptorResolver.java | 2 +- .../kotlin/load/kotlin/ModuleMapping.kt | 3 +- .../load/kotlin/header/KotlinClassHeader.kt | 11 +++---- ...eadKotlinClassHeaderAnnotationVisitor.java | 3 +- .../kotlin/builtins/BuiltInsBinaryVersion.kt | 2 ++ .../builtins/BuiltinsPackageFragment.kt | 2 +- .../deserialization/BinaryVersion.kt | 4 ++- .../classFile/ClassFileDecompilerUtil.kt | 4 +-- .../classFile/KotlinClassFileDecompiler.kt | 4 +-- .../classFile/KotlinClsStubBuilder.kt | 2 +- .../kotlin/idea/vfilefinder/fileIndexes.kt | 4 +-- .../versions/KotlinRuntimeLibraryUtil.java | 8 +++-- 17 files changed, 31 insertions(+), 56 deletions(-) delete mode 100644 core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java b/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java index 729d4f4dfd0..2c5fbba49e4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java @@ -20,7 +20,6 @@ import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.backend.common.output.OutputFile; -import org.jetbrains.kotlin.load.java.AbiVersionUtil; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion; import org.jetbrains.kotlin.name.FqName; @@ -147,6 +146,6 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { int[] version = (int[]) CodegenTestUtil.getAnnotationAttribute(annotation, VERSION_FIELD_NAME); assertNotNull(version); assertTrue("Annotation " + annotationFqName + " is written with an unsupported format", - AbiVersionUtil.isAbiVersionCompatible(JvmBytecodeBinaryVersion.create(version))); + JvmBytecodeBinaryVersion.create(version).isCompatible()); } } diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt index a531b1baaae..6d974e6fe1c 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt @@ -29,6 +29,8 @@ class KotlinJavascriptMetadata(val abiVersion: Int, val moduleName: String, val class JsBinaryVersion 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(0, 3, 0) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java deleted file mode 100644 index 7b776aad961..00000000000 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.java; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; - -public final class AbiVersionUtil { - public static boolean isAbiVersionCompatible(@NotNull BinaryVersion actual) { - return actual.isCompatibleTo(JvmBytecodeBinaryVersion.INSTANCE); - } - - private AbiVersionUtil() { - } -} 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 753eb8c8e17..1773a963b48 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 @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion class JvmBytecodeBinaryVersion 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) 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 ea43a55df2b..cab83407cd1 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,7 +70,7 @@ fun LazyJavaResolverContext.resolveKotlinBinaryClass(kotlinClass: KotlinJvmBinar val header = kotlinClass.classHeader return when { - !header.isCompatibleAbiVersion -> { + !header.version.isCompatible() -> { components.errorReporter.reportIncompatibleAbiVersion(kotlinClass.classId, kotlinClass.location, header.version) KotlinClassLookupResult.NotFound } 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 3eb5bc96591..229ce8d2025 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,7 +115,7 @@ public final class DeserializedDescriptorResolver { @Nullable public String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @NotNull Set expectedKinds) { KotlinClassHeader header = kotlinClass.getClassHeader(); - if (!header.isCompatibleAbiVersion()) { + if (!header.getVersion().isCompatible()) { errorReporter.reportIncompatibleAbiVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getVersion()); } else if (expectedKinds.contains(header.getKind())) { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt index 04f8381a9d1..82cb85604fa 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.load.kotlin -import org.jetbrains.kotlin.load.java.AbiVersionUtil import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable import java.io.ByteArrayInputStream @@ -43,7 +42,7 @@ class ModuleMapping private constructor(val packageFqName2Parts: Map() 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 6747d7c01ad..503093a3f4f 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,7 +16,6 @@ package org.jetbrains.kotlin.load.kotlin.header -import org.jetbrains.kotlin.load.java.AbiVersionUtil import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion class KotlinClassHeader( @@ -30,8 +29,6 @@ class KotlinClassHeader( val isInterfaceDefaultImpls: Boolean, val isLocalClass: Boolean ) { - val isCompatibleAbiVersion: Boolean get() = AbiVersionUtil.isAbiVersionCompatible(version) - enum class Kind { CLASS, FILE_FACADE, @@ -47,7 +44,7 @@ class KotlinClassHeader( "version=$version" } -fun KotlinClassHeader.isCompatibleClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.CLASS -fun KotlinClassHeader.isCompatibleFileFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.FILE_FACADE -fun KotlinClassHeader.isCompatibleMultifileClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS -fun KotlinClassHeader.isCompatibleMultifileClassPartKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART +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 3683c84a831..73112e0fccf 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 @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.load.kotlin.header; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.SourceElement; -import org.jetbrains.kotlin.load.java.AbiVersionUtil; import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; @@ -62,7 +61,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor return null; } - if (!AbiVersionUtil.isAbiVersionCompatible(version)) { + if (!version.isCompatible()) { annotationData = null; } else if (shouldHaveData() && annotationData == null) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt index c91efe50f4c..65357cff748 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt @@ -25,6 +25,8 @@ import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion class BuiltInsBinaryVersion 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, 0) diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt index 4ef79355bb8..d35bd53d16e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt @@ -38,7 +38,7 @@ class BuiltinsPackageFragment( val dataInput = DataInputStream(stream) val version = BuiltInsBinaryVersion.create((1..dataInput.readInt()).map { dataInput.readInt() }.toIntArray()) - if (!version.isCompatibleTo(BuiltInsBinaryVersion.INSTANCE)) { + if (!version.isCompatible()) { // TODO: report a proper diagnostic throw UnsupportedOperationException( "Kotlin built-in definition format version is not supported: " + diff --git a/core/util.runtime/src/org/jetbrains/kotlin/serialization/deserialization/BinaryVersion.kt b/core/util.runtime/src/org/jetbrains/kotlin/serialization/deserialization/BinaryVersion.kt index 1d71a17c44b..21d2e37c670 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/serialization/deserialization/BinaryVersion.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/serialization/deserialization/BinaryVersion.kt @@ -31,6 +31,8 @@ abstract class BinaryVersion protected constructor( val patch: Int, val rest: List ) { + abstract fun isCompatible(): Boolean + fun toArray(): IntArray = intArrayOf(major, minor, patch, *rest.toIntArray()) @@ -40,7 +42,7 @@ abstract class BinaryVersion protected constructor( * * @param ourVersion the version of this format in the current compiler */ - fun isCompatibleTo(ourVersion: BinaryVersion): Boolean { + protected fun isCompatibleTo(ourVersion: BinaryVersion): Boolean { return if (major == 0) ourVersion.major == 0 && minor == ourVersion.minor else major == ourVersion.major && minor <= ourVersion.minor } 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 fc5ff120c0b..f0e383dac5a 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 @@ -53,8 +53,8 @@ fun isKotlinJvmCompiledFile(file: VirtualFile): Boolean { fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean { if (!isKotlinJvmCompiledFile(file)) return false - val header = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)?.classHeader - return header != null && header.isCompatibleAbiVersion + val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file) + return kotlinClass != null && kotlinClass.classHeader.version.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 cbeb3088db5..379a9c1f299 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 @@ -86,7 +86,7 @@ fun buildDecompiledTextForClassFile( val packageFqName = classId.packageFqName return when { - !classHeader.isCompatibleAbiVersion -> { + !classHeader.version.isCompatible() -> { DecompiledText( INCOMPATIBLE_ABI_VERSION_COMMENT .replace(CURRENT_ABI_VERSION_MARKER, JvmBytecodeBinaryVersion.INSTANCE.toString()) @@ -103,6 +103,6 @@ fun buildDecompiledTextForClassFile( buildDecompiledText(packageFqName, partMembers, decompilerRendererForClassFiles) } else -> - throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.isCompatibleAbiVersion}") + throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.version.isCompatible()}") } } 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 50c8c2ba65d..d9701de9632 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 @@ -62,7 +62,7 @@ open class KotlinClsStubBuilder : ClsStubBuilder() { val header = kotlinClassHeaderInfo.classHeader val classId = kotlinClassHeaderInfo.classId val packageFqName = classId.packageFqName - if (!header.isCompatibleAbiVersion) { + if (!header.version.isCompatible()) { return createIncompatibleAbiVersionFileStub() } 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 d83ec870a38..54ac1645835 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 @@ -78,8 +78,8 @@ object KotlinClassFileIndex : KotlinFileIndexBase(KotlinCl private val VERSION = 2 private val INDEXER = indexer() { fileContent -> - val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(fileContent.file, fileContent.content) - if (kotlinClassHeaderInfo != null && kotlinClassHeaderInfo.classHeader.isCompatibleAbiVersion) kotlinClassHeaderInfo.classId.asSingleFqName() else null + val headerInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(fileContent.file, fileContent.content) + if (headerInfo != null && headerInfo.classHeader.version.isCompatible()) headerInfo.classId.asSingleFqName() else null } } diff --git a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java index 8e603bc6fcc..9248364cef5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java +++ b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java @@ -21,7 +21,10 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -46,7 +49,6 @@ import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider; import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider; import org.jetbrains.kotlin.idea.framework.LibraryPresentationProviderUtil; import org.jetbrains.kotlin.idea.project.ProjectStructureUtil; -import org.jetbrains.kotlin.load.java.AbiVersionUtil; import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils; import org.jetbrains.kotlin.utils.KotlinPaths; @@ -77,7 +79,7 @@ public class KotlinRuntimeLibraryUtil { new Function1() { @Override public Boolean invoke(@NotNull BinaryVersion version) { - return !AbiVersionUtil.isAbiVersionCompatible(version); + return !version.isCompatible(); } }); }