From 6494227c6441309d441613349a6e1438ce234cdb Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Tue, 16 Jul 2019 14:54:19 +0300 Subject: [PATCH] Change order in SerializableProperties initialization logic in that way so binding context would be checked only after resolve is triggered (via .getContributed descriptors). Empty binding context led to some subtle bugs. Fixes https://github.com/Kotlin/kotlinx.serialization/issues/508 --- .../resolve/SerializableProperties.kt | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt index 8ac8d35a2b5..459903200bc 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt @@ -27,22 +27,37 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val private val primaryConstructorParameters: List = serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList() - private val primaryConstructorProperties: Map = - primaryConstructorParameters.asSequence() - .map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() } - .mapNotNull { (a, b) -> if (a == null) null else a to b } - .toMap() + val serializableProperties: List + val isExternallySerializable: Boolean + private val primaryConstructorProperties: Map - val isExternallySerializable: Boolean = - primaryConstructorParameters.size == primaryConstructorProperties.size - val serializableProperties: List = - serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) + init { + val descriptorsSequence = serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) .asSequence() - .filterIsInstance() + // call to any BindingContext.get should be only AFTER MemberScope.getContributedDescriptors + primaryConstructorProperties = + primaryConstructorParameters.asSequence() + .map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() } + .mapNotNull { (a, b) -> if (a == null) null else a to b } + .toMap() + + fun isPropSerializable(it: PropertyDescriptor) = + if (serializableClass.isInternalSerializable) !it.annotations.serialTransient + else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains( + it + )) + + serializableProperties = descriptorsSequence.filterIsInstance() .filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION } - .filter(this::isPropSerializable) - .map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false, prop.hasBackingField(bindingContext)) } + .filter(::isPropSerializable) + .map { prop -> + SerializableProperty( + prop, + primaryConstructorProperties[prop] ?: false, + prop.hasBackingField(bindingContext) + ) + } .filterNot { it.transient } .partition { primaryConstructorProperties.contains(it.descriptor) } .run { @@ -52,12 +67,8 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val else SerializableProperties(supers, bindingContext).serializableProperties + first + second } - - private fun isPropSerializable(it: PropertyDescriptor) = - if (serializableClass.isInternalSerializable) !it.annotations.serialTransient - else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains( - it - )) + isExternallySerializable = primaryConstructorParameters.size == primaryConstructorProperties.size + } val serializableConstructorProperties: List = serializableProperties.asSequence() @@ -79,4 +90,4 @@ internal fun List.bitMaskSlotCount() = size / 32 + 1 internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32 internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties = - this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this) \ No newline at end of file + this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)