Report incompatible metadata version error correctly

Similarly to pre-release classes, load metadata for the class anyway and allow
the resolution to select it as the result and prohibit its usage in the end
with the special diagnostic reported in MissingDependencyClassChecker
This commit is contained in:
Alexander Udalov
2016-12-06 21:21:41 +03:00
parent d204fa91cc
commit b943ed26f3
20 changed files with 243 additions and 42 deletions
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
import org.jetbrains.kotlin.resolve.checkers.PlatformImplDeclarationChecker;
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData;
import org.jetbrains.kotlin.types.KotlinType;
import java.lang.reflect.Field;
@@ -83,6 +84,7 @@ public interface Errors {
DiagnosticFactory1<PsiElement, FqName> MISSING_DEPENDENCY_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, FqName> PRE_RELEASE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, FqName, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
//Elements with "INVISIBLE_REFERENCE" error are marked as unresolved, unlike elements with "INVISIBLE_MEMBER" error
//"INVISIBLE_REFERENCE" is used for invisible classes references and references in import
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.diagnostics.rendering;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.io.FileUtil;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,6 +32,7 @@ import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
import org.jetbrains.kotlin.psi.KtTypeConstraint;
import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.util.MappedExtensionProvider;
import org.jetbrains.kotlin.util.OperatorNameConventions;
@@ -321,6 +323,17 @@ public class DefaultErrorMessages {
MAP.put(MISSING_DEPENDENCY_CLASS, "Cannot access class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
MAP.put(PRE_RELEASE_CLASS, "Class ''{0}'' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler", TO_STRING);
MAP.put(INCOMPATIBLE_CLASS,
"Class ''{0}'' was compiled with an incompatible version of Kotlin. {1}",
TO_STRING, new DiagnosticParameterRenderer<IncompatibleVersionErrorData<?>>() {
@NotNull
@Override
public String render(@NotNull IncompatibleVersionErrorData<?> incompatibility, @NotNull RenderingContext renderingContext) {
return "The binary version of its metadata is " + incompatibility.getActualVersion() +
", expected version is " + incompatibility.getExpectedVersion() + ".\n" +
"The class is loaded from " + FileUtil.toSystemIndependentName(incompatibility.getFilePath());
}
});
MAP.put(LOCAL_OBJECT_NOT_ALLOWED, "Named object ''{0}'' is a singleton and cannot be local. Try to use anonymous object instead", NAME);
MAP.put(LOCAL_INTERFACE_NOT_ALLOWED, "''{0}'' is an interface so it cannot be local. Try to use anonymous object or abstract class instead", NAME);
@@ -23,8 +23,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors.MISSING_DEPENDENCY_CLASS
import org.jetbrains.kotlin.diagnostics.Errors.PRE_RELEASE_CLASS
import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
@@ -57,9 +56,15 @@ object MissingDependencyClassChecker : CallChecker {
}
private fun incompatibilityDiagnosticFor(source: SourceElement?, reportOn: PsiElement): Diagnostic? {
if (source is DeserializedContainerSource && source.isPreReleaseInvisible) {
// TODO: if at least one PRE_RELEASE_CLASS is reported, display a hint to disable the diagnostic
return PRE_RELEASE_CLASS.on(reportOn, source.presentableFqName)
if (source is DeserializedContainerSource) {
val incompatibility = source.incompatibility
if (incompatibility != null) {
return INCOMPATIBLE_CLASS.on(reportOn, source.presentableFqName, incompatibility)
}
if (source.isPreReleaseInvisible) {
// TODO: if at least one PRE_RELEASE_CLASS is reported, display a hint to disable the diagnostic
return PRE_RELEASE_CLASS.on(reportOn, source.presentableFqName)
}
}
return null
+4 -3
View File
@@ -1,11 +1,12 @@
compiler/testData/cli/jvm/wrongAbiVersion.kt:3:12: error: class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
The class is loaded from $TESTDATA_DIR$/wrongAbiVersionLib/bin/ClassWithWrongAbiVersion.class
fun foo(x: ClassWithWrongAbiVersion) {
^
compiler/testData/cli/jvm/wrongAbiVersion.kt:4:5: error: unresolved reference: bar
(note: this may be caused by the fact that some classes compiled with an incompatible version of Kotlin were found in the classpath. Such classes cannot be loaded properly by this version of Kotlin compiler. See below for more information)
bar()
^
compiler/testData/cli/jvm/wrongAbiVersion.kt:6:7: error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public fun String.replaceIndent(newIndent: String = ...): String defined in kotlin.text
(note: this may be caused by the fact that some classes compiled with an incompatible version of Kotlin were found in the classpath. Such classes cannot be loaded properly by this version of Kotlin compiler. See below for more information)
1.replaceIndent(2, 3)
^
compiler/testData/cli/jvm/wrongAbiVersionLib/bin/ClassWithWrongAbiVersion.class: error: class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$
COMPILATION_ERROR
+4 -1
View File
@@ -1,2 +1,5 @@
compiler/testData/cli/jvm/wrongAbiVersionLib/bin/wrong/ClassWithInnerLambda.class: error: class 'wrong/ClassWithInnerLambda' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$
compiler/testData/cli/jvm/wrongAbiVersionNoErrors.kt:3:14: error: class 'wrong.ClassWithInnerLambda' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
The class is loaded from $TESTDATA_DIR$/wrongAbiVersionLib/bin/wrong/ClassWithInnerLambda.class
import wrong.ClassWithInnerLambda
^
COMPILATION_ERROR
@@ -0,0 +1,11 @@
package a
open class A {
class Nested
fun method() {}
}
fun foo() {}
var bar = 42
typealias TA = String
@@ -0,0 +1,49 @@
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:5:16: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
fun baz(param: A, nested: A.Nested) {
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:5:27: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
fun baz(param: A, nested: A.Nested) {
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:5:29: error: class 'a.A.Nested' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A$Nested.class
fun baz(param: A, nested: A.Nested) {
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:6:23: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
val constructor = A()
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:7:18: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
val nested = A.Nested()
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:7:20: error: class 'a.A.Nested' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A$Nested.class
val nested = A.Nested()
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:8:22: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
val methodCall = param.method()
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:9:30: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
val supertype = object : A() {}
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:11:13: error: class 'a.AKt' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/AKt.class
val x = foo()
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:12:13: error: class 'a.AKt' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/AKt.class
val y = bar
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:13:5: error: class 'a.AKt' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/AKt.class
bar = 239
^
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:14:12: error: class 'a.AKt' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/AKt.class
val z: TA = ""
^
COMPILATION_ERROR
@@ -0,0 +1,15 @@
package usage
import a.*
fun baz(param: A, nested: A.Nested) {
val constructor = A()
val nested = A.Nested()
val methodCall = param.method()
val supertype = object : A() {}
val x = foo()
val y = bar
bar = 239
val z: TA = ""
}
@@ -0,0 +1,11 @@
package a
open class A {
class Nested
fun method() {}
}
fun foo() {}
var bar = 42
typealias TA = String
@@ -0,0 +1,16 @@
@file:Suppress("UNUSED_VARIABLE", "UNUSED_PARAMETER")
package usage
import a.*
fun baz(param: A, nested: A.Nested) {
val constructor = A()
val nested2 = A.Nested()
val methodCall = param.method()
val supertype = object : A() {}
val x = foo()
val y = bar
bar = 239
val z: TA = ""
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.cli;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import kotlin.Pair;
@@ -72,8 +73,10 @@ public abstract class AbstractCliTest extends TestCaseWithTmpdir {
@NotNull String testDataDir,
@NotNull BinaryVersion version
) {
String testDataAbsoluteDir = new File(testDataDir).getAbsolutePath();
String normalizedOutputWithoutExitCode = pureOutput
.replace(new File(testDataDir).getAbsolutePath(), "$TESTDATA_DIR$")
.replace(testDataAbsoluteDir, "$TESTDATA_DIR$")
.replace(FileUtil.toSystemIndependentName(testDataAbsoluteDir), "$TESTDATA_DIR$")
.replace(PathUtil.getKotlinPathsForDistDirectory().getHomePath().getAbsolutePath(), "$PROJECT_DIR$")
.replace("expected version is " + version, "expected version is $ABI_VERSION$")
.replace("\\", "/")
@@ -22,9 +22,11 @@ import com.intellij.openapi.util.io.FileUtil;
import kotlin.Pair;
import kotlin.collections.SetsKt;
import kotlin.io.FilesKt;
import kotlin.jvm.functions.Function2;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.cli.AbstractCliTest;
import org.jetbrains.kotlin.cli.WrongBytecodeVersionTest;
import org.jetbrains.kotlin.cli.common.ExitCode;
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport;
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer;
@@ -37,6 +39,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.config.KotlinCompilerVersion;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver;
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -92,7 +95,7 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
private String normalizeOutput(@NotNull Pair<String, ExitCode> output) {
return AbstractCliTest.getNormalizedCompilerOutput(
output.getFirst(), output.getSecond(), getTestDataDirectory().getPath(), JvmMetadataVersion.INSTANCE
);
).replace(FileUtil.toSystemIndependentName(tmpdir.getAbsolutePath()), "$TMP_DIR$");
}
private void doTestWithTxt(@NotNull File... extraClassPath) throws Exception {
@@ -134,6 +137,20 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
@NotNull
private static File copyJarFileWithoutEntry(@NotNull File jarPath, @NotNull String... entriesToDelete) {
return transformJar(jarPath, new Function2<String, byte[], byte[]>() {
@Override
public byte[] invoke(String s, byte[] bytes) {
return bytes;
}
}, entriesToDelete);
}
@NotNull
private static File transformJar(
@NotNull File jarPath,
@NotNull Function2<String, byte[], byte[]> transformEntry,
@NotNull String... entriesToDelete
) {
try {
File outputFile = new File(jarPath.getParentFile(), FileUtil.getNameWithoutExtension(jarPath) + "-after.jar");
Set<String> toDelete = SetsKt.setOf(entriesToDelete);
@@ -144,11 +161,16 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
try {
for (Enumeration<JarEntry> enumeration = jar.entries(); enumeration.hasMoreElements(); ) {
JarEntry jarEntry = enumeration.nextElement();
if (toDelete.contains(jarEntry.getName())) {
String name = jarEntry.getName();
if (toDelete.contains(name)) {
continue;
}
output.putNextEntry(jarEntry);
output.write(FileUtil.loadBytes(jar.getInputStream(jarEntry)));
byte[] bytes = FileUtil.loadBytes(jar.getInputStream(jarEntry));
byte[] newBytes = name.endsWith(".class") ? transformEntry.invoke(name, bytes) : bytes;
JarEntry newEntry = new JarEntry(name);
newEntry.setSize(newBytes.length);
output.putNextEntry(newEntry);
output.write(newBytes);
output.closeEntry();
}
}
@@ -228,6 +250,23 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
}
private void doTestKotlinLibraryWithWrongMetadataVersion(@NotNull String libraryName, @NotNull String... additionalOptions) throws Exception {
final int[] version = new JvmMetadataVersion(42, 0, 0).toArray();
File library = transformJar(compileLibrary(libraryName), new Function2<String, byte[], byte[]>() {
@Override
public byte[] invoke(String name, byte[] bytes) {
return WrongBytecodeVersionTest.Companion.transformMetadataInClassFile(bytes, new Function2<String, Object, Object>() {
@Override
public Object invoke(String name, Object value) {
return JvmAnnotationNames.METADATA_VERSION_FIELD_NAME.equals(name) ? version : null;
}
});
}
});
Pair<String, ExitCode> output = compileKotlin("source.kt", tmpdir, Arrays.asList(additionalOptions), library);
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
}
@SuppressWarnings("deprecation")
private void doTestPreReleaseKotlinLibrary(@NotNull String libraryName, @NotNull String... additionalOptions) throws Exception {
// Compiles the library with the "pre-release" flag, then compiles a usage of this library in the release mode
@@ -377,6 +416,17 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
}
*/
public void testWrongMetadataVersion() throws Exception {
doTestKotlinLibraryWithWrongMetadataVersion("library");
}
/*
// TODO: refactor and uncomment
public void testWrongMetadataVersionSkipVersionCheck() throws Exception {
doTestKotlinLibraryWithWrongMetadataVersion("library", "-Xskip-metadata-version-check");
}
*/
/*test source mapping generation when source info is absent*/
public void testInlineFunWithoutDebugInfo() throws Exception {
compileKotlin("sourceInline.kt", tmpdir);
@@ -99,25 +99,20 @@ class LazyJavaPackageScope(
object SyntheticClass : KotlinClassLookupResult()
}
private fun resolveKotlinBinaryClass(kotlinClass: KotlinJvmBinaryClass?): KotlinClassLookupResult {
if (kotlinClass == null) return KotlinClassLookupResult.NotFound
val header = kotlinClass.classHeader
return when {
!header.metadataVersion.isCompatible() -> {
c.components.errorReporter.reportIncompatibleMetadataVersion(kotlinClass.classId, kotlinClass.location, header.metadataVersion)
KotlinClassLookupResult.NotFound
private fun resolveKotlinBinaryClass(kotlinClass: KotlinJvmBinaryClass?): KotlinClassLookupResult =
when {
kotlinClass == null -> {
KotlinClassLookupResult.NotFound
}
kotlinClass.classHeader.kind == KotlinClassHeader.Kind.CLASS -> {
val descriptor = c.components.deserializedDescriptorResolver.resolveClass(kotlinClass)
if (descriptor != null) KotlinClassLookupResult.Found(descriptor) else KotlinClassLookupResult.NotFound
}
else -> {
// This is a package or interface DefaultImpls or something like that
KotlinClassLookupResult.SyntheticClass
}
}
header.kind == KotlinClassHeader.Kind.CLASS -> {
val descriptor = c.components.deserializedDescriptorResolver.resolveClass(kotlinClass)
if (descriptor != null) KotlinClassLookupResult.Found(descriptor) else KotlinClassLookupResult.NotFound
}
else -> {
// This is a package or interface DefaultImpls or something like that
KotlinClassLookupResult.SyntheticClass
}
}
}
// javaClass here is only for sake of optimizations
private class FindClassRequest(val name: Name, val javaClass: JavaClass?) {
@@ -25,8 +25,10 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.ClassDataWithSource
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
import org.jetbrains.kotlin.utils.addToStdlib.check
import org.jetbrains.kotlin.utils.sure
import javax.inject.Inject
@@ -50,7 +52,11 @@ class DeserializedDescriptorResolver(private val errorReporter: ErrorReporter) {
val classData = parseProto(kotlinClass) {
JvmProtoBufUtil.readClassDataFrom(data, strings)
}
val sourceElement = KotlinJvmBinarySourceElement(kotlinClass, !IS_PRE_RELEASE && kotlinClass.classHeader.isPreRelease)
val sourceElement = KotlinJvmBinarySourceElement(
kotlinClass,
kotlinClass.incompatibility,
!IS_PRE_RELEASE && kotlinClass.classHeader.isPreRelease
)
return ClassDataWithSource(classData, sourceElement)
}
@@ -62,6 +68,7 @@ class DeserializedDescriptorResolver(private val errorReporter: ErrorReporter) {
}
val source = JvmPackagePartSource(
kotlinClass,
kotlinClass.incompatibility,
isPreReleaseInvisible = !IS_PRE_RELEASE && kotlinClass.classHeader.isPreRelease
)
return DeserializedPackageMemberScope(descriptor, packageProto, nameResolver, source, components) {
@@ -70,16 +77,15 @@ class DeserializedDescriptorResolver(private val errorReporter: ErrorReporter) {
}
}
private fun readData(kotlinClass: KotlinJvmBinaryClass, expectedKinds: Set<KotlinClassHeader.Kind>): Array<String>? {
val header = kotlinClass.classHeader
if (!header.metadataVersion.isCompatible()) {
errorReporter.reportIncompatibleMetadataVersion(kotlinClass.classId, kotlinClass.location, header.metadataVersion)
}
else if (expectedKinds.contains(header.kind)) {
return header.data
private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>?
get() {
if (classHeader.metadataVersion.isCompatible()) return null
return IncompatibleVersionErrorData(classHeader.metadataVersion, JvmMetadataVersion.INSTANCE, location, classId)
}
return null
internal fun readData(kotlinClass: KotlinJvmBinaryClass, expectedKinds: Set<KotlinClassHeader.Kind>): Array<String>? {
val header = kotlinClass.classHeader
return (header.data ?: header.incompatibleData)?.check { header.kind in expectedKinds }
}
private inline fun <T> parseProto(klass: KotlinJvmBinaryClass, block: () -> T): T {
@@ -21,18 +21,25 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
class JvmPackagePartSource(
val className: JvmClassName,
val facadeClassName: JvmClassName?,
override val incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? = null,
override val isPreReleaseInvisible: Boolean = false
) : DeserializedContainerSource {
constructor(kotlinClass: KotlinJvmBinaryClass, isPreReleaseInvisible: Boolean = false) : this(
constructor(
kotlinClass: KotlinJvmBinaryClass,
incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? = null,
isPreReleaseInvisible: Boolean = false
) : this(
JvmClassName.byClassId(kotlinClass.classId),
kotlinClass.classHeader.multifileClassName?.let {
if (it.isNotEmpty()) JvmClassName.byInternalName(it) else null
},
incompatibility,
isPreReleaseInvisible
)
@@ -18,10 +18,12 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
class KotlinJvmBinarySourceElement(
val binaryClass: KotlinJvmBinaryClass,
override val incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? = null,
override val isPreReleaseInvisible: Boolean = false
) : DeserializedContainerSource {
override val presentableFqName: FqName
@@ -27,6 +27,7 @@ class KotlinClassHeader(
val metadataVersion: JvmMetadataVersion,
val bytecodeVersion: JvmBytecodeBinaryVersion,
val data: Array<String>?,
val incompatibleData: Array<String>?,
val strings: Array<String>?,
val extraString: String?,
val extraInt: Int
@@ -54,6 +54,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
private int extraInt = 0;
private String[] data = null;
private String[] strings = null;
private String[] incompatibleData = null;
private KotlinClassHeader.Kind headerKind = null;
@Nullable
@@ -62,6 +63,10 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
return null;
}
if (!metadataVersion.isCompatible()) {
incompatibleData = data;
}
if (metadataVersion == null || !metadataVersion.isCompatible()) {
data = null;
}
@@ -76,6 +81,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION,
bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION,
data,
incompatibleData,
strings,
extraString,
extraInt
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.types.SimpleType
@@ -43,6 +44,9 @@ interface DeserializedMemberDescriptor : MemberDescriptor {
}
interface DeserializedContainerSource : SourceElement {
// Non-null if this container is loaded from a class with an incompatible binary version
val incompatibility: IncompatibleVersionErrorData<*>?
// True iff this is container is "invisible" because it's loaded from a pre-release class and this compiler is a release
val isPreReleaseInvisible: Boolean