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
This commit is contained in:
Leonid Startsev
2019-07-16 14:54:19 +03:00
parent 822b4556e3
commit 6494227c64
@@ -27,22 +27,37 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
private val primaryConstructorParameters: List<ValueParameterDescriptor> = private val primaryConstructorParameters: List<ValueParameterDescriptor> =
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList() serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean> = val serializableProperties: List<SerializableProperty>
primaryConstructorParameters.asSequence() val isExternallySerializable: Boolean
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() } private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean>
.mapNotNull { (a, b) -> if (a == null) null else a to b }
.toMap()
val isExternallySerializable: Boolean =
primaryConstructorParameters.size == primaryConstructorProperties.size
val serializableProperties: List<SerializableProperty> = init {
serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) val descriptorsSequence = serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.asSequence() .asSequence()
.filterIsInstance<PropertyDescriptor>() // 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<PropertyDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION } .filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
.filter(this::isPropSerializable) .filter(::isPropSerializable)
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false, prop.hasBackingField(bindingContext)) } .map { prop ->
SerializableProperty(
prop,
primaryConstructorProperties[prop] ?: false,
prop.hasBackingField(bindingContext)
)
}
.filterNot { it.transient } .filterNot { it.transient }
.partition { primaryConstructorProperties.contains(it.descriptor) } .partition { primaryConstructorProperties.contains(it.descriptor) }
.run { .run {
@@ -52,12 +67,8 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
else else
SerializableProperties(supers, bindingContext).serializableProperties + first + second SerializableProperties(supers, bindingContext).serializableProperties + first + second
} }
isExternallySerializable = primaryConstructorParameters.size == primaryConstructorProperties.size
private fun isPropSerializable(it: PropertyDescriptor) = }
if (serializableClass.isInternalSerializable) !it.annotations.serialTransient
else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(
it
))
val serializableConstructorProperties: List<SerializableProperty> = val serializableConstructorProperties: List<SerializableProperty> =
serializableProperties.asSequence() serializableProperties.asSequence()
@@ -79,4 +90,4 @@ internal fun List<SerializableProperty>.bitMaskSlotCount() = size / 32 + 1
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32 internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties = internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties =
this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this) this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)