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
@@ -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