[K/JS] Exclude kotlinx.serialization synthetic declarations from JsExport

^KT-57024 Fixed
This commit is contained in:
Artem Kobzar
2023-02-28 18:11:36 +00:00
committed by Space Team
parent 36ae6d1238
commit 50a462fed1
22 changed files with 359 additions and 49 deletions
+12 -24
View File
@@ -7214,18 +7214,18 @@
<sha256 value="abc222435fa7a892eda76a4a1623ad19792bf5c965426b630c38fb7fdf8a630d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-core" version="1.4.0-RC">
<artifact name="kotlinx-serialization-core-metadata-1.4.0-RC-all.jar">
<md5 value="e593fca534711d7896ea6ef3a3c84bfc" origin="Generated by Gradle"/>
<sha256 value="87ee01517d3418721737b8f02021e917e49b7065d87b8458907bebfac1fc347c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-core" version="1.4.1">
<artifact name="kotlinx-serialization-core-metadata-1.4.1-all.jar">
<md5 value="e6b48fe6c8e4d796541a88f552707ade" origin="Generated by Gradle"/>
<sha256 value="11d00f05f4c0e1a894ef4cbc4370ba818d21ef70ebb015c8731af43751cfa233" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-core-js" version="1.4.1">
<artifact name="kotlinx-serialization-core-jsir-1.4.1.klib">
<md5 value="ddd26a3c17dc14aa0f80af72ced55cee" origin="Generated by Gradle"/>
<sha256 value="18c31786d261abb3ab648c94fedc69f3300baec407ed8994c56b8bc7b3667da5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-core-jvm" version="1.0.0">
<artifact name="kotlinx-serialization-core-jvm-1.0.0.jar">
<md5 value="008b4a519c55ce7534359e19f099c274" origin="Generated by Gradle"/>
@@ -7258,12 +7258,6 @@
<sha256 value="7ef62d1a0114052608d0f541c17b25f1faac17a270d5e26217ac4329ea164752" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-core-jvm" version="1.4.0-RC">
<artifact name="kotlinx-serialization-core-jvm-1.4.0-RC.jar">
<md5 value="6f151fd23347be84bce070eb2f15b47d" origin="Generated by Gradle"/>
<sha256 value="d6651a429223c906aa51faec629c42d59266666d690d67b6bc8c447ec4ea79bb" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-core-jvm" version="1.4.1">
<artifact name="kotlinx-serialization-core-jvm-1.4.1.jar">
<md5 value="a97020d828c89c7df2453bdfd1cd403a" origin="Generated by Gradle"/>
@@ -7316,18 +7310,18 @@
<sha256 value="ec642685d370f3aff4ae3efb8e441296d90db9f28b688d9ed888b25db760b844" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-json" version="1.4.0-RC">
<artifact name="kotlinx-serialization-json-metadata-1.4.0-RC-all.jar">
<md5 value="a60e806a0c3a861cad6522de1a502df7" origin="Generated by Gradle"/>
<sha256 value="f9f6f8a472e98252e679d999e44f07d83d02128ea1b2ca762cbb8d28776f64af" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-json" version="1.4.1">
<artifact name="kotlinx-serialization-json-metadata-1.4.1-all.jar">
<md5 value="47f4431d572e2a2bd68feda535249706" origin="Generated by Gradle"/>
<sha256 value="c316fc2b8445af447f11239388069b781a50e6747b1dc3218b1f155bb9410d19" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-json-js" version="1.4.1">
<artifact name="kotlinx-serialization-json-jsir-1.4.1.klib">
<md5 value="e9511e5aebc1e44c629373329f0a0396" origin="Generated by Gradle"/>
<sha256 value="73ace4a978f0c360cd522a76092ee7e228e5f1fdbeb56e06b257fbb1cef52a55" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-json-jvm" version="1.0.0">
<artifact name="kotlinx-serialization-json-jvm-1.0.0.jar">
<md5 value="a7a87f36305c8bef0b5225fd3ca6bccf" origin="Generated by Gradle"/>
@@ -7360,12 +7354,6 @@
<sha256 value="2a0dd7c162c3cc6d713610b81d809bd5976a140dc9efb1eb7152caf093509965" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-json-jvm" version="1.4.0-RC">
<artifact name="kotlinx-serialization-json-jvm-1.4.0-RC.jar">
<md5 value="df9049885997956336f00a2b409ec1c4" origin="Generated by Gradle"/>
<sha256 value="0d302c3de73ef8db548a5537a522a35eb599ed02a29b579092362bab9c34e1fc" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlinx" name="kotlinx-serialization-json-jvm" version="1.4.1">
<artifact name="kotlinx-serialization-json-jvm-1.4.1.jar">
<md5 value="9c0d33c9b12c371a5d8934c97466eb70" origin="Generated by Gradle"/>
@@ -1,3 +1,7 @@
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.d8.D8RootPlugin
description = "Kotlin Serialization Compiler Plugin"
plugins {
@@ -5,6 +9,23 @@ plugins {
id("jps-compatible")
}
val d8Plugin = D8RootPlugin.apply(rootProject)
d8Plugin.version = v8Version
val jsonJsIrRuntimeForTests: Configuration by configurations.creating {
attributes {
attribute(KotlinPlatformType.attribute, KotlinPlatformType.js)
attribute(KotlinJsCompilerAttribute.jsCompilerAttribute, KotlinJsCompilerAttribute.ir)
}
}
val coreJsIrRuntimeForTests: Configuration by configurations.creating {
attributes {
attribute(KotlinPlatformType.attribute, KotlinPlatformType.js)
attribute(KotlinJsCompilerAttribute.jsCompilerAttribute, KotlinJsCompilerAttribute.ir)
}
}
dependencies {
embedded(project(":kotlinx-serialization-compiler-plugin.common")) { isTransitive = false }
embedded(project(":kotlinx-serialization-compiler-plugin.k1")) { isTransitive = false }
@@ -22,6 +43,7 @@ dependencies {
testApi(projectTests(":compiler:tests-common-new"))
testApi(project(":compiler:fir:plugin-utils"))
testImplementation(projectTests(":generators:test-generator"))
testImplementation(projectTests(":js:js.tests"))
testApiJUnit5()
testImplementation(project(":kotlinx-serialization-compiler-plugin.common"))
@@ -33,6 +55,9 @@ dependencies {
testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1")
testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1")
coreJsIrRuntimeForTests("org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1") { isTransitive = false }
jsonJsIrRuntimeForTests("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") { isTransitive = false }
testRuntimeOnly(intellijCore())
testRuntimeOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
testRuntimeOnly(project(":core:descriptors.runtime"))
@@ -59,6 +84,28 @@ testsJar()
projectTest(parallel = true, jUnitMode = JUnitMode.JUnit5) {
workingDir = rootDir
useJUnitPlatform()
setUpJsIrBoxTests()
}
val generateTests by generator("org.jetbrains.kotlinx.serialization.TestGeneratorKt")
fun Test.setUpJsIrBoxTests() {
dependsOn(d8Plugin.setupTaskProvider)
dependsOn(":kotlin-stdlib-js-ir:compileKotlinJs")
dependsOn(":kotlin-test:kotlin-test-js-ir:compileKotlinJs")
val localJsCoreRuntimeForTests: FileCollection = coreJsIrRuntimeForTests
val localJsJsonRuntimeForTests: FileCollection = jsonJsIrRuntimeForTests
val v8ExecutablePath = d8Plugin.requireConfigured().executablePath.absolutePath
doFirst {
systemProperty("javascript.engine.path.V8", v8ExecutablePath)
systemProperty("serialization.core.path", localJsCoreRuntimeForTests.asPath)
systemProperty("serialization.json.path", localJsJsonRuntimeForTests.asPath)
}
systemProperty("kotlin.js.test.root.out.dir", "$buildDir/")
systemProperty("kotlin.js.full.stdlib.path", "libraries/stdlib/js-ir/build/classes/kotlin/js/main")
systemProperty("kotlin.js.reduced.stdlib.path", "libraries/stdlib/js-ir-minimal-for-test/build/classes/kotlin/js/main")
systemProperty("kotlin.js.kotlin.test.path", "libraries/kotlin.test/js-ir/build/classes/kotlin/js/main")
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.jvm.functionByName
import org.jetbrains.kotlin.backend.jvm.ir.fileParent
import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.deepCopyWithVariables
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.expressions.IrVararg
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
@@ -27,6 +29,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.platform.isJs
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
@@ -64,6 +67,25 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
return throwMissedFieldExceptionFunc != null && throwMissedFieldExceptionArrayFunc != null
}
fun IrDeclaration.excludeFromJsExport() {
if (!compilerContext.platform.isJs()) {
return
}
val jsExportIgnore = compilerContext.jsExportIgnoreClass ?: return
val jsExportIgnoreCtor = jsExportIgnore.primaryConstructor ?: return
annotations += IrConstructorCallImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
jsExportIgnore.defaultType,
jsExportIgnoreCtor.symbol,
jsExportIgnore.typeParameters.size,
jsExportIgnoreCtor.typeParameters.size,
jsExportIgnoreCtor.valueParameters.size,
)
}
private fun getClassListFromFileAnnotation(annotationFqName: FqName): List<IrClassSymbol> {
val annotation = currentClass.fileParent.annotations.findAnnotation(annotationFqName) ?: return emptyList()
val vararg = annotation.getValueArgument(0) as? IrVararg ?: return emptyList()
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.synthetic.syntheticVisibility
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
@@ -60,6 +60,7 @@ class IrPreGenerator(
}
method.apply {
dispatchReceiverParameter = null // function is static
excludeFromJsExport()
}
val typeParams = irClass.typeParameters.map {
@@ -108,7 +109,7 @@ class IrPreGenerator(
val ctor = irClass.addConstructor {
origin = SERIALIZATION_PLUGIN_ORIGIN
visibility = DescriptorVisibilities.PUBLIC
}
}.apply { excludeFromJsExport() }
val markerClassSymbol =
compilerContext.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_CTOR_MARKER_NAME.asString())
val serializableProperties = serializablePropertiesForIrBackend(irClass).serializableProperties
@@ -178,7 +178,7 @@ class SerializableCompanionIrGenerator(
type = compilerContext.irBuiltIns.arrayClass.typeWith(kSerializerStarType)
origin = SERIALIZATION_PLUGIN_ORIGIN
}
return f
return f.apply { excludeFromJsExport() }
}
private fun generateSerializerFactoryIfNeeded(getterDescriptor: IrSimpleFunction) {
@@ -19,6 +19,8 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.findDeclaration
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
@@ -33,6 +35,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.ir.*
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializationJvmIrIntrinsicSupport
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationJsDependenciesClassIds
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
import java.util.concurrent.ConcurrentHashMap
@@ -75,6 +78,16 @@ class SerializationPluginContext(baseContext: IrPluginContext, val metadataPlugi
internal val lazyClass = referenceClass(ClassId.topLevel(SerializationDependencies.LAZY_FQ))!!.owner
internal val lazyValueGetter = lazyClass.getPropertyGetter("value")!!
internal val jsExportIgnoreClass: IrClass? by lazy {
val pkg = SerializationJsDependenciesClassIds.jsExportIgnore.packageFqName
val jsExportName = SerializationJsDependenciesClassIds.jsExportIgnore.parentClassId!!.shortClassName
val jsExportIgnoreFqName = SerializationJsDependenciesClassIds.jsExportIgnore.asSingleFqName()
getClassFromRuntimeOrNull(jsExportName.identifier, pkg)
?.owner
?.findDeclaration { it.fqNameWhenAvailable == jsExportIgnoreFqName }
}
// serialization runtime declarations
internal val enumSerializerFactoryFunc = baseContext.referenceFunctions(
CallableId(
@@ -197,6 +197,10 @@ object SerializationDependencies {
val LAZY_PUBLICATION_MODE_NAME = Name.identifier("PUBLICATION")
}
object SerializationJsDependenciesClassIds {
val jsExportIgnore = ClassId.fromString("kotlin/js/JsExport.Ignore")
}
object SerializersClassIds {
val kSerializerId = ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME)
val enumSerializerId = ClassId(SerializationPackages.internalPackageFqName, Name.identifier(SpecialBuiltins.enumSerializer))
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.platform.jvm.isJvm
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ANNOTATED_ENUM_SERIALIZER_FACTORY_FUNC_NAME
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.inheritableSerialInfoFqName
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.metaSerializableAnnotationFqName
@@ -275,6 +277,11 @@ fun ClassDescriptor.needSerializerFactory(): Boolean {
return true
}
fun DeclarationDescriptor.jsExportIgnore(): AnnotationDescriptor? {
val jsExportIgnore = runIf(platform.isJs()) { module.getJsExportIgnore() } ?: return null
return AnnotationDescriptorImpl(jsExportIgnore.defaultType, mapOf(), jsExportIgnore.source)
}
fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? {
val serializerForClass = serializerDescriptor.serializerForClass
if (serializerForClass != null) return serializerForClass.toClassDescriptor
@@ -7,10 +7,7 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.createDeprecatedAnnotation
import org.jetbrains.kotlin.descriptors.annotations.*
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
@@ -81,7 +78,7 @@ object KSerializerDescriptorResolver {
thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source,
scope,
Modality.FINAL, DescriptorVisibilities.PUBLIC,
Annotations.create(listOf(createDeprecatedHiddenAnnotation(thisDescriptor.module))),
Annotations.create(listOfNotNull(createDeprecatedHiddenAnnotation(thisDescriptor.module), thisDescriptor.jsExportIgnore())),
DescriptorVisibilities.PRIVATE,
serializerKind, false
)
@@ -211,7 +208,7 @@ object KSerializerDescriptorResolver {
needBackingField: Boolean = false
): PropertyDescriptor {
val propertyDescriptor = PropertyDescriptorImpl.create(
thisDescriptor, Annotations.EMPTY, modality, visibility, false, name,
thisDescriptor, Annotations.create(listOfNotNull(thisDescriptor.jsExportIgnore())), modality, visibility, false, name,
CallableMemberDescriptor.Kind.SYNTHESIZED, thisDescriptor.source, false, false, false, false, false, false
)
@@ -225,12 +222,12 @@ object KSerializerDescriptorResolver {
)
val propertyGetter = PropertyGetterDescriptorImpl(
propertyDescriptor, Annotations.EMPTY, modality, visibility, false, false, false,
propertyDescriptor, Annotations.create(listOfNotNull(thisDescriptor.jsExportIgnore())), modality, visibility, false, false, false,
CallableMemberDescriptor.Kind.SYNTHESIZED, null, thisDescriptor.source
)
propertyGetter.initialize(type)
val backingField = if (needBackingField) FieldDescriptorImpl(Annotations.EMPTY, propertyDescriptor) else null
val backingField = if (needBackingField) FieldDescriptorImpl(Annotations.create(listOfNotNull(thisDescriptor.jsExportIgnore())), propertyDescriptor) else null
propertyDescriptor.initialize(propertyGetter, null, backingField, null)
return propertyDescriptor
}
@@ -240,7 +237,11 @@ object KSerializerDescriptorResolver {
name: Name
): SimpleFunctionDescriptor {
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
companionDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, companionDescriptor.source
companionDescriptor,
Annotations.create(listOfNotNull(companionDescriptor.jsExportIgnore())),
name,
CallableMemberDescriptor.Kind.SYNTHESIZED,
companionDescriptor.source
)
val serializableClassOnImplSite = extractKSerializerArgumentFromImplementation(companionDescriptor)
@@ -273,7 +274,7 @@ object KSerializerDescriptorResolver {
): PropertyDescriptor {
val propertyDescriptor = PropertyDescriptorImpl.create(
containingClassDescriptor,
Annotations.EMPTY, Modality.FINAL, visibility, false, name,
Annotations.create(listOfNotNull(containingClassDescriptor.jsExportIgnore())), Modality.FINAL, visibility, false, name,
CallableMemberDescriptor.Kind.SYNTHESIZED, containingClassDescriptor.source, false, false, false, false, false, false
)
val extensionReceiverParameter: ReceiverParameterDescriptor? = null // kludge to disambiguate call
@@ -287,7 +288,7 @@ object KSerializerDescriptorResolver {
val propertyGetter: PropertyGetterDescriptorImpl? = if (createGetter) {
PropertyGetterDescriptorImpl(
propertyDescriptor, Annotations.EMPTY, Modality.FINAL, visibility, false, false, false,
propertyDescriptor, Annotations.create(listOfNotNull(containingClassDescriptor.jsExportIgnore())), Modality.FINAL, visibility, false, false, false,
CallableMemberDescriptor.Kind.SYNTHESIZED, null, containingClassDescriptor.source
).apply { initialize(type) }
} else {
@@ -308,7 +309,7 @@ object KSerializerDescriptorResolver {
val functionDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor,
Annotations.create(listOf(createDeprecatedHiddenAnnotation(classDescriptor.module))),
Annotations.create(listOfNotNull(createDeprecatedHiddenAnnotation(classDescriptor.module), classDescriptor.jsExportIgnore())),
false,
SourceElement.NO_SOURCE
)
@@ -433,7 +434,7 @@ object KSerializerDescriptorResolver {
private fun createSerializerFactoryVarargDescriptor(thisClass: ClassDescriptor): SimpleFunctionDescriptor {
val f = SimpleFunctionDescriptorImpl.create(
thisClass,
Annotations.EMPTY,
Annotations.create(listOfNotNull(thisClass.jsExportIgnore())),
SerialEntityNames.SERIALIZER_PROVIDER_NAME,
CallableMemberDescriptor.Kind.SYNTHESIZED,
thisClass.source
@@ -482,7 +483,7 @@ object KSerializerDescriptorResolver {
): SimpleFunctionDescriptor {
val f = SimpleFunctionDescriptorImpl.create(
thisClass,
Annotations.EMPTY,
Annotations.create(listOfNotNull(thisClass.jsExportIgnore())),
SerialEntityNames.SERIALIZER_PROVIDER_NAME,
CallableMemberDescriptor.Kind.SYNTHESIZED,
thisClass.source
@@ -500,7 +501,6 @@ object KSerializerDescriptorResolver {
return f
}
private fun KotlinType.makeNullableIfNotPrimitive() =
if (KotlinBuiltIns.isPrimitiveType(this)) this
else this.makeNullable()
@@ -508,7 +508,7 @@ object KSerializerDescriptorResolver {
fun createWriteSelfFunctionDescriptor(thisClass: ClassDescriptor): SimpleFunctionDescriptor {
val jvmStaticClass = thisClass.module.findClassAcrossModuleDependencies(StandardClassIds.Annotations.JvmStatic)!!
val jvmStaticAnnotation = AnnotationDescriptorImpl(jvmStaticClass.defaultType, mapOf(), jvmStaticClass.source)
val annotations = Annotations.create(listOf(jvmStaticAnnotation))
val annotations = Annotations.create(listOfNotNull(jvmStaticAnnotation, thisClass.jsExportIgnore()))
val f = SimpleFunctionDescriptorImpl.create(
thisClass,
@@ -82,6 +82,9 @@ fun ClassDescriptor.getKSerializer(): ClassDescriptor =
)
)!!
fun ModuleDescriptor.getJsExportIgnore(): ClassDescriptor? =
findClassAcrossModuleDependencies(SerializationJsDependenciesClassIds.jsExportIgnore)
fun getInternalPackageFqn(classSimpleName: String): FqName =
SerializationPackages.internalPackageFqName.child(Name.identifier(classSimpleName))
@@ -175,8 +175,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
symbol = FirNamedFunctionSymbol(callableId)
origin = SerializationPluginKey.origin
status = original.status.copy(modality = Modality.FINAL)
}
copy.excludeFromJsExport()
return listOf(copy.symbol)
}
@@ -208,6 +208,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
}
}
function.excludeFromJsExport()
return function.symbol
}
@@ -224,6 +226,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
target.resolvedReturnType
)
property.excludeFromJsExport()
return listOf(property.symbol)
}
@@ -270,6 +274,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
}
// TODO: add deprecate hidden
// serializerFirClass.replaceAnnotations(listOf(Annotations.create(listOf(KSerializerDescriptorResolver.createDeprecatedHiddenAnnotation(thisDescriptor.module)))))
serializerFirClass.excludeFromJsExport()
return serializerFirClass.symbol
}
@@ -282,6 +287,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
superType(serializerFactoryClassId.constructClassLikeType(emptyArray(), false))
}
}
return companion.symbol
}
@@ -6,7 +6,9 @@
package org.jetbrains.kotlinx.serialization.compiler.fir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.*
@@ -14,15 +16,28 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.arguments
import org.jetbrains.kotlin.fir.resolve.createSubstitutionForSupertype
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
import org.jetbrains.kotlin.fir.extensions.FirExtension
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.platformSpecificOverridabilityRules
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
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.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlinx.serialization.compiler.fir.services.dependencySerializationInfoProvider
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
@@ -30,6 +45,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotat
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.metaSerializableAnnotationClassId
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoClassId
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialNameAnnotationClassId
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationJsDependenciesClassIds
object AnnotationParameterNames {
val VALUE = Name.identifier("value")
@@ -217,3 +233,27 @@ val ConeKotlinType.isTypeParameter: Boolean
context(FirSession)
val ConeKotlinType.isGeneratedSerializableObject: Boolean
get() = toRegularClassSymbol(this@FirSession)?.let { it.classKind.isObject && it.hasSerializableOrMetaAnnotationWithoutArgs } ?: false
context(FirExtension)
fun FirAnnotationContainer.excludeFromJsExport() {
if (!session.moduleData.platform.isJs()) {
return
}
val jsExportIgnore = session.symbolProvider.getClassLikeSymbolByClassId(SerializationJsDependenciesClassIds.jsExportIgnore)
val jsExportIgnoreAnnotation = jsExportIgnore as? FirRegularClassSymbol ?: return
val jsExportIgnoreConstructor = jsExportIgnoreAnnotation.declarationSymbols.firstIsInstanceOrNull<FirConstructorSymbol>() ?: return
val jsExportIgnoreAnnotationCall = buildAnnotationCall {
argumentList = buildResolvedArgumentList(linkedMapOf())
annotationTypeRef = buildResolvedTypeRef {
type = jsExportIgnoreAnnotation.defaultType()
}
calleeReference = buildResolvedNamedReference {
name = jsExportIgnoreAnnotation.name
resolvedSymbol = jsExportIgnoreConstructor
}
}
replaceAnnotations(annotations + jsExportIgnoreAnnotationCall)
}
@@ -0,0 +1,47 @@
// WITH_STDLIB
// TARGET_BACKEND: JS_IR
// TARGET_BACKEND: JS_IR_ES6
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: lib
// FILE: lib.kt
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.descriptors.*
@JsExport
@Serializable
class Basic(val name: String, val age: UInt)
@JsExport
@Serializable
class WithCompanion(val name: String, val age: UInt) {
companion object {
fun foo() = "Test"
}
}
// FILE: test.js
function box() {
const { Basic, WithCompanion } = this.lib;
if (Basic.Companion === undefined) return "fail: Unfortunatly we can't exclude the companion from export because it would break logic of other plugins";
const basic = new Basic("Test", 44);
if (basic.name !== "Test") return "fail: something wrong with a simple string field access";
if (basic.age !== 44) return "fail: something wrong with a simple uint field access";
if (WithCompanion.Companion === undefined) return "fail: User defined companion should be exported";
if (WithCompanion.Companion.serializer !== undefined) return "fail: serializer fabric should not be exported";
const withCompanion = new WithCompanion("Test", 44);
if (withCompanion.name !== "Test") return "fail: something wrong with a simple string field access";
if (withCompanion.age !== 44) return "fail: something wrong with a simple uint field access";
if (WithCompanion.Companion.foo() !== "Test") return "fail: something wrong with user defined function inside companion"
return "OK"
}
@@ -0,0 +1,51 @@
// WITH_STDLIB
// TARGET_BACKEND: JS_IR
// TARGET_BACKEND: JS_IR_ES6
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: lib
// FILE: lib.kt
@file:JsExport
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.descriptors.*
@Serializable
class Basic(val name: String, val age: UInt)
@Serializable
class WithCompanion(val name: String, val age: UInt) {
companion object {
fun foo() = "Test"
}
}
// FILE: test.js
function box() {
const pkg = this.lib;
const exportedDeclarationNames = Object.keys(pkg);
if (exportedDeclarationNames.length != 2) return "fail: expect to have only 'Basic' and 'WithComapnion' names, but got: " + exportedDeclarationNames.join(", ")
const { Basic, WithCompanion } = pkg;
if (Basic.Companion === undefined) return "fail: Unfortunatly we can't exclude the companion from export because it would break logic of other plugins";
const basic = new Basic("Test", 44);
if (basic.name !== "Test") return "fail: something wrong with a simple string field access";
if (basic.age !== 44) return "fail: something wrong with a simple uint field access";
if (WithCompanion.Companion === undefined) return "fail: User defined companion should be exported";
if (WithCompanion.Companion.serializer !== undefined) return "fail: serializer fabric should not be exported";
const withCompanion = new WithCompanion("Test", 44);
if (withCompanion.name !== "Test") return "fail: something wrong with a simple string field access";
if (withCompanion.age !== 44) return "fail: something wrong with a simple uint field access";
if (WithCompanion.Companion.foo() !== "Test") return "fail: something wrong with user defined function inside companion"
return "OK"
}
@@ -1,3 +1,4 @@
// TARGET_BACKEND: JVM_IR
// WITH_STDLIB
import kotlinx.serialization.*
@@ -33,3 +33,4 @@ package
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -0,0 +1,45 @@
/*
* 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 SerializationIrJsBoxTestGenerated extends AbstractSerializationIrJsBoxTest {
@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("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");
}
}
@@ -56,6 +56,10 @@ fun main(args: Array<String>) {
testClass<AbstractSerializationWithoutRuntimeIrBoxTest> {
model("boxWithoutRuntime")
}
testClass<AbstractSerializationIrJsBoxTest> {
model("boxIr")
}
}
}
}
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.runners.codegen.AbstractFirLightTreeBlackBoxCodegenTest
import org.jetbrains.kotlin.test.runners.codegen.AbstractIrBlackBoxCodegenTest
import org.jetbrains.kotlinx.serialization.configureForKotlinxSerialization
import org.jetbrains.kotlin.js.test.ir.AbstractJsIrTest;
import org.jetbrains.kotlin.test.TargetBackend
open class AbstractSerializationIrBoxTest : AbstractIrBlackBoxCodegenTest() {
override fun configure(builder: TestConfigurationBuilder) {
@@ -30,3 +32,13 @@ open class AbstractSerializationFirLightTreeBlackBoxTest : AbstractFirLightTreeB
builder.configureForKotlinxSerialization()
}
}
open class AbstractSerializationIrJsBoxTest : AbstractJsIrTest(
pathToTestDir = "plugins/kotlinx-serialization/testData/boxIr/",
testGroupOutputDirPrefix = "codegen/serializationBoxIr/"
) {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.configureForKotlinxSerialization(target = TargetBackend.JS_IR)
}
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.bind
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.model.TestModule
@@ -39,15 +40,32 @@ class SerializationEnvironmentConfigurator(
}
}
class SerializationRuntimeClasspathProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) {
class SerializationRuntimeClasspathJvmProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) {
override fun runtimeClassPaths(module: TestModule): List<File> {
return librariesPaths
}
}
fun TestConfigurationBuilder.configureForKotlinxSerialization(noLibraries: Boolean = false) {
useConfigurators(::SerializationEnvironmentConfigurator.bind(noLibraries))
if (!noLibraries) {
useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathProvider)
class SerializationRuntimeClasspathJsProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) {
override fun runtimeClassPaths(module: TestModule): List<File> {
return listOf(
File(System.getProperty("serialization.core.path")!!),
File(System.getProperty("serialization.json.path")!!),
)
}
}
fun TestConfigurationBuilder.configureForKotlinxSerialization(
noLibraries: Boolean = false,
target: TargetBackend = TargetBackend.JVM
) {
useConfigurators(::SerializationEnvironmentConfigurator.bind(noLibraries))
if (!noLibraries) {
when (target) {
TargetBackend.JVM, TargetBackend.JVM_IR -> useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathJvmProvider)
TargetBackend.JS_IR, TargetBackend.JS_IR_ES6 -> useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathJsProvider)
else -> error("Unsupported backend")
}
}
}