From 8a250b07df0b6bdbc4820a7b0794d1aabecbf0ea Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Thu, 21 Sep 2017 16:22:00 +0300 Subject: [PATCH] Default case in "load" switch-case throws exception instead of silent read ending. Improved error descriptions, fixed issue with transient properties without backing field (Kotlin/kotlinx.serialization#2) Don't add serialClassDesc property if user already defined one (Kotlin/kotlinx.serialization#10) Bump version to 0.1.1 Fix issue with mixing serial name with real property name (Kotlin/kotlinx.serialization#13) --- .../tools/kotlin-maven-serialization/pom.xml | 2 +- .../tools/kotlin-serialization/build.gradle | 2 +- .../backend/common/SerializerCodegen.kt | 4 ++-- .../backend/js/SerializerJsTranslator.kt | 20 +++++++++---------- .../compiler/backend/jvm/JVMCodegenUtil.kt | 1 + .../backend/jvm/SerializableCodegenImpl.kt | 13 ++++++++++-- .../backend/jvm/SerializerCodegenImpl.kt | 13 ++++++++++-- .../compiler/resolve/KSerializationUtil.kt | 5 +++-- .../resolve/KSerializerDescriptorResolver.kt | 8 ++++---- 9 files changed, 44 insertions(+), 24 deletions(-) diff --git a/libraries/tools/kotlin-maven-serialization/pom.xml b/libraries/tools/kotlin-maven-serialization/pom.xml index 4dc8161e81f..a3bbcc61ed8 100755 --- a/libraries/tools/kotlin-maven-serialization/pom.xml +++ b/libraries/tools/kotlin-maven-serialization/pom.xml @@ -17,7 +17,7 @@ org.jetbrains.kotlinx kotlinx-maven-serialization-plugin jar - 0.1 + 0.1.1 Serialization plugin for Maven diff --git a/libraries/tools/kotlin-serialization/build.gradle b/libraries/tools/kotlin-serialization/build.gradle index 62056d168a5..bcb8b3fbaf6 100644 --- a/libraries/tools/kotlin-serialization/build.gradle +++ b/libraries/tools/kotlin-serialization/build.gradle @@ -3,7 +3,7 @@ plugins { } group = 'org.jetbrains.kotlinx' -version = '0.1' +version = '0.1.1' apply plugin: 'kotlin' diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt index 2d85f0c6314..33e7d557212 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt @@ -80,13 +80,13 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex fun getPropertyToGenerate( classDescriptor: ClassDescriptor, name: String, - isReturnTypeOk: (KotlinType) -> Boolean + isReturnTypeOk: (PropertyDescriptor) -> Boolean ): PropertyDescriptor? = classDescriptor.unsubstitutedMemberScope.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BACKEND) .singleOrNull { property -> property.kind.let { kind -> kind == CallableMemberDescriptor.Kind.SYNTHESIZED || kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } && property.modality != Modality.FINAL && property.returnType != null && - isReturnTypeOk(property.returnType!!) + isReturnTypeOk(property) } } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt index 01ba9362d15..98385cc2370 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt @@ -272,20 +272,20 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, bitMasks[i / 32], JsIntLiteral(bitPos) ).makeStmt() - // if (!readAll) break -- but only if this is last prop - if (i != orderedProperties.lastIndex) - +JsIf(JsAstUtils.not(readAllVar), JsBreak()) - else { - // if (readAll) breakLoop else break - +JsIf(readAllVar, JsBreak(loopRef), JsBreak()) - } + // if (!readAll) break + +JsIf(JsAstUtils.not(readAllVar), JsBreak()) } } - // case -1, default: break loop - case(JsIntLiteral(-1)) {} - default { + // case -1: break loop + case(JsIntLiteral(-1)) { +JsBreak(loopRef) } + // default: throw + default { + val excClassRef = serializableDescriptor.getClassFromSerializationPackage("UnknownFieldException") + .let { context.getQualifiedReference(it) } + +JsThrow(JsNew(excClassRef, listOf(indexVar))) + } } }, loop) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt index 49fa38c9d80..338432f00c9 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt @@ -51,6 +51,7 @@ internal val kSerializerArrayType = Type.getObjectType("[Lkotlinx/serialization/ internal val serializationExceptionName = "kotlinx/serialization/SerializationException" internal val serializationExceptionMissingFieldName = "kotlinx/serialization/MissingFieldException" +internal val serializationExceptionUnknownIndexName = "kotlinx/serialization/UnknownFieldException" val OPT_MASK_TYPE: Type = Type.INT_TYPE val OPT_MASK_BITS = 32 diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt index 45d861a3bd0..d863e95562f 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen @@ -140,6 +141,8 @@ class SerializableCodegenImpl( goTo(nextLabel) visitLabel(setLbl) // setting defaultValue + if (classCodegen.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, prop.descriptor] != true) + throw CompilationException("Optional properties without backing fields doesn't have much sense, maybe you want transient?", null, getProp(prop)) exprCodegen.genInitProperty(prop) visitLabel(nextLabel) } @@ -150,6 +153,7 @@ class SerializableCodegenImpl( val serializedProps = properties.serializableProperties.map { it.descriptor } (descToProps - serializedProps) + .filter { classCodegen.shouldInitializeProperty(it.value) } .forEach { (_, prop) -> classCodegen.initializeProperty(exprCodegen, prop) } (paramsToProps - serializedProps) .forEach { (t, u) -> exprCodegen.genInitParam(t, u) } @@ -168,7 +172,8 @@ class SerializableCodegenImpl( load(0, thisAsmType) if (!superClass.isInternalSerializable) { - require(superClass.constructors.firstOrNull { it.valueParameters.isEmpty() } != null) { "Non-serializable parent of serializable class must have no arg constructor" } + require(superClass.constructors.firstOrNull { it.valueParameters.isEmpty() } != null, + { "Non-serializable parent of serializable $serializableDescriptor must have no arg constructor" }) // call invokespecial(superType, "", "()V", false) @@ -191,14 +196,18 @@ class SerializableCodegenImpl( } ?: getParam(prop)?.let { this.v.load(0, thisAsmType) + if (!it.hasDefaultValue()) throw CompilationException("Optional field ${it.name} in primary constructor of serializable " + + "$serializableDescriptor must have default value", null, it) this.gen(it.defaultValue, prop.asmType) - this.v.putfield(thisAsmType.internalName, prop.name, prop.asmType.descriptor) + this.v.putfield(thisAsmType.internalName, prop.descriptor.name.asString(), prop.asmType.descriptor) } ?: throw IllegalStateException() private fun ExpressionCodegen.genInitParam(prop: PropertyDescriptor, param: KtParameter) { this.v.load(0, thisAsmType) val mapType = classCodegen.typeMapper.mapType(prop.type) + if (!param.hasDefaultValue()) throw CompilationException("Transient field ${param.name} in primary constructor of serializable " + + "$serializableDescriptor must have default value", null, param) this.gen(param.defaultValue, mapType) this.v.putfield(thisAsmType.internalName, prop.name.asString(), mapType.descriptor) } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt index b09058942d8..82cc23630ac 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt @@ -210,6 +210,7 @@ class SerializerCodegenImpl( val labeledProperties = orderedProperties.filter { !it.transient } val readAllLabel = Label() val readEndLabel = Label() + val incorrectIndLabel = Label() val labels = arrayOfNulls