[FIR] Save information about SerializationPluginMetadataExtensions in the property attribute

K1 implementation of kotlinx.serialization used SerializationPluginMetadataExtensions
  for two purposes:
- to extract the source-order of properties
- to identify which properties are actually serializable

In K2, the first point is covered by the compiler itself (as it correctly orders
  properties during deserialization), and to cover the second point we
  need to save in the propery information if it was mentioned in this extension
  or not

KT-64312
This commit is contained in:
Dmitriy Novozhilov
2024-01-03 12:00:59 +02:00
committed by Space Team
parent 5208b3c024
commit 717d1c774b
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeTypeProjection
@@ -142,9 +143,14 @@ fun deserializeClassToSymbol(
}
)
val propertiesOrderFromExtension = classProto.getPropertyOrderFromMetadataExtension()
addDeclarations(
classProto.propertiesInOrder(versionRequirements).map {
classDeserializer.loadProperty(it, classProto, symbol)
classProto.propertiesInOrder(versionRequirements, propertiesOrderFromExtension).map { propertyProto ->
classDeserializer.loadProperty(propertyProto, classProto, symbol).also { property ->
if (propertyProto.name in propertiesOrderFromExtension) {
property.registeredInSerializationPluginMetadataExtension = true
}
}
}
)
@@ -299,21 +305,33 @@ fun FirRegularClassBuilder.addCloneForArrayIfNeeded(classId: ClassId, dispatchRe
}
}
private fun ProtoBuf.ClassOrBuilder.propertiesInOrder(versionRequirements: List<VersionRequirement>): List<ProtoBuf.Property> {
private fun ProtoBuf.ClassOrBuilder.getPropertyOrderFromMetadataExtension(): Set<Int> {
return getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder).toSet()
}
private fun ProtoBuf.ClassOrBuilder.propertiesInOrder(
versionRequirements: List<VersionRequirement>,
orderFromExtension: Set<Int>,
): List<ProtoBuf.Property> {
val properties = propertyList
if (versionRequirements.any { it.version.major >= 2 }) return properties
val order = getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder)
.takeIf { it.isNotEmpty() }
?.toSet()
?: return properties
if (orderFromExtension.isEmpty()) return properties
val propertiesByName = properties.groupBy { it.name }
val orderedProperties = order.flatMap { propertiesByName[it] ?: emptyList() }
val orderedProperties = orderFromExtension.flatMap { propertiesByName[it] ?: emptyList() }
// non-serializable properties are not saved in SerializationPluginMetadataExtensions, so we need to pick up them if any
return if (orderedProperties.size == properties.size) {
orderedProperties
} else {
orderedProperties + properties.filter { it.name !in order }
orderedProperties + properties.filter { it.name !in orderFromExtension }
}
}
val FirSession.deserializationExtension: FirDeserializationExtension? by FirSession.nullableSessionComponentAccessor()
private object RegisteredInSerializationPluginMetadataExtensionKey : FirDeclarationDataKey()
private var FirProperty.registeredInSerializationPluginMetadataExtension: Boolean?
by FirDeclarationDataRegistry.data(RegisteredInSerializationPluginMetadataExtensionKey)
val FirPropertySymbol.registeredInSerializationPluginMetadataExtension: Boolean
get() = fir.registeredInSerializationPluginMetadataExtension ?: false