diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt index 6c4ffb74226..800c50eb4cf 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.getContainingDeclarationSymbol import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr import org.jetbrains.kotlin.fir.copy import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy import org.jetbrains.kotlin.fir.declarations.origin import org.jetbrains.kotlin.fir.declarations.utils.isCompanion @@ -28,17 +29,12 @@ import org.jetbrains.kotlin.fir.scopes.impl.toConeType import org.jetbrains.kotlin.fir.scopes.scopeForSupertype import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.types.ConeTypeProjection -import org.jetbrains.kotlin.fir.types.classId -import org.jetbrains.kotlin.fir.types.constructClassLikeType -import org.jetbrains.kotlin.fir.types.constructType +import org.jetbrains.kotlin.fir.types.* 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.platform.isJs -import org.jetbrains.kotlin.platform.isWasm -import org.jetbrains.kotlin.platform.konan.isNative +import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_FACTORY_INTERFACE_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages @@ -151,7 +147,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene useSiteSuperType.scopeForSupertype(session, scopeSession, owner.fir, memberRequiredPhase = null) } val targets = scopes.flatMap { extractor(it) } - return targets.singleOrNull() ?: error("Multiple overrides found for ${callableId.callableName}") + return targets.singleOrNull() ?: error("Zero or multiple overrides found for ${callableId.callableName} in $owner") } @OptIn(SymbolInternals::class) @@ -165,8 +161,13 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene if (with(session) { owner.isSerializableObject }) owner else null } - serializableClass ?: return emptyList() - return listOf(generateSerializerGetterInCompanion(owner, serializableClass, callableId)) + if (serializableClass == null) return emptyList() + val serializableGetterInCompanion = generateSerializerGetterInCompanion(owner, serializableClass, callableId) + val serializableGetterFromFactory = runIf (with(session) { serializableClass.companionNeedsSerializerFactory }) { + val original = getFromSupertype(callableId, owner) { it.getFunctions(callableId.callableName) }.fir + generateSerializerFactoryVararg(owner, callableId, original) + } + return listOfNotNull(serializableGetterInCompanion, serializableGetterFromFactory) } if (!owner.isSerializer) return emptyList() if (callableId.callableName !in setOf( @@ -188,6 +189,18 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene return listOf(copy.symbol) } + private fun generateSerializerFactoryVararg( + owner: FirClassSymbol<*>, + callableId: CallableId, + original: FirSimpleFunction + ): FirNamedFunctionSymbol = + createMemberFunction(owner, SerializationPluginKey, callableId.callableName, original.returnTypeRef.coneType) { + val vpo = original.valueParameters.single() + valueParameter(vpo.name, vpo.returnTypeRef.coneType, vpo.isCrossinline, vpo.isNoinline, vpo.isVararg, vpo.defaultValue != null) + }.apply { + excludeFromJsExport() + }.symbol + private fun generateSerializerGetterInCompanion( owner: FirClassSymbol<*>, serializableClassSymbol: FirClassSymbol<*>, @@ -309,16 +322,4 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene private val FirClassSymbol<*>.isExternalSerializer: Boolean get() = session.predicateBasedProvider.matches(FirSerializationPredicates.serializerFor, this) - context(FirSession) - private val FirClassSymbol<*>.companionNeedsSerializerFactory: Boolean - get() { - if (!(moduleData.platform.isNative() || moduleData.platform.isJs() || moduleData.platform.isWasm())) return false - if (isSerializableObject) return true - if (isSerializableEnum) return true - if (isAbstractOrSealedSerializableClass) return true - if (isSealedSerializableInterface) return true - if (typeParameterSymbols.isEmpty()) return false - return true - } - } diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirSupertypesExtension.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirSupertypesExtension.kt index 7cf44061081..7343c8fb3ba 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirSupertypesExtension.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirSupertypesExtension.kt @@ -5,8 +5,13 @@ package org.jetbrains.kotlinx.serialization.compiler.fir +import org.jetbrains.kotlin.descriptors.isObject import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.getContainingDeclarationSymbol +import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression @@ -14,22 +19,42 @@ import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension import org.jetbrains.kotlin.fir.extensions.buildUserTypeFromQualifierParts import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider +import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.types.* 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.name.ClassId import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.isJs +import org.jetbrains.kotlin.platform.isWasm +import org.jetbrains.kotlin.platform.konan.isNative +import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationPredicates.annotatedWithSerializableOrMeta import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationPredicates.serializerFor import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages class SerializationFirSupertypesExtension(session: FirSession) : FirSupertypeGenerationExtension(session) { + private val isJvmOrMetadata = !session.moduleData.platform.run { isNative() || isJs() || isWasm() } + override fun needTransformSupertypes(declaration: FirClassLikeDeclaration): Boolean = - session.predicateBasedProvider.matches(serializerFor, declaration) + session.predicateBasedProvider.matches(serializerFor, declaration) || isSerializableObjectAndNeedsFactory(declaration) || isCompanionAndNeedsFactory(declaration) + + private fun isSerializableObjectAndNeedsFactory(declaration: FirClassLikeDeclaration): Boolean = with(session) { + if (isJvmOrMetadata) return false + return declaration is FirClass && declaration.classKind.isObject + && session.predicateBasedProvider.matches(annotatedWithSerializableOrMeta, declaration) + } + + private fun isCompanionAndNeedsFactory(declaration: FirClassLikeDeclaration): Boolean = with(session) { + if (isJvmOrMetadata) return false + if (declaration !is FirRegularClass) return false + if (!declaration.isCompanion) return false + val parentSymbol = declaration.symbol.getContainingDeclarationSymbol(session) as FirClassSymbol<*> + return session.predicateBasedProvider.matches(annotatedWithSerializableOrMeta, parentSymbol) + && parentSymbol.companionNeedsSerializerFactory + } override fun FirDeclarationPredicateRegistrar.registerPredicates() { register(serializerFor) @@ -38,22 +63,33 @@ class SerializationFirSupertypesExtension(session: FirSession) : FirSupertypeGen context(TypeResolveServiceContainer) override fun computeAdditionalSupertypes( classLikeDeclaration: FirClassLikeDeclaration, - resolvedSupertypes: List + resolvedSupertypes: List, ): List { 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() - return if (session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration)) { - val getClassArgument = classLikeDeclaration.getSerializerFor(session) ?: return emptyList() - val serializerConeType = resolveConeTypeFromArgument(getClassArgument) + return when { + session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration) -> { + if (resolvedSupertypes.any { it.type.classId == kSerializerClassId || it.type.classId == generatedSerializerClassId }) return emptyList() + val getClassArgument = classLikeDeclaration.getSerializerFor(session) ?: return emptyList() + val serializerConeType = resolveConeTypeFromArgument(getClassArgument) - listOf( - buildResolvedTypeRef { - type = kSerializerClassId.constructClassLikeType(arrayOf(serializerConeType), isNullable = false) - } - ) - } else emptyList() + listOf( + buildResolvedTypeRef { + type = kSerializerClassId.constructClassLikeType(arrayOf(serializerConeType), isNullable = false) + } + ) + } + isSerializableObjectAndNeedsFactory(classLikeDeclaration) || isCompanionAndNeedsFactory(classLikeDeclaration) -> { + val serializerFactoryClassId = ClassId( + SerializationPackages.internalPackageFqName, + SerialEntityNames.SERIALIZER_FACTORY_INTERFACE_NAME + ) + if (resolvedSupertypes.any { it.type.classId == serializerFactoryClassId }) return emptyList() + listOf(serializerFactoryClassId.constructClassLikeType(emptyArray(), false).toFirResolvedTypeRef()) + } + else -> emptyList() + } } // Function helps to resolve class call from annotation argument to `ConeKotlinType` diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt index 031c20da406..fb012077bd8 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt @@ -29,6 +29,8 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.isJs +import org.jetbrains.kotlin.platform.isWasm +import org.jetbrains.kotlin.platform.konan.isNative import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlinx.serialization.compiler.fir.services.dependencySerializationInfoProvider import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames @@ -145,6 +147,18 @@ internal val FirClassSymbol<*>.shouldHaveGeneratedMethodsInCompanion: Boolean || (classKind == ClassKind.CLASS && hasSerializableOrMetaAnnotation) || isSealedSerializableInterface +context(FirSession) +internal val FirClassSymbol<*>.companionNeedsSerializerFactory: Boolean + get() { + if (!moduleData.platform.run { isNative() || isJs() || isWasm() }) return false + if (isSerializableObject) return true + if (isSerializableEnum) return true + if (isAbstractOrSealedSerializableClass) return true + if (isSealedSerializableInterface) return true + if (typeParameterSymbols.isEmpty()) return false + return true + } + context(FirSession) internal val FirClassSymbol<*>.isInternalSerializable: Boolean get() { diff --git a/plugins/kotlinx-serialization/testData/boxIr/serializerFactory.kt b/plugins/kotlinx-serialization/testData/boxIr/serializerFactory.kt new file mode 100644 index 00000000000..45f2b34a840 --- /dev/null +++ b/plugins/kotlinx-serialization/testData/boxIr/serializerFactory.kt @@ -0,0 +1,26 @@ +// WITH_STDLIB +// ISSUE: KT-58501 + +import kotlinx.serialization.* +import kotlinx.serialization.json.* + +@Serializable object Objekt + +@Serializable sealed class SealedInterface +@Serializable data object Inheritor: SealedInterface() + +@Serializable enum class EnumKlass { INSTANCE } + +@Serializable class Plain + +fun box(): String { + serializer() + Objekt.serializer() + serializer() + EnumKlass.serializer() + serializer() + SealedInterface.serializer() + serializer() + Plain.serializer() + return "OK" +} diff --git a/plugins/kotlinx-serialization/testData/boxIr/serializerFactoryInUserDefined.kt b/plugins/kotlinx-serialization/testData/boxIr/serializerFactoryInUserDefined.kt new file mode 100644 index 00000000000..a0a3590d843 --- /dev/null +++ b/plugins/kotlinx-serialization/testData/boxIr/serializerFactoryInUserDefined.kt @@ -0,0 +1,45 @@ +// WITH_STDLIB +// ISSUE: KT-59768 + +import kotlinx.serialization.* +import kotlinx.serialization.json.* + +@Serializable sealed class SealedInterface { + companion object { + fun unrelated() {} + } +} +@Serializable enum class EnumKlass { INSTANCE; + companion object { + fun unrelated() {} + } +} + +@Serializable class Plain { + companion object { + fun unrelated() {} + } +} + +@MetaSerializable +@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY) +annotation class MySerializable + +@MySerializable +sealed interface SealedMeta { + companion object { + fun unrelated() {} + } +} + +fun box(): String { + serializer() + EnumKlass.serializer() + serializer() + SealedInterface.serializer() + serializer() + Plain.serializer() + serializer() + SealedMeta.serializer() + return "OK" +} diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirJsBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirJsBoxTestGenerated.java new file mode 100644 index 00000000000..acf4eae0893 --- /dev/null +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirJsBoxTestGenerated.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2023 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.runners; + +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 org.jetbrains.kotlinx.serialization.TestGeneratorKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/kotlinx-serialization/testData/boxIr") +@TestDataPath("$PROJECT_ROOT") +public class SerializationFirJsBoxTestGenerated extends AbstractSerializationFirJsBoxTest { + @Test + public void testAllFilesPresentInBoxIr() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlinx-serialization/testData/boxIr"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("constValInSerialName.kt") + public void testConstValInSerialName() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/constValInSerialName.kt"); + } + + @Test + @TestMetadata("delegatedProperty.kt") + public void testDelegatedProperty() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/delegatedProperty.kt"); + } + + @Test + @TestMetadata("excludedFromExport.kt") + public void testExcludedFromExport() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/excludedFromExport.kt"); + } + + @Test + @TestMetadata("excludedFromFileExport.kt") + public void testExcludedFromFileExport() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/excludedFromFileExport.kt"); + } + + @Test + @TestMetadata("serializerFactory.kt") + public void testSerializerFactory() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactory.kt"); + } + + @Test + @TestMetadata("serializerFactoryInUserDefined.kt") + public void testSerializerFactoryInUserDefined() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactoryInUserDefined.kt"); + } +} diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirLightTreeBlackBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirLightTreeBlackBoxTestGenerated.java index 998435a8de3..2f5a114d0b7 100644 --- a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirLightTreeBlackBoxTestGenerated.java +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirLightTreeBlackBoxTestGenerated.java @@ -231,6 +231,18 @@ public class SerializationFirLightTreeBlackBoxTestGenerated extends AbstractSeri runTest("plugins/kotlinx-serialization/testData/boxIr/serializableOnPropertyType.kt"); } + @Test + @TestMetadata("serializerFactory.kt") + public void testSerializerFactory() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactory.kt"); + } + + @Test + @TestMetadata("serializerFactoryInUserDefined.kt") + public void testSerializerFactoryInUserDefined() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactoryInUserDefined.kt"); + } + @Test @TestMetadata("starProjections.kt") public void testStarProjections() throws Exception { diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java index 30ed8b023dc..d9fef509799 100644 --- a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java @@ -229,6 +229,18 @@ public class SerializationIrBoxTestGenerated extends AbstractSerializationIrBoxT runTest("plugins/kotlinx-serialization/testData/boxIr/serializableOnPropertyType.kt"); } + @Test + @TestMetadata("serializerFactory.kt") + public void testSerializerFactory() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactory.kt"); + } + + @Test + @TestMetadata("serializerFactoryInUserDefined.kt") + public void testSerializerFactoryInUserDefined() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactoryInUserDefined.kt"); + } + @Test @TestMetadata("starProjections.kt") public void testStarProjections() throws Exception { diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrJsBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrJsBoxTestGenerated.java index 17635da2ae8..d9e2e2f3fd0 100644 --- a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrJsBoxTestGenerated.java +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrJsBoxTestGenerated.java @@ -48,4 +48,16 @@ public class SerializationIrJsBoxTestGenerated extends AbstractSerializationIrJs public void testExcludedFromFileExport() throws Exception { runTest("plugins/kotlinx-serialization/testData/boxIr/excludedFromFileExport.kt"); } + + @Test + @TestMetadata("serializerFactory.kt") + public void testSerializerFactory() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactory.kt"); + } + + @Test + @TestMetadata("serializerFactoryInUserDefined.kt") + public void testSerializerFactoryInUserDefined() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializerFactoryInUserDefined.kt"); + } } diff --git a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt index 14768d756b2..d70f54317df 100644 --- a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt +++ b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt @@ -64,6 +64,10 @@ fun main(args: Array) { testClass { model("boxIr") } + + testClass { + model("boxIr") + } } } } diff --git a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt index 47812a871f0..6c66f686ec1 100644 --- a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt +++ b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlinx.serialization.runners +import org.jetbrains.kotlin.js.test.fir.AbstractFirJsBoxTest +import org.jetbrains.kotlin.js.test.fir.AbstractFirJsTest import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.runners.codegen.AbstractFirLightTreeBlackBoxCodegenTest import org.jetbrains.kotlin.test.runners.codegen.AbstractIrBlackBoxCodegenTest @@ -48,4 +50,14 @@ open class AbstractSerializationIrJsBoxTest : AbstractJsIrTest( super.configure(builder) builder.configureForKotlinxSerialization(target = TargetBackend.JS_IR) } -} \ No newline at end of file +} + +open class AbstractSerializationFirJsBoxTest : AbstractFirJsTest( + pathToTestDir = "plugins/kotlinx-serialization/testData/boxIr/", + testGroupOutputDirPrefix = "codegen/serializationBoxFir/" +) { + override fun configure(builder: TestConfigurationBuilder) { + super.configure(builder) + builder.configureForKotlinxSerialization(target = TargetBackend.JS_IR) + } +}