Do not fail when deserializing incompatible metadata

Catch all exceptions when deserializing metadata with an incompatible version
to prevent the compiler from failing on discovering incompatible classes on the
classpath. Note that this is not the perfect solution: any invariant may be
broken in the incompatible metadata and it may result in a later exception
This commit is contained in:
Alexander Udalov
2016-12-07 21:30:26 +03:00
parent 789483e1eb
commit 830d2f6603
9 changed files with 172 additions and 12 deletions
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErr
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
class DeserializedDescriptorResolver {
@@ -47,10 +46,10 @@ class DeserializedDescriptorResolver {
internal fun readClassData(kotlinClass: KotlinJvmBinaryClass): ClassDataWithSource? {
val data = readData(kotlinClass, KOTLIN_CLASS) ?: return null
val strings = kotlinClass.classHeader.strings.sure { "String table not found in $kotlinClass" }
val strings = kotlinClass.classHeader.strings ?: return null
val classData = parseProto(kotlinClass) {
JvmProtoBufUtil.readClassDataFrom(data, strings)
}
} ?: return null
val sourceElement = KotlinJvmBinarySourceElement(
kotlinClass,
kotlinClass.incompatibility,
@@ -61,10 +60,10 @@ class DeserializedDescriptorResolver {
fun createKotlinPackagePartScope(descriptor: PackageFragmentDescriptor, kotlinClass: KotlinJvmBinaryClass): MemberScope? {
val data = readData(kotlinClass, KOTLIN_FILE_FACADE_OR_MULTIFILE_CLASS_PART) ?: return null
val strings = kotlinClass.classHeader.strings.sure { "String table not found in $kotlinClass" }
val strings = kotlinClass.classHeader.strings ?: return null
val (nameResolver, packageProto) = parseProto(kotlinClass) {
JvmProtoBufUtil.readPackageDataFrom(data, strings)
}
} ?: return null
val source = JvmPackagePartSource(
kotlinClass,
kotlinClass.incompatibility,
@@ -87,12 +86,21 @@ class DeserializedDescriptorResolver {
return (header.data ?: header.incompatibleData)?.check { header.kind in expectedKinds }
}
private inline fun <T> parseProto(klass: KotlinJvmBinaryClass, block: () -> T): T {
private inline fun <T : Any> parseProto(klass: KotlinJvmBinaryClass, block: () -> T): T? {
try {
return block()
try {
return block()
}
catch (e: InvalidProtocolBufferException) {
throw IllegalStateException("Could not read data from ${klass.location}", e)
}
}
catch (e: InvalidProtocolBufferException) {
throw IllegalStateException("Could not read data from ${klass.location}", e)
catch (e: Throwable) {
if (!klass.classHeader.metadataVersion.isCompatible()) {
// TODO: log.warn
return null
}
throw e
}
}