Support serializable objects in FIR plugin
This commit is contained in:
+6
-8
@@ -132,8 +132,10 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
@OptIn(SymbolInternals::class)
|
||||
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
|
||||
val owner = context?.owner ?: return emptyList()
|
||||
if (owner.name == SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT && callableId.callableName == SerialEntityNames.SERIALIZER_PROVIDER_NAME)
|
||||
return listOf(generateSerializerGetterInCompanion(owner, callableId))
|
||||
if (callableId.callableName == SerialEntityNames.SERIALIZER_PROVIDER_NAME) {
|
||||
val serializableClass = session.getSerializableClassDescriptorByCompanion(owner) ?: return emptyList()
|
||||
return listOf(generateSerializerGetterInCompanion(owner, serializableClass, callableId))
|
||||
}
|
||||
if (owner.name != SerialEntityNames.SERIALIZER_CLASS_NAME) return emptyList()
|
||||
if (callableId.callableName !in setOf(
|
||||
SpecialNames.INIT,
|
||||
@@ -154,7 +156,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
return listOf(copy.symbol)
|
||||
}
|
||||
|
||||
private fun generateSerializerGetterInCompanion(owner: FirClassSymbol<*>, callableId: CallableId): FirNamedFunctionSymbol {
|
||||
private fun generateSerializerGetterInCompanion(owner: FirClassSymbol<*>, serializableClassSymbol: FirClassSymbol<*>, callableId: CallableId): FirNamedFunctionSymbol {
|
||||
val f = buildSimpleFunction {
|
||||
moduleData = session.moduleData
|
||||
symbol = FirNamedFunctionSymbol(callableId)
|
||||
@@ -167,10 +169,6 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
name = callableId.callableName
|
||||
dispatchReceiverType = owner.defaultType()
|
||||
|
||||
// TODO: handle serializable objects
|
||||
val serializableClassSymbol =
|
||||
(owner.getContainingDeclarationSymbol(session) as? FirClassSymbol<*>) ?: error("Can't get outer class for $owner")
|
||||
|
||||
typeParameters.addAll(serializableClassSymbol.typeParameterSymbols.map { newSimpleTypeParameter(session, symbol, it.name) })
|
||||
val parametersAsArguments = typeParameters.map { it.toConeType() }.toTypedArray<ConeTypeProjection>()
|
||||
|
||||
@@ -193,7 +191,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
return f.symbol
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class) // TODO: localSerializersFieldDescriptors
|
||||
@OptIn(SymbolInternals::class)
|
||||
override fun generateProperties(callableId: CallableId, context: MemberGenerationContext?): List<FirPropertySymbol> {
|
||||
val owner = context?.owner ?: return emptyList()
|
||||
if (owner.name != SerialEntityNames.SERIALIZER_CLASS_NAME) return emptyList()
|
||||
|
||||
+15
@@ -5,15 +5,22 @@
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingDeclarationSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.outerClassSymbol
|
||||
import org.jetbrains.kotlin.fir.declarations.findArgumentByName
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.expressions.classId
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isSerializableObject
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
|
||||
|
||||
internal val FirClassSymbol<*>.hasSerializableAnnotation
|
||||
get() = this.annotations.any {
|
||||
@@ -59,4 +66,12 @@ private fun FirClassSymbol<*>.isFinalOrOpen(): Boolean {
|
||||
val modality = rawStatus.modality
|
||||
// null means default modality, final
|
||||
return (modality == null || modality == Modality.FINAL || modality == Modality.OPEN)
|
||||
}
|
||||
|
||||
internal fun FirSession.getSerializableClassDescriptorByCompanion(thisDescriptor: FirClassSymbol<*>): FirClassSymbol<*>? {
|
||||
if (thisDescriptor.isSerializableObject) return thisDescriptor
|
||||
if (!thisDescriptor.isCompanion) return null
|
||||
val classDescriptor = (thisDescriptor.getContainingDeclarationSymbol(this) as? FirClassSymbol<*>) ?: return null
|
||||
if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null
|
||||
return classDescriptor
|
||||
}
|
||||
+6
@@ -54,4 +54,10 @@ public class SerializationFirBlackBoxTestGenerated extends AbstractSerialization
|
||||
public void testPrivatePropertiesSerialization() throws Exception {
|
||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/privatePropertiesSerialization.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("serializableObject.kt")
|
||||
public void testSerializableObject() throws Exception {
|
||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/serializableObject.kt");
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -53,4 +53,10 @@ public class SerializationFirMembersTestGenerated extends AbstractSerializationF
|
||||
public void testPrivatePropertiesSerialization() throws Exception {
|
||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/privatePropertiesSerialization.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("serializableObject.kt")
|
||||
public void testSerializableObject() throws Exception {
|
||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/serializableObject.kt");
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
FILE: serializableObject.kt
|
||||
@R|kotlinx/serialization/Serializable|() public final object FooBar : R|kotlin/Any| {
|
||||
private constructor(): R|FooBar| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<FooBar>|
|
||||
|
||||
}
|
||||
public final fun box(): R|kotlin/String| {
|
||||
lval encoded: R|kotlin/String| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.encodeToString|<R|FooBar|>(Q|FooBar|.R|/FooBar.serializer|(), Q|FooBar|)
|
||||
when () {
|
||||
!=(R|<local>/encoded|, String({})) -> {
|
||||
^box R|<local>/encoded|
|
||||
}
|
||||
}
|
||||
|
||||
lval decoded: R|FooBar| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.decodeFromString|<R|FooBar|>(Q|FooBar|.R|/FooBar.serializer|(), R|<local>/encoded|)
|
||||
when () {
|
||||
!==(R|<local>/decoded|, Q|FooBar|) -> {
|
||||
^box String(Incorrect object instance)
|
||||
}
|
||||
}
|
||||
|
||||
^box String(OK)
|
||||
}
|
||||
plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/serializableObject.kt
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.*
|
||||
|
||||
@Serializable
|
||||
object FooBar
|
||||
|
||||
fun box(): String {
|
||||
val encoded = Json.encodeToString(FooBar.serializer(), FooBar)
|
||||
if (encoded != "{}") return encoded
|
||||
val decoded = Json.decodeFromString(FooBar.serializer(), encoded)
|
||||
if (decoded !== FooBar) return "Incorrect object instance"
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user