Prototype of kotlinx.serialization FIR plugin:
Implement basic non-parameterized case
This commit is contained in:
@@ -36,6 +36,7 @@ data class FirExtensionPointName(val name: Name) {
|
|||||||
constructor(name: String) : this(Name.identifier(name))
|
constructor(name: String) : this(Name.identifier(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: KDOC
|
||||||
abstract class FirDeclarationPredicateRegistrar {
|
abstract class FirDeclarationPredicateRegistrar {
|
||||||
abstract fun register(vararg predicates: DeclarationPredicate)
|
abstract fun register(vararg predicates: DeclarationPredicate)
|
||||||
abstract fun register(predicates: Collection<DeclarationPredicate>)
|
abstract fun register(predicates: Collection<DeclarationPredicate>)
|
||||||
|
|||||||
+1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
|
|||||||
|
|
||||||
// -------------------------------------------- Predicates --------------------------------------------
|
// -------------------------------------------- Predicates --------------------------------------------
|
||||||
|
|
||||||
|
// todo: Missing KDOC
|
||||||
sealed class DeclarationPredicate {
|
sealed class DeclarationPredicate {
|
||||||
abstract val annotations: Set<AnnotationFqn>
|
abstract val annotations: Set<AnnotationFqn>
|
||||||
abstract val metaAnnotations: Set<AnnotationFqn>
|
abstract val metaAnnotations: Set<AnnotationFqn>
|
||||||
|
|||||||
+2
@@ -61,6 +61,7 @@ fun FirDeclarationGenerationExtension.buildMaterializeFunction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: this has to be shared
|
||||||
@OptIn(SymbolInternals::class)
|
@OptIn(SymbolInternals::class)
|
||||||
fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner: Boolean, key: GeneratedDeclarationKey): FirConstructor {
|
fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner: Boolean, key: GeneratedDeclarationKey): FirConstructor {
|
||||||
val lookupTag = ConeClassLikeLookupTagImpl(classId)
|
val lookupTag = ConeClassLikeLookupTagImpl(classId)
|
||||||
@@ -92,6 +93,7 @@ fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: this has to be shared
|
||||||
fun ClassId.toSimpleConeType(typeArguments: Array<ConeKotlinTypeProjection> = emptyArray()): ConeClassLikeType {
|
fun ClassId.toSimpleConeType(typeArguments: Array<ConeKotlinTypeProjection> = emptyArray()): ConeClassLikeType {
|
||||||
return ConeClassLikeTypeImpl(
|
return ConeClassLikeTypeImpl(
|
||||||
ConeClassLikeLookupTagImpl(this),
|
ConeClassLikeLookupTagImpl(this),
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ dependencies {
|
|||||||
compileOnly(project(":js:js.translator"))
|
compileOnly(project(":js:js.translator"))
|
||||||
compileOnly(project(":kotlin-util-klib-metadata"))
|
compileOnly(project(":kotlin-util-klib-metadata"))
|
||||||
|
|
||||||
|
// FIR dependencies
|
||||||
|
compileOnly(project(":compiler:fir:cones"))
|
||||||
|
compileOnly(project(":compiler:fir:tree"))
|
||||||
|
compileOnly(project(":compiler:fir:resolve"))
|
||||||
|
// compileOnly(project(":compiler:fir:checkers"))
|
||||||
|
// compileOnly(project(":compiler:fir:checkers:checkers.jvm"))
|
||||||
|
// compileOnly(project(":compiler:fir:fir2ir"))
|
||||||
|
// compileOnly(project(":compiler:ir.tree.impl"))
|
||||||
|
compileOnly(project(":compiler:fir:entrypoint"))
|
||||||
|
|
||||||
runtimeOnly(kotlinStdlib())
|
runtimeOnly(kotlinStdlib())
|
||||||
|
|
||||||
testApi(projectTests(":compiler:tests-common"))
|
testApi(projectTests(":compiler:tests-common"))
|
||||||
@@ -44,6 +54,7 @@ sourceSets {
|
|||||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
freeCompilerArgs += "-opt-in=org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI"
|
freeCompilerArgs += "-opt-in=org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI"
|
||||||
|
freeCompilerArgs += "-opt-in=org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.GeneratedDeclarationKey
|
||||||
|
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.builder.buildPrimaryConstructor
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.origin
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||||
|
import org.jetbrains.kotlin.fir.moduleData
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: this has to be shared (copied from plugin example)
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner: Boolean, key: GeneratedDeclarationKey): FirConstructor {
|
||||||
|
val lookupTag = ConeClassLikeLookupTagImpl(classId)
|
||||||
|
return buildPrimaryConstructor {
|
||||||
|
moduleData = session.moduleData
|
||||||
|
origin = key.origin
|
||||||
|
returnTypeRef = buildResolvedTypeRef {
|
||||||
|
type = ConeClassLikeTypeImpl(
|
||||||
|
lookupTag,
|
||||||
|
emptyArray(),
|
||||||
|
isNullable = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
status = FirResolvedDeclarationStatusImpl(
|
||||||
|
Visibilities.Public,
|
||||||
|
Modality.FINAL,
|
||||||
|
EffectiveVisibility.Public
|
||||||
|
)
|
||||||
|
symbol = FirConstructorSymbol(classId)
|
||||||
|
if (isInner && classId.isNestedClass) {
|
||||||
|
dispatchReceiverType = classId.parentClassId?.let {
|
||||||
|
val firClass = session.symbolProvider.getClassLikeSymbolByClassId(it)?.fir as? FirClass
|
||||||
|
firClass?.defaultType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also {
|
||||||
|
it.containingClassForStaticMemberAttr = lookupTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: copied from Parcelize plugin
|
||||||
|
inline fun FirSession.createFunction(
|
||||||
|
owner: FirRegularClassSymbol,
|
||||||
|
callableId: CallableId,
|
||||||
|
init: FirSimpleFunctionBuilder.() -> Unit
|
||||||
|
): FirNamedFunctionSymbol {
|
||||||
|
val function = buildSimpleFunction {
|
||||||
|
moduleData = this@createFunction.moduleData
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
status = FirResolvedDeclarationStatusImpl(
|
||||||
|
Visibilities.Public,
|
||||||
|
if (owner.modality == Modality.FINAL) Modality.FINAL else Modality.OPEN,
|
||||||
|
EffectiveVisibility.Public
|
||||||
|
).apply {
|
||||||
|
isOverride = true
|
||||||
|
}
|
||||||
|
name = callableId.callableName
|
||||||
|
symbol = FirNamedFunctionSymbol(callableId)
|
||||||
|
dispatchReceiverType = owner.defaultType()
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
return function.symbol
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||||
|
|
||||||
|
class FirSerializationExtensionRegistrar: FirExtensionRegistrar() {
|
||||||
|
override fun ExtensionRegistrarContext.configurePlugin() {
|
||||||
|
+::SerializationFirResolveExtension
|
||||||
|
+::SerializationFirSupertypesExtension
|
||||||
|
}
|
||||||
|
}
|
||||||
+339
@@ -0,0 +1,339 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.GeneratedDeclarationKey
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingDeclarationSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.copy
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.origin
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.addDefaultBoundIfNecessary
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.predicate.AnnotatedWith
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
||||||
|
import org.jetbrains.kotlin.fir.moduleData
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
|
import org.jetbrains.kotlin.fir.types.constructClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.toTypeProjection
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||||
|
|
||||||
|
object SerializationPluginKey : GeneratedDeclarationKey() {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "KotlinxSerializationPlugin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val generatedSerializerClassId = ClassId(SerializationPackages.internalPackageFqName, SerialEntityNames.GENERATED_SERIALIZER_CLASS)
|
||||||
|
val kSerializerClassId = ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME)
|
||||||
|
|
||||||
|
class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||||
|
|
||||||
|
// FIXME: I can't check status here
|
||||||
|
override fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||||
|
val result = mutableSetOf<Name>()
|
||||||
|
if (classSymbol.shouldHaveGeneratedMethodsInCompanion && !classSymbol.isSerializableObject)
|
||||||
|
result += SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
|
||||||
|
if (classSymbol.shouldHaveGeneratedSerializer /* TODO && !classSymbol.hasCompanionObjectAsSerializer*/)
|
||||||
|
result += SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* It's not documented how these classes relate with getCallableNamesForClass
|
||||||
|
* Document says:
|
||||||
|
* 1.> If you generate some class using generateClassLikeDeclaration then you don't need to fill it's declarations.
|
||||||
|
* Q: Don't need or MUSTN'T?
|
||||||
|
*
|
||||||
|
* 2. > Instead of that you need to generate members via generateProperties/Functions/Constructors methods
|
||||||
|
* of same generation extension (this is important note if you have multiple generation extensions in your plugin)
|
||||||
|
*
|
||||||
|
* Q: Does this mean that for e.g. generated companion `generateFunctions` will be called regardless of provided predicate?
|
||||||
|
*
|
||||||
|
* 3. This method is stated to be called on SUPERTYPES, but getNestedClassifiersNames stated to be called after SUPERTYPES. How is this possible?
|
||||||
|
*
|
||||||
|
* 4. It is should be mentioned that supertypes for generated class should be added here,
|
||||||
|
* while supertypes for exisiting classes — in separate extension
|
||||||
|
*/
|
||||||
|
override fun generateClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||||
|
return when (classId.shortClassName) {
|
||||||
|
SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT -> {
|
||||||
|
generateCompanionDeclaration(classId)
|
||||||
|
}
|
||||||
|
SerialEntityNames.SERIALIZER_CLASS_NAME -> {
|
||||||
|
addSerializerImplClass(classId)
|
||||||
|
}
|
||||||
|
else -> error("Can't generate class ${classId.asSingleFqName()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. It is unclear that for `generateConstructors` to work, one need to return SpecialNames.INIT from here
|
||||||
|
* 1a. Also it is unclear that objects need constructors too.
|
||||||
|
*
|
||||||
|
* 2. If it is a user-written companion object, will I get here? Why?
|
||||||
|
*
|
||||||
|
* 3. Is it supposed to check that classSymbol does not already have same Name? How to add a generated overload?
|
||||||
|
*
|
||||||
|
* 4. It is unclear what to do with properties
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||||
|
val classId = classSymbol.classId
|
||||||
|
val result = mutableSetOf<Name>()
|
||||||
|
when (classId.shortClassName) {
|
||||||
|
SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT -> {
|
||||||
|
val origin = classSymbol.origin as? FirDeclarationOrigin.Plugin
|
||||||
|
if (origin?.key == SerializationPluginKey) {
|
||||||
|
result += SpecialNames.INIT
|
||||||
|
result += SerialEntityNames.SERIALIZER_PROVIDER_NAME
|
||||||
|
} else {
|
||||||
|
// TODO: handle user-written companions & named companions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SerialEntityNames.SERIALIZER_CLASS_NAME -> {
|
||||||
|
// TODO: check classSymbol for already added functions
|
||||||
|
// TODO: support user-defined serializers?
|
||||||
|
result += setOf(
|
||||||
|
SpecialNames.INIT,
|
||||||
|
SerialEntityNames.SAVE_NAME,
|
||||||
|
SerialEntityNames.LOAD_NAME,
|
||||||
|
// FIXME: correctly create property?
|
||||||
|
SerialEntityNames.SERIAL_DESC_FIELD_NAME
|
||||||
|
)
|
||||||
|
if (classSymbol.superConeTypes.any {
|
||||||
|
it.classId == ClassId(
|
||||||
|
SerializationPackages.internalPackageFqName,
|
||||||
|
SerialEntityNames.GENERATED_SERIALIZER_CLASS
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
result += SerialEntityNames.CHILD_SERIALIZERS_GETTER
|
||||||
|
|
||||||
|
if (classSymbol.typeParameterSymbols.isNotEmpty()) {
|
||||||
|
result += SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> if (classSymbol.isSerializableObject) result += SerialEntityNames.SERIALIZER_PROVIDER_NAME
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
private fun <T> getFromSupertype(callableId: CallableId, owner: FirClassSymbol<*>, extractor: (FirTypeScope) -> List<T>): T {
|
||||||
|
val scopeSession = ScopeSession() // ????????
|
||||||
|
val scopes = lookupSuperTypes(
|
||||||
|
owner, lookupInterfaces = true, deep = false, useSiteSession = session
|
||||||
|
).mapNotNull { useSiteSuperType ->
|
||||||
|
useSiteSuperType.scopeForSupertype(session, scopeSession, owner.fir)
|
||||||
|
}
|
||||||
|
val targets = scopes.flatMap { extractor(it) }
|
||||||
|
val target = targets.singleOrNull() ?: error("Multiple overrides found for ${callableId.callableName}")
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: support @Serializer(for)
|
||||||
|
@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 (owner.name != SerialEntityNames.SERIALIZER_CLASS_NAME) return emptyList()
|
||||||
|
if (callableId.callableName !in setOf(
|
||||||
|
SpecialNames.INIT,
|
||||||
|
SerialEntityNames.SAVE_NAME,
|
||||||
|
SerialEntityNames.LOAD_NAME,
|
||||||
|
SerialEntityNames.CHILD_SERIALIZERS_GETTER,
|
||||||
|
SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER
|
||||||
|
)
|
||||||
|
) return emptyList()
|
||||||
|
val target = getFromSupertype(callableId, owner) { it.getFunctions(callableId.callableName) }
|
||||||
|
val original = target.fir
|
||||||
|
val copy = buildSimpleFunctionCopy(original) {
|
||||||
|
symbol = FirNamedFunctionSymbol(callableId)
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
status = original.status.copy(modality = Modality.FINAL)
|
||||||
|
|
||||||
|
}
|
||||||
|
return listOf(copy.symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateSerializerGetterInCompanion(owner: FirClassSymbol<*>, callableId: CallableId): FirNamedFunctionSymbol {
|
||||||
|
val f = buildSimpleFunction {
|
||||||
|
moduleData = session.moduleData
|
||||||
|
symbol = FirNamedFunctionSymbol(callableId)
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
status = FirResolvedDeclarationStatusImpl(
|
||||||
|
Visibilities.Public,
|
||||||
|
Modality.FINAL,
|
||||||
|
EffectiveVisibility.Public
|
||||||
|
)
|
||||||
|
name = callableId.callableName
|
||||||
|
dispatchReceiverType = owner.defaultType()
|
||||||
|
|
||||||
|
// TODO: handle serializable objects
|
||||||
|
val serializableType =
|
||||||
|
(owner.getContainingDeclarationSymbol(session) as? FirClassSymbol<*>) ?: error("Can't get outer class for $owner")
|
||||||
|
|
||||||
|
// TODO: Add value parameters & type parameters for parameterized classes
|
||||||
|
returnTypeRef = buildResolvedTypeRef {
|
||||||
|
type = kSerializerClassId.constructClassLikeType(
|
||||||
|
arrayOf(serializableType.defaultType().toTypeProjection(Variance.INVARIANT)),
|
||||||
|
isNullable = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
@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()
|
||||||
|
if (callableId.callableName != SerialEntityNames.SERIAL_DESC_FIELD_NAME) return emptyList()
|
||||||
|
|
||||||
|
val target = getFromSupertype(callableId, owner) { it.getProperties(callableId.callableName).filterIsInstance<FirPropertySymbol>() }
|
||||||
|
val original = target.fir
|
||||||
|
val copy = buildPropertyCopy(original) {
|
||||||
|
symbol = FirPropertySymbol(callableId)
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
status = original.status.copy(modality = Modality.FINAL)
|
||||||
|
getter = buildPropertyAccessor {
|
||||||
|
status = original.status.copy(modality = Modality.FINAL)
|
||||||
|
symbol = FirPropertyAccessorSymbol()
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
moduleData = session.moduleData
|
||||||
|
isGetter = true
|
||||||
|
returnTypeRef = original.returnTypeRef
|
||||||
|
dispatchReceiverType = owner.defaultType()
|
||||||
|
propertySymbol = this@buildPropertyCopy.symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listOf(copy.symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: it seems that this list will always be used, why not provide it automatically?
|
||||||
|
private val matchedClasses by lazy {
|
||||||
|
session.predicateBasedProvider.getSymbolsByPredicate(AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName)))
|
||||||
|
.filterIsInstance<FirRegularClassSymbol>()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateConstructors(context: MemberGenerationContext): List<FirConstructorSymbol> {
|
||||||
|
val constructor = buildConstructor(context.owner.classId, isInner = false, SerializationPluginKey)
|
||||||
|
return listOf(constructor.symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addSerializerImplClass(
|
||||||
|
classId: ClassId
|
||||||
|
): FirClassLikeSymbol<*>? {
|
||||||
|
val owner = matchedClasses.firstOrNull { it.classId == classId.outerClassId } ?: return null
|
||||||
|
val hasTypeParams = owner.typeParameterSymbols.isNotEmpty()
|
||||||
|
val serializerKind = if (hasTypeParams) ClassKind.CLASS else ClassKind.OBJECT
|
||||||
|
val serializerFirClass = buildRegularClass {
|
||||||
|
moduleData = session.moduleData
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
classKind = serializerKind
|
||||||
|
scopeProvider = session.kotlinScopeProvider
|
||||||
|
name = SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||||
|
symbol = FirRegularClassSymbol(classId)
|
||||||
|
status = FirResolvedDeclarationStatusImpl(
|
||||||
|
Visibilities.Public,
|
||||||
|
Modality.FINAL,
|
||||||
|
EffectiveVisibility.Public
|
||||||
|
)
|
||||||
|
// FIXME: how to create annotations?
|
||||||
|
// annotations = listOf(Annotations.create(listOf(KSerializerDescriptorResolver.createDeprecatedHiddenAnnotation(thisDescriptor.module))))
|
||||||
|
|
||||||
|
|
||||||
|
typeParameters.addAll(owner.typeParameterSymbols.map { param ->
|
||||||
|
buildTypeParameter {
|
||||||
|
moduleData = session.moduleData
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
resolvePhase = FirResolvePhase.BODY_RESOLVE
|
||||||
|
variance = Variance.INVARIANT
|
||||||
|
name = param.name
|
||||||
|
symbol = FirTypeParameterSymbol()
|
||||||
|
containingDeclarationSymbol = this@buildRegularClass.symbol
|
||||||
|
isReified = false
|
||||||
|
addDefaultBoundIfNecessary() // there should be KSerializer but whatever
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
superTypeRefs += buildResolvedTypeRef {
|
||||||
|
// FIXME: document how one gets type ref from FirClass
|
||||||
|
// is this a correct one or should I go with buildTypeProjectionWithVariance ?
|
||||||
|
// is this a correct place to add supertypes to synthetic declarations? Looks like FirSupertypesExtension does not see class.
|
||||||
|
// It seems that this code generates KSerializer<Box<[declared type param of Box]>> instead of KSerializer<Box<*>>, but it didn't matter for old FE
|
||||||
|
type = generatedSerializerClassId.constructClassLikeType(arrayOf(owner.defaultType().toTypeProjection(Variance.INVARIANT)), isNullable = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: add typed constructor
|
||||||
|
// val secondaryCtors =
|
||||||
|
// if (!hasTypeParams)
|
||||||
|
// emptyList()
|
||||||
|
// else
|
||||||
|
// listOf(
|
||||||
|
// KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(
|
||||||
|
// serializerFirClass,
|
||||||
|
// thisDescriptor,
|
||||||
|
// typeParameters
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// serializerFirClass.secondaryConstructors = secondaryCtors
|
||||||
|
return serializerFirClass.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateCompanionDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||||
|
if (classId.shortClassName != SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT) return null
|
||||||
|
val owner = matchedClasses.firstOrNull { it.classId == classId.outerClassId } ?: return null
|
||||||
|
if (owner.companionObjectSymbol != null) return null
|
||||||
|
val regularClass = buildRegularClass {
|
||||||
|
moduleData = session.moduleData
|
||||||
|
origin = SerializationPluginKey.origin
|
||||||
|
classKind = ClassKind.OBJECT
|
||||||
|
scopeProvider = session.kotlinScopeProvider
|
||||||
|
status = FirResolvedDeclarationStatusImpl(
|
||||||
|
Visibilities.Public,
|
||||||
|
Modality.FINAL,
|
||||||
|
EffectiveVisibility.Public
|
||||||
|
).apply {
|
||||||
|
isCompanion = true
|
||||||
|
}
|
||||||
|
name = SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
|
||||||
|
symbol = FirRegularClassSymbol(classId)
|
||||||
|
superTypeRefs += session.builtinTypes.anyType
|
||||||
|
}
|
||||||
|
return regularClass.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||||
|
// No predicate on final/open etc
|
||||||
|
register(AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.predicate.*
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
|
||||||
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
|
import org.jetbrains.kotlin.fir.types.constructClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.toTypeProjection
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||||
|
|
||||||
|
class SerializationFirSupertypesExtension(session: FirSession) : FirSupertypeGenerationExtension(session) {
|
||||||
|
companion object {
|
||||||
|
private val serializerFor: DeclarationPredicate =
|
||||||
|
AnnotatedWith(setOf(SerializationAnnotations.serializerAnnotationFqName)) // @Serializer(for=...)
|
||||||
|
private val generatedSerializer: DeclarationPredicate =
|
||||||
|
ancestorAnnotated(SerializationAnnotations.serializableAnnotationFqName) // @Serializable X.$serializer
|
||||||
|
private val PREDICATE = serializerFor or generatedSerializer
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun needTransformSupertypes(declaration: FirClassLikeDeclaration): Boolean =
|
||||||
|
session.predicateBasedProvider.matches(serializerFor, declaration)
|
||||||
|
|| ( // TODO: this part is not working
|
||||||
|
session.predicateBasedProvider.matches(generatedSerializer, declaration)
|
||||||
|
&& declaration is FirRegularClass
|
||||||
|
&& declaration.name == SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||||
|
register(PREDICATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun computeAdditionalSupertypes(
|
||||||
|
classLikeDeclaration: FirClassLikeDeclaration,
|
||||||
|
resolvedSupertypes: List<FirResolvedTypeRef>
|
||||||
|
): List<FirResolvedTypeRef> {
|
||||||
|
val kSerializerClassId = ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME)
|
||||||
|
val generatedSerializerClassId = ClassId(SerializationPackages.internalPackageFqName, SerialEntityNames.GENERATED_SERIALIZER_CLASS)
|
||||||
|
if (resolvedSupertypes.any { it.type.classId == kSerializerClassId || it.type.classId == generatedSerializerClassId }) return emptyList()
|
||||||
|
|
||||||
|
|
||||||
|
if (session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration)) {
|
||||||
|
TODO("Support @Serializer(for=...) supertype generation")
|
||||||
|
} else {
|
||||||
|
// TODO: Remove this section as it is not working because one should add supertype for generated class where this class is created.
|
||||||
|
// @Serializable X.$serializer
|
||||||
|
val parent = (classLikeDeclaration.getContainingDeclaration(session) as? FirRegularClass)
|
||||||
|
?: error("Generated serializer $classLikeDeclaration is not contained in any class")
|
||||||
|
|
||||||
|
return listOf(buildResolvedTypeRef {
|
||||||
|
// FIXME: document how one gets type ref from FirClass
|
||||||
|
// FIXME: is this a correct one or should I go with buildTypeProjectionWithVariance ?
|
||||||
|
// It seems that this code generates KSerializer<Box<[declared type param]>> instead of KSerializer<Box<*>>, but it didn't matter for old FE
|
||||||
|
type = generatedSerializerClassId.constructClassLikeType(arrayOf(parent.defaultType().toTypeProjection(Variance.INVARIANT)), isNullable = false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.findArgumentByName
|
||||||
|
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
|
||||||
|
|
||||||
|
// FIXME: why FirAnnotation.classId.asSingleFqName is available, but FirAnnotation.fqName() requires FirSession?
|
||||||
|
internal val FirClassSymbol<*>.hasSerializableAnnotation
|
||||||
|
get() = this.annotations.any {
|
||||||
|
it.classId?.asSingleFqName()?.asString() == SerializationAnnotations.serializableAnnotationFqName.asString()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val FirClassSymbol<*>.hasSerializableAnnotationWithoutArgs: Boolean
|
||||||
|
get() {
|
||||||
|
if (!hasSerializableAnnotation) return false
|
||||||
|
val target = this.resolvedAnnotationsWithArguments.find {
|
||||||
|
it.classId?.asSingleFqName()?.asString() == SerializationAnnotations.serializableAnnotationFqName.asString()
|
||||||
|
}!!
|
||||||
|
return target.findArgumentByName(Name.identifier("with")) == null
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val FirClassSymbol<*>.shouldHaveGeneratedMethodsInCompanion: Boolean
|
||||||
|
get() = this.isSerializableObject || this.isSerializableEnum() || this.classKind == ClassKind.CLASS && hasSerializableAnnotation || this.isSealedSerializableInterface
|
||||||
|
|
||||||
|
internal val FirClassSymbol<*>.isSerializableObject: Boolean
|
||||||
|
get() = classKind == ClassKind.OBJECT && hasSerializableAnnotation
|
||||||
|
|
||||||
|
internal val FirClassSymbol<*>.isInternallySerializableObject: Boolean
|
||||||
|
get() = classKind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs
|
||||||
|
|
||||||
|
internal val FirClassSymbol<*>.isSealedSerializableInterface: Boolean
|
||||||
|
get() = classKind == ClassKind.INTERFACE && modality == Modality.SEALED && hasSerializableAnnotation
|
||||||
|
|
||||||
|
internal val FirClassSymbol<*>.isInternalSerializable: Boolean
|
||||||
|
get() {
|
||||||
|
if (classKind != ClassKind.CLASS) return false
|
||||||
|
return hasSerializableAnnotationWithoutArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun FirClassSymbol<*>.isSerializableEnum(): Boolean = classKind == ClassKind.ENUM_CLASS && hasSerializableAnnotation
|
||||||
|
|
||||||
|
internal fun FirClassSymbol<*>.isInternallySerializableEnum(): Boolean =
|
||||||
|
classKind == ClassKind.ENUM_CLASS && hasSerializableAnnotationWithoutArgs
|
||||||
|
|
||||||
|
internal val FirClassSymbol<*>.shouldHaveGeneratedSerializer: Boolean
|
||||||
|
get() = (isInternalSerializable && isFinalOrOpen()) || isInternallySerializableEnum()
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
private fun FirClassSymbol<*>.isFinalOrOpen(): Boolean {
|
||||||
|
val modality = fir.status.modality
|
||||||
|
// null means default modality, final
|
||||||
|
return (modality == null || modality == Modality.FINAL || modality == Modality.OPEN)
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
|
||||||
|
import org.jetbrains.kotlin.test.TargetBackend
|
||||||
|
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
|
||||||
|
import org.jetbrains.kotlin.test.backend.handlers.*
|
||||||
|
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
|
||||||
|
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||||
|
import org.jetbrains.kotlin.test.builders.fir2IrStep
|
||||||
|
import org.jetbrains.kotlin.test.builders.irHandlersStep
|
||||||
|
import org.jetbrains.kotlin.test.builders.jvmArtifactsHandlersStep
|
||||||
|
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
|
||||||
|
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
|
||||||
|
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
|
||||||
|
import org.jetbrains.kotlin.test.runners.baseFirDiagnosticTestConfiguration
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensionRegistrar
|
||||||
|
|
||||||
|
abstract class AbstractSerializationFirMembersTest: AbstractKotlinCompilerTest() {
|
||||||
|
override fun TestConfigurationBuilder.configuration() {
|
||||||
|
baseFirDiagnosticTestConfiguration()
|
||||||
|
|
||||||
|
defaultDirectives {
|
||||||
|
+FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES
|
||||||
|
+FirDiagnosticsDirectives.FIR_DUMP
|
||||||
|
}
|
||||||
|
|
||||||
|
configureForKotlinxSerialization(listOf(getSerializationCoreLibraryJar()!!)) {
|
||||||
|
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class AbstractSerializationFirBlackBoxTest : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) {
|
||||||
|
override fun TestConfigurationBuilder.configuration() {
|
||||||
|
baseFirDiagnosticTestConfiguration()
|
||||||
|
defaultDirectives {
|
||||||
|
+FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES
|
||||||
|
}
|
||||||
|
|
||||||
|
fir2IrStep()
|
||||||
|
irHandlersStep {
|
||||||
|
useHandlers(
|
||||||
|
::IrTextDumpHandler,
|
||||||
|
::IrTreeVerifierHandler,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
facadeStep(::JvmIrBackendFacade)
|
||||||
|
jvmArtifactsHandlersStep {
|
||||||
|
useHandlers(::JvmBoxRunner)
|
||||||
|
}
|
||||||
|
|
||||||
|
useAfterAnalysisCheckers(::BlackBoxCodegenSuppressor)
|
||||||
|
|
||||||
|
configureForKotlinxSerialization(listOf(getSerializationCoreLibraryJar()!!)) {
|
||||||
|
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -47,7 +47,7 @@ internal fun getSerializationLibraryJar(classToDetect: String): File? = try {
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun TestConfigurationBuilder.configureForKotlinxSerialization(librariesPaths: List<File>) {
|
internal fun TestConfigurationBuilder.configureForKotlinxSerialization(librariesPaths: List<File>, registerAdditionalExtensions: ExtensionStorage.() -> Unit = {}) {
|
||||||
useConfigurators(
|
useConfigurators(
|
||||||
{ services ->
|
{ services ->
|
||||||
object : EnvironmentConfigurator(services) {
|
object : EnvironmentConfigurator(services) {
|
||||||
@@ -60,6 +60,7 @@ internal fun TestConfigurationBuilder.configureForKotlinxSerialization(libraries
|
|||||||
|
|
||||||
override fun ExtensionStorage.registerCompilerExtensions(module: TestModule, configuration: CompilerConfiguration) {
|
override fun ExtensionStorage.registerCompilerExtensions(module: TestModule, configuration: CompilerConfiguration) {
|
||||||
SerializationComponentRegistrar.registerExtensions(this)
|
SerializationComponentRegistrar.registerExtensions(this)
|
||||||
|
registerAdditionalExtensions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||||
|
import org.jetbrains.kotlin.test.TargetBackend;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class SerializationFirBlackBoxTestGenerated extends AbstractSerializationFirBlackBoxTest {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInFirMembers() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("classWithCompanionObject.kt")
|
||||||
|
public void testClassWithCompanionObject() throws Exception {
|
||||||
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/classWithCompanionObject.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class SerializationFirMembersTestGenerated extends AbstractSerializationFirMembersTest {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInFirMembers() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("classWithCompanionObject.kt")
|
||||||
|
public void testClassWithCompanionObject() throws Exception {
|
||||||
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/classWithCompanionObject.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -20,6 +20,14 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractSerializationIrBoxTest> {
|
testClass<AbstractSerializationIrBoxTest> {
|
||||||
model("boxIr")
|
model("boxIr")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClass<AbstractSerializationFirMembersTest> {
|
||||||
|
model("firMembers")
|
||||||
|
}
|
||||||
|
|
||||||
|
testClass<AbstractSerializationFirBlackBoxTest> {
|
||||||
|
model("firMembers")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
FILE: classWithCompanionObject.kt
|
||||||
|
@R|kotlinx/serialization/Serializable|() public final class SomeClass : R|kotlin/Any| {
|
||||||
|
public constructor(): R|SomeClass| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final companion object Companion : R|kotlin/Any| {
|
||||||
|
public final fun serializer(): R|kotlinx/serialization/KSerializer<SomeClass>|
|
||||||
|
|
||||||
|
public constructor(): R|SomeClass.Companion|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final object $serializer : R|kotlinx/serialization/internal/GeneratedSerializer<SomeClass>| {
|
||||||
|
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|SomeClass|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|SomeClass|
|
||||||
|
|
||||||
|
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||||
|
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||||
|
|
||||||
|
public final fun childSerializers(): R|kotlin/Array<kotlinx/serialization/KSerializer<*>>|
|
||||||
|
|
||||||
|
public constructor(): R|SomeClass.$serializer|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun box(): R|kotlin/String| {
|
||||||
|
^box String(OK)
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SomeClass
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
// SomeClass.serializer()
|
||||||
|
// SomeClass.Companion.serializer()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user