Update version to 0.4

Optimize references in generated code. Also fixes Kotlin/kotlinx.serialization/issues/65

Fix (again) broken char boxing

Rebased on 1.2.40 and fixed broken compatibility

Fix https://github.com/Kotlin/kotlinx.serialization/issues/107 and code reformatting

(cherry picked from commit d4c307d)

Add correct type parameter information to synthetic declarations

Needed by kapt due to https://github.com/Kotlin/kotlinx.serialization/issues/76

Make correct call to sealed class constructor

Fixes https://github.com/Kotlin/kotlinx.serialization/issues/112

Bump version

1.2.50-eap-1 compatible
This commit is contained in:
Leonid Startsev
2017-12-22 17:54:07 +03:00
parent 5e19e89dda
commit 97694e65aa
17 changed files with 254 additions and 138 deletions
+2 -1
View File
@@ -17,8 +17,9 @@ dependencies {
val ideaPluginDir: File by rootProject.extra val ideaPluginDir: File by rootProject.extra
val ideaSandboxDir: File by rootProject.extra val ideaSandboxDir: File by rootProject.extra
val serialPluginDir: File by rootProject.extra
runIdeTask("runIde", ideaPluginDir, ideaSandboxDir) { runIdeTask("runIde", ideaPluginDir, ideaSandboxDir, serialPluginDir) {
// TODO: add serialization plugin to pluginDir // TODO: add serialization plugin to pluginDir
dependsOn(":dist", ":ideaPlugin", ":kotlinx-serialization-compiler-plugin:dist") dependsOn(":dist", ":ideaPlugin", ":kotlinx-serialization-compiler-plugin:dist")
} }
@@ -19,7 +19,7 @@
<groupId>org.jetbrains.kotlinx</groupId> <groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-maven-serialization-plugin</artifactId> <artifactId>kotlinx-maven-serialization-plugin</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>0.3</version> <version>0.5.0</version>
<description>Serialization plugin for Maven</description> <description>Serialization plugin for Maven</description>
<repositories> <repositories>
@@ -8,7 +8,7 @@ configureJvmProject(project)
configurePublishing(project) configurePublishing(project)
group = 'org.jetbrains.kotlinx' group = 'org.jetbrains.kotlinx'
version = '0.3' version = '0.5.0'
if (!project.hasProperty("deploy")) { if (!project.hasProperty("deploy")) {
version = "$version-SNAPSHOT" version = "$version-SNAPSHOT"
} }
@@ -1,11 +1,16 @@
description = "Kotlin Serialization Compiler Plugin" description = "Kotlin Serialization Compiler Plugin"
apply { plugin("kotlin") } plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies { dependencies {
compileOnly(ideaSdkCoreDeps("intellij-core")) // val compileOnly by configurations
compileOnly(ideaPluginDeps("maven", plugin = "maven")) // val runtime by configurations
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep())
compileOnly(intellijPluginDep("maven"))
compileOnly(project(":jps-plugin")) compileOnly(project(":jps-plugin"))
compileOnly(project(":compiler:plugin-api")) compileOnly(project(":compiler:plugin-api"))
compileOnly(project(":compiler:frontend")) compileOnly(project(":compiler:frontend"))
@@ -19,8 +24,6 @@ dependencies {
runtime(projectRuntimeJar(":kotlin-compiler")) runtime(projectRuntimeJar(":kotlin-compiler"))
runtime(projectDist(":kotlin-stdlib")) runtime(projectDist(":kotlin-stdlib"))
// val compileOnly by configurations
// val runtime by configurations
} }
sourceSets { sourceSets {
@@ -1,7 +1,7 @@
<idea-plugin url="https://github.com/Kotlin/kotlinx.serialization" > <idea-plugin url="https://github.com/Kotlin/kotlinx.serialization" >
<name>Kotlin-serialization</name> <name>Kotlin-serialization</name>
<id>org.jetbrains.kotlinx.serialization</id> <id>org.jetbrains.kotlinx.serialization</id>
<version>0.3</version> <version>0.5.0</version>
<depends>org.jetbrains.kotlin</depends> <depends>org.jetbrains.kotlin</depends>
<idea-version since-build="172"/> <idea-version since-build="172"/>
@@ -28,7 +28,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
import org.jetbrains.kotlin.types.typeUtil.isBoolean
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
@@ -36,29 +39,32 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySe
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
open class SerialTypeInfo( open class SerialTypeInfo(
val property: SerializableProperty, val property: SerializableProperty,
val elementMethodPrefix: String, val elementMethodPrefix: String,
val serializer: ClassDescriptor? = null, val serializer: ClassDescriptor? = null,
val unit: Boolean = false val unit: Boolean = false
) )
fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
val T = property.type val T = property.type
return when { return when {
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null) T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(property, T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
T.nameIfStandardType.toString().capitalize()) property,
T.nameIfStandardType.toString().capitalize()
)
KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String") KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String")
KotlinBuiltIns.isUnit(T) -> SerialTypeInfo(property, "Unit", unit = true) KotlinBuiltIns.isUnit(T) -> SerialTypeInfo(property, "Unit", unit = true)
KotlinBuiltIns.isPrimitiveArray(T) -> TODO("primitive arrays are not supported yet") KotlinBuiltIns.isPrimitiveArray(T) -> TODO("primitive arrays are not supported yet")
KotlinBuiltIns.isNonPrimitiveArray(T.toClassDescriptor!!) -> { KotlinBuiltIns.isNonPrimitiveArray(T.toClassDescriptor!!) -> {
val serializer = property.serializableWith?.toClassDescriptor ?: val serializer = property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(
property.module.findClassAcrossModuleDependencies(referenceArraySerializerId) referenceArraySerializerId
)
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer) SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
} }
T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> { T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> {
val serializer = property.serializableWith?.toClassDescriptor ?: val serializer =
property.module.findClassAcrossModuleDependencies(enumSerializerId) property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(enumSerializerId)
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer) SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
} }
else -> { else -> {
@@ -72,9 +78,9 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescri
return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module) return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module)
else if (kType.isTypeParameter()) return null else if (kType.isTypeParameter()) return null
else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type
?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer ?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer
?: findEnumTypeSerializer(module, kType) ?: findEnumTypeSerializer(module, kType)
?: module.findClassAcrossModuleDependencies(contextSerializerId) ?: module.findClassAcrossModuleDependencies(contextSerializerId)
} }
fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
@@ -110,8 +116,8 @@ fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDe
fun KotlinType.requiresPolymorphism(): Boolean { fun KotlinType.requiresPolymorphism(): Boolean {
return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true
|| (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class || (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class
|| this.containsTypeProjectionsInTopLevelArguments() // List<*> || this.containsTypeProjectionsInTopLevelArguments() // List<*>
} }
fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor { fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor {
@@ -119,20 +125,23 @@ fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor {
} }
fun KtPureClassOrObject.bodyPropertiesDescriptorsMap(bindingContext: BindingContext): Map<PropertyDescriptor, KtProperty> = declarations fun KtPureClassOrObject.bodyPropertiesDescriptorsMap(bindingContext: BindingContext): Map<PropertyDescriptor, KtProperty> = declarations
.asSequence() .asSequence()
.filterIsInstance<KtProperty>() .filterIsInstance<KtProperty>()
.associateBy { (bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? PropertyDescriptor)!! } // can filter here because it's impossible to create body property w/ backing field w/o explicit delegating or initializing
.filter { it.delegateExpressionOrInitializer != null }
.associateBy { (bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? PropertyDescriptor)!! }
fun KtPureClassOrObject.primaryPropertiesDescriptorsMap(bindingContext: BindingContext): Map<PropertyDescriptor, KtParameter> = primaryConstructorParameters fun KtPureClassOrObject.primaryPropertiesDescriptorsMap(bindingContext: BindingContext): Map<PropertyDescriptor, KtParameter> =
primaryConstructorParameters
.asSequence() .asSequence()
.filter { it.hasValOrVar() } .filter { it.hasValOrVar() }
.associateBy { bindingContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!! } .associateBy { bindingContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!! }
fun KtPureClassOrObject.anonymousInitializers() = declarations fun KtPureClassOrObject.anonymousInitializers() = declarations
.asSequence() .asSequence()
.filterIsInstance<KtAnonymousInitializer>() .filterIsInstance<KtAnonymousInitializer>()
.mapNotNull { it.body } .mapNotNull { it.body }
.toList() .toList()
fun SerializableProperty.annotationVarsAndDesc(annotationClass: ClassDescriptor): Pair<List<ValueArgument>, List<ValueParameterDescriptor>> { fun SerializableProperty.annotationVarsAndDesc(annotationClass: ClassDescriptor): Pair<List<ValueArgument>, List<ValueParameterDescriptor>> {
val args: List<ValueArgument> = (this.descriptor.annotations.findAnnotation(annotationClass.fqNameSafe) as? LazyAnnotationDescriptor)?.annotationEntry?.valueArguments.orEmpty() val args: List<ValueArgument> = (this.descriptor.annotations.findAnnotation(annotationClass.fqNameSafe) as? LazyAnnotationDescriptor)?.annotationEntry?.valueArguments.orEmpty()
@@ -16,10 +16,12 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.js package org.jetbrains.kotlinx.serialization.compiler.backend.js
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
internal class JsBlockBuilder { internal class JsBlockBuilder {
@@ -91,4 +93,12 @@ internal fun propNotSeenTest(seenVar: JsNameRef, index: Int): JsBinaryOperation
JsIntLiteral(1 shl (index % 32)) JsIntLiteral(1 shl (index % 32))
), ),
JsIntLiteral(0) JsIntLiteral(0)
) )
internal fun TranslationContext.serializerObjectGetter(serializer: ClassDescriptor): JsExpression {
return ReferenceTranslator.translateAsValueReference(serializer, this)
}
internal fun TranslationContext.translateQualifiedReference(clazz: ClassDescriptor): JsExpression {
return ReferenceTranslator.translateAsTypeReference(clazz, this)
}
@@ -17,7 +17,9 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.js package org.jetbrains.kotlinx.serialization.compiler.backend.js
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsInvocation import org.jetbrains.kotlin.js.backend.ast.JsInvocation
import org.jetbrains.kotlin.js.backend.ast.JsNameRef import org.jetbrains.kotlin.js.backend.ast.JsNameRef
import org.jetbrains.kotlin.js.backend.ast.JsReturn import org.jetbrains.kotlin.js.backend.ast.JsReturn
@@ -33,8 +35,8 @@ class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
val f = context.buildFunction(methodDescriptor) {jsFun, context -> val f = context.buildFunction(methodDescriptor) {jsFun, context ->
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!! val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
val stmt = if (serializableDescriptor.declaredTypeParameters.isEmpty()) { val stmt: JsExpression = if (serializer.kind == ClassKind.OBJECT) {
context.getQualifiedReference(serializer) context.serializerObjectGetter(serializer)
} else { } else {
val args = jsFun.parameters.map { JsNameRef(it.name) } val args = jsFun.parameters.map { JsNameRef(it.name) }
val ref = context.getInnerNameForDescriptor( val ref = context.getInnerNameForDescriptor(
@@ -35,25 +35,32 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryProper
import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
class SerializableJsTranslator(val declaration: KtPureClassOrObject, class SerializableJsTranslator(
val translator: DeclarationBodyVisitor, val declaration: KtPureClassOrObject,
val context: TranslationContext) : SerializableCodegen(declaration, context.bindingContext()) { val translator: DeclarationBodyVisitor,
val context: TranslationContext
) : SerializableCodegen(declaration, context.bindingContext()) {
val initMap: Map<PropertyDescriptor, KtExpression?> = declaration.run { private val initMap: Map<PropertyDescriptor, KtExpression?> = declaration.run {
(bodyPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.delegateExpressionOrInitializer } + (bodyPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.delegateExpressionOrInitializer } +
primaryPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.defaultValue }) primaryPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.defaultValue })
} }
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) { override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) {
val missingExceptionClassRef = serializableDescriptor.getClassFromSerializationPackage("MissingFieldException") val missingExceptionClassRef = serializableDescriptor.getClassFromSerializationPackage("MissingFieldException")
.let { context.getQualifiedReference(it) } .let { context.translateQualifiedReference(it) }
val f = context.buildFunction(constructorDescriptor) { jsFun, context -> val f = context.buildFunction(constructorDescriptor) { jsFun, context ->
val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef() val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef()
val context = context.innerContextWithAliased(serializableDescriptor.thisAsReceiverParameter, thiz) val context = context.innerContextWithAliased(serializableDescriptor.thisAsReceiverParameter, thiz)
+JsVars(JsVars.JsVar(thiz.name, Namer.createObjectWithPrototypeFrom(context.getQualifiedReference(serializableDescriptor)))) +JsVars(
JsVars.JsVar(
thiz.name,
Namer.createObjectWithPrototypeFrom(context.getInnerNameForDescriptor(serializableDescriptor).makeRef())
)
)
val seenVar = jsFun.parameters[0].name.makeRef() val seenVar = jsFun.parameters[0].name.makeRef()
for ((index, prop) in properties.serializableProperties.withIndex()) { for ((index, prop) in properties.serializableProperties.withIndex()) {
val paramRef = jsFun.parameters[index + 1].name.makeRef() val paramRef = jsFun.parameters[index + 1].name.makeRef()
@@ -64,8 +71,7 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject,
val initializer = initMap.getValue(prop.descriptor) ?: throw IllegalArgumentException("optional without an initializer") val initializer = initMap.getValue(prop.descriptor) ?: throw IllegalArgumentException("optional without an initializer")
val initExpr = Translation.translateAsExpression(initializer, context) val initExpr = Translation.translateAsExpression(initializer, context)
TranslationUtils.assignmentToBackingField(context, prop.descriptor, initExpr).makeStmt() TranslationUtils.assignmentToBackingField(context, prop.descriptor, initExpr).makeStmt()
} } else {
else {
JsThrow(JsNew(missingExceptionClassRef, listOf(JsStringLiteral(prop.name)))) JsThrow(JsNew(missingExceptionClassRef, listOf(JsStringLiteral(prop.name))))
} }
// (seen & 1 << i == 0) -- not seen // (seen & 1 << i == 0) -- not seen
@@ -75,14 +81,14 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject,
//transient initializers and init blocks //transient initializers and init blocks
val serialDescs = properties.serializableProperties.map { it.descriptor } val serialDescs = properties.serializableProperties.map { it.descriptor }
(initMap - serialDescs).forEach { (desc, expr) -> (initMap - serialDescs).forEach { (desc, expr) ->
val e = requireNotNull(expr) {"transient without an initializer"} val e = requireNotNull(expr) { "transient without an initializer" }
val initExpr = Translation.translateAsExpression(e, context) val initExpr = Translation.translateAsExpression(e, context)
+TranslationUtils.assignmentToBackingField(context, desc, initExpr).makeStmt() +TranslationUtils.assignmentToBackingField(context, desc, initExpr).makeStmt()
} }
declaration.anonymousInitializers() declaration.anonymousInitializers()
.forEach { Translation.translateAsExpression(it, context, this.block) } .forEach { Translation.translateAsExpression(it, context, this.block) }
+JsReturn(thiz) +JsReturn(thiz)
} }
@@ -96,7 +102,12 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject,
} }
companion object { companion object {
fun translate(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) { fun translate(
declaration: KtPureClassOrObject,
descriptor: ClassDescriptor,
translator: DeclarationBodyVisitor,
context: TranslationContext
) {
if (descriptor.isInternalSerializable) if (descriptor.isInternalSerializable)
SerializableJsTranslator(declaration, translator, context).generate() SerializableJsTranslator(declaration, translator, context).generate()
} }
@@ -80,7 +80,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
val argExprs = args.map { arg -> val argExprs = args.map { arg ->
Translation.translateAsExpression(arg.getArgumentExpression()!!, context) Translation.translateAsExpression(arg.getArgumentExpression()!!, context)
} }
val classRef = context.getQualifiedReference(annotationClass) val classRef = context.translateQualifiedReference(annotationClass)
val invok = JsInvocation(JsNameRef(context.getNameForDescriptor(pushFunc), serialClassDescRef), JsNew(classRef, argExprs)) val invok = JsInvocation(JsNameRef(context.getNameForDescriptor(pushFunc), serialClassDescRef), JsNew(classRef, argExprs))
translator.addInitializerStatement(invok.makeStmt()) translator.addInitializerStatement(invok.makeStmt())
} }
@@ -101,7 +101,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
val f = context.buildFunction(typedConstructorDescriptor) { jsFun, context -> val f = context.buildFunction(typedConstructorDescriptor) { jsFun, context ->
val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef() val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef()
+JsVars(JsVars.JsVar(thiz.name, JsNew(getQualifiedClassReferenceName(serializerDescriptor)))) +JsVars(JsVars.JsVar(thiz.name, JsNew(context.getInnerNameForDescriptor(serializerDescriptor).makeRef())))
jsFun.parameters.forEachIndexed { i, parameter -> jsFun.parameters.forEachIndexed { i, parameter ->
val thisFRef = JsNameRef(context.scope().declareName("$typeArgPrefix$i"), thiz) val thisFRef = JsNameRef(context.scope().declareName("$typeArgPrefix$i"), thiz)
+JsAstUtils.assignment(thisFRef, JsNameRef(parameter.name)).makeStmt() +JsAstUtils.assignment(thisFRef, JsNameRef(parameter.name)).makeStmt()
@@ -170,19 +170,15 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
+JsInvocation(JsNameRef(wEndFunc, localOutputRef), serialClassDescRef).makeStmt() +JsInvocation(JsNameRef(wEndFunc, localOutputRef), serialClassDescRef).makeStmt()
} }
private fun getQualifiedClassReferenceName(classDescriptor: ClassDescriptor): JsExpression {
return context.getQualifiedReference(classDescriptor)
}
private fun serializerInstance(serializerClass: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, genericIndex: Int? = null): JsExpression? { private fun serializerInstance(serializerClass: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, genericIndex: Int? = null): JsExpression? {
val nullableSerClass = getQualifiedClassReferenceName(requireNotNull( val nullableSerClass = context.translateQualifiedReference(requireNotNull(
module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier("NullableSerializer"))))) module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier("NullableSerializer")))))
if (serializerClass == null) { if (serializerClass == null) {
if (genericIndex == null) return null if (genericIndex == null) return null
return JsNameRef(context.scope().declareName("$typeArgPrefix$genericIndex"), JsThisRef()) return JsNameRef(context.scope().declareName("$typeArgPrefix$genericIndex"), JsThisRef())
} }
if (serializerClass.kind == ClassKind.OBJECT) { if (serializerClass.kind == ClassKind.OBJECT) {
return getQualifiedClassReferenceName(serializerClass) return context.serializerObjectGetter(serializerClass)
} }
else { else {
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId) var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
@@ -197,9 +193,9 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
val serializable = getSerializableClassDescriptorBySerializer(serializerClass) val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) { val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor) val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
JsInvocation(context.getInnerNameForDescriptor(desc).makeRef(), args) JsInvocation(context.getInnerReference(desc), args)
} else { } else {
JsNew(getQualifiedClassReferenceName(serializerClass), args) JsNew(context.translateQualifiedReference(serializerClass), args)
} }
return ref return ref
} }
@@ -207,7 +203,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
private fun createGetKClassExpression(classDescriptor: ClassDescriptor): JsExpression = private fun createGetKClassExpression(classDescriptor: ClassDescriptor): JsExpression =
JsInvocation(context.namer().kotlin("getKClass"), JsInvocation(context.namer().kotlin("getKClass"),
getQualifiedClassReferenceName(classDescriptor)) context.translateQualifiedReference(classDescriptor))
override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context -> override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context ->
@@ -312,9 +308,15 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
} }
// char unboxing crutch // char unboxing crutch
if (KotlinBuiltIns.isCharOrNullableChar(property.type)) { if (KotlinBuiltIns.isCharOrNullableChar(property.type)) {
// can't use KotlinCompilerVersion.VERSION because javac inlines final string literal :(
val coerceTo = if (KotlinVersion.CURRENT.run { major == 1 && minor == 2 && patch in (0..10) }) {
context.currentModule.builtIns.charType
} else {
TranslationUtils.getReturnTypeForCoercion(property.descriptor)
}
+JsAstUtils.assignment( +JsAstUtils.assignment(
localProps[i], localProps[i],
TranslationUtils.coerce(context, localProps[i], context.currentModule.builtIns.charType) TranslationUtils.coerce(context, localProps[i], coerceTo)
).makeStmt() ).makeStmt()
} }
@@ -335,7 +337,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
// default: throw // default: throw
default { default {
val excClassRef = serializableDescriptor.getClassFromSerializationPackage("UnknownFieldException") val excClassRef = serializableDescriptor.getClassFromSerializationPackage("UnknownFieldException")
.let { context.getQualifiedReference(it) } .let { context.translateQualifiedReference(it) }
+JsThrow(JsNew(excClassRef, listOf(indexVar))) +JsThrow(JsNew(excClassRef, listOf(indexVar)))
} }
} }
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -182,7 +183,15 @@ class SerializableCodegenImpl(
{ "Non-serializable parent of serializable $serializableDescriptor must have no arg constructor" }) { "Non-serializable parent of serializable $serializableDescriptor must have no arg constructor" })
// call // call
invokespecial(superType, "<init>", "()V", false) // Sealed classes have private <init> so they cannot be inherited from Java src
// public <init> is synthetic and contains additional parameter
val desc = if (DescriptorUtils.isSealedClass(superClass)) {
aconst(null)
"(Lkotlin/jvm/internal/DefaultConstructorMarker;)V"
} else {
"()V"
}
invokespecial(superType, "<init>", desc, false)
return 0 to propStartVar return 0 to propStartVar
} }
else { else {
@@ -30,4 +30,7 @@ class SerializationCodegenExtension : ExpressionCodegenExtension {
SerializerCodegenImpl.generateSerializerExtensions(codegen) SerializerCodegenImpl.generateSerializerExtensions(codegen)
SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen) SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen)
} }
override val shouldGenerateClassSyntheticPartsInLightClassesMode: Boolean
get() = false
} }
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
@@ -42,30 +43,49 @@ class SerializationResolveExtension : SyntheticResolveExtension {
else -> emptyList() else -> emptyList()
} }
override fun generateSyntheticClasses(thisDescriptor: ClassDescriptor, name: Name, ctx: LazyClassContext, declarationProvider: ClassMemberDeclarationProvider, result: MutableSet<ClassDescriptor>) { override fun generateSyntheticClasses(
thisDescriptor: ClassDescriptor,
name: Name,
ctx: LazyClassContext,
declarationProvider: ClassMemberDeclarationProvider,
result: MutableSet<ClassDescriptor>
) {
if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && name == KSerializerDescriptorResolver.IMPL_NAME) if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && name == KSerializerDescriptorResolver.IMPL_NAME)
result.add(KSerializerDescriptorResolver.addSerialInfoImplClass(thisDescriptor, declarationProvider, ctx)) result.add(KSerializerDescriptorResolver.addSerialInfoImplClass(thisDescriptor, declarationProvider, ctx))
else if (thisDescriptor.isInternalSerializable && name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME && else if (thisDescriptor.isInternalSerializable && name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME &&
result.none { it.name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME }) result.none { it.name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME }
)
result.add(KSerializerDescriptorResolver.addSerializerImplClass(thisDescriptor, declarationProvider, ctx)) result.add(KSerializerDescriptorResolver.addSerializerImplClass(thisDescriptor, declarationProvider, ctx))
return return
} }
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? = override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? =
if (thisDescriptor.isInternalSerializable) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT if (thisDescriptor.isInternalSerializable) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
else null else null
override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) { override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes) KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes)
KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes) KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes)
} }
override fun generateSyntheticMethods(thisDescriptor: ClassDescriptor, name: Name, fromSupertypes: List<SimpleFunctionDescriptor>, result: MutableCollection<SimpleFunctionDescriptor>) { override fun generateSyntheticMethods(
thisDescriptor: ClassDescriptor,
name: Name,
bindingContext: BindingContext,
fromSupertypes: List<SimpleFunctionDescriptor>,
result: MutableCollection<SimpleFunctionDescriptor>
) {
KSerializerDescriptorResolver.generateSerializerMethods(thisDescriptor, fromSupertypes, name, result) KSerializerDescriptorResolver.generateSerializerMethods(thisDescriptor, fromSupertypes, name, result)
KSerializerDescriptorResolver.generateCompanionObjectMethods(thisDescriptor, fromSupertypes, name, result) KSerializerDescriptorResolver.generateCompanionObjectMethods(thisDescriptor, fromSupertypes, name, result)
} }
override fun generateSyntheticProperties(thisDescriptor: ClassDescriptor, name: Name, fromSupertypes: ArrayList<PropertyDescriptor>, result: MutableSet<PropertyDescriptor>) { override fun generateSyntheticProperties(
thisDescriptor: ClassDescriptor,
name: Name,
bindingContext: BindingContext,
fromSupertypes: ArrayList<PropertyDescriptor>,
result: MutableSet<PropertyDescriptor>
) {
KSerializerDescriptorResolver.generateDescriptorsForAnnotationImpl(thisDescriptor, name, fromSupertypes, result) KSerializerDescriptorResolver.generateDescriptorsForAnnotationImpl(thisDescriptor, name, fromSupertypes, result)
KSerializerDescriptorResolver.generateSerializerProperties(thisDescriptor, fromSupertypes, name, result) KSerializerDescriptorResolver.generateSerializerProperties(thisDescriptor, fromSupertypes, name, result)
} }
@@ -28,7 +28,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.createProjection import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import java.util.* import java.util.*
@@ -74,7 +77,7 @@ object KSerializerDescriptorResolver {
val interfaceDecl = declarationProvider.correspondingClassOrObject!! val interfaceDecl = declarationProvider.correspondingClassOrObject!!
val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor) val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor)
return SyntheticClassOrObjectDescriptor(ctx, val descriptor = SyntheticClassOrObjectDescriptor(ctx,
interfaceDecl, interfaceDecl,
interfaceDesc, interfaceDesc,
IMPL_NAME, IMPL_NAME,
@@ -85,18 +88,35 @@ object KSerializerDescriptorResolver {
Visibilities.PRIVATE, Visibilities.PRIVATE,
ClassKind.CLASS, ClassKind.CLASS,
false) false)
descriptor.initialize()
return descriptor
} }
fun addSerializerImplClass(thisDescriptor: ClassDescriptor, declarationProvider: ClassMemberDeclarationProvider, ctx: LazyClassContext): ClassDescriptor { fun addSerializerImplClass(
thisDescriptor: ClassDescriptor,
declarationProvider: ClassMemberDeclarationProvider,
ctx: LazyClassContext
): ClassDescriptor {
val thisDeclaration = declarationProvider.correspondingClassOrObject!! val thisDeclaration = declarationProvider.correspondingClassOrObject!!
val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor) val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor)
val serializerKind = if (thisDescriptor.declaredTypeParameters.isNotEmpty()) ClassKind.CLASS else ClassKind.OBJECT val serializerKind = if (thisDescriptor.declaredTypeParameters.isNotEmpty()) ClassKind.CLASS else ClassKind.OBJECT
return SyntheticClassOrObjectDescriptor(ctx, val serializerDescriptor = SyntheticClassOrObjectDescriptor(
thisDeclaration, ctx,
thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source, thisDeclaration,
scope, thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source,
Modality.FINAL, Visibilities.PUBLIC, Visibilities.PRIVATE, scope,
serializerKind, false) Modality.FINAL, Visibilities.PUBLIC, Visibilities.PRIVATE,
serializerKind, false
)
val typeParameters: List<TypeParameterDescriptor> =
thisDescriptor.declaredTypeParameters.mapIndexed { index, param ->
TypeParameterDescriptorImpl.createWithDefaultBound(
serializerDescriptor, Annotations.EMPTY, false, Variance.INVARIANT,
param.name, index
)
}
serializerDescriptor.initialize(typeParameters)
return serializerDescriptor
} }
fun generateSerializerProperties(thisDescriptor: ClassDescriptor, fun generateSerializerProperties(thisDescriptor: ClassDescriptor,
@@ -110,10 +130,12 @@ object KSerializerDescriptorResolver {
} }
fun generateCompanionObjectMethods(thisDescriptor: ClassDescriptor, fun generateCompanionObjectMethods(
fromSupertypes: List<SimpleFunctionDescriptor>, thisDescriptor: ClassDescriptor,
name: Name, fromSupertypes: List<SimpleFunctionDescriptor>,
result: MutableCollection<SimpleFunctionDescriptor>) { name: Name,
result: MutableCollection<SimpleFunctionDescriptor>
) {
val classDescriptor = getSerializableClassDescriptorByCompanion(thisDescriptor) ?: return val classDescriptor = getSerializableClassDescriptorByCompanion(thisDescriptor) ?: return
if (name == SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == classDescriptor.declaredTypeParameters.size }) { if (name == SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == classDescriptor.declaredTypeParameters.size }) {
@@ -248,24 +270,32 @@ object KSerializerDescriptorResolver {
return functionDescriptor return functionDescriptor
} }
fun createTypedSerializerConstructorDescriptor(classDescriptor: ClassDescriptor, serializableDescriptor: ClassDescriptor): ConstructorDescriptor { fun createTypedSerializerConstructorDescriptor(
classDescriptor: ClassDescriptor,
serializableDescriptor: ClassDescriptor
): ConstructorDescriptor {
val constrDesc = ClassConstructorDescriptorImpl.createSynthesized( val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor, classDescriptor,
Annotations.EMPTY, Annotations.EMPTY,
false, false,
classDescriptor.source classDescriptor.source
) )
val serializerClass = classDescriptor.getClassFromSerializationPackage("KSerializer") val serializerClass = classDescriptor.getClassFromSerializationPackage("KSerializer")
val targs = mutableListOf<TypeParameterDescriptor>() val targs = mutableListOf<TypeParameterDescriptor>()
val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, _ -> val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, param ->
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(constrDesc, Annotations.EMPTY, false, Variance.INVARIANT, val targ = TypeParameterDescriptorImpl.createWithDefaultBound(
Name.identifier("T$index"), index) constrDesc, Annotations.EMPTY, false, Variance.INVARIANT,
param.name, index
)
val pType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType))) val pType =
KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType)))
targs.add(targ) targs.add(targ)
ValueParameterDescriptorImpl(constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType, ValueParameterDescriptorImpl(
false, false, false, null, constrDesc.source) constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType,
false, false, false, null, constrDesc.source
)
} }
constrDesc.initialize(args, Visibilities.PUBLIC, targs) constrDesc.initialize(args, Visibilities.PUBLIC, targs)
@@ -274,7 +304,13 @@ object KSerializerDescriptorResolver {
} }
fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor { fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor {
val f = SimpleFunctionDescriptorImpl.create(thisClass, Annotations.EMPTY, SERIALIZER_PROVIDER_NAME, CallableMemberDescriptor.Kind.SYNTHESIZED, thisClass.source) val f = SimpleFunctionDescriptorImpl.create(
thisClass,
Annotations.EMPTY,
SERIALIZER_PROVIDER_NAME,
CallableMemberDescriptor.Kind.SYNTHESIZED,
thisClass.source
)
val serializerClass = thisClass.getClassFromSerializationPackage("KSerializer") val serializerClass = thisClass.getClassFromSerializationPackage("KSerializer")
val args = mutableListOf<ValueParameterDescriptor>() val args = mutableListOf<ValueParameterDescriptor>()
@@ -282,31 +318,38 @@ object KSerializerDescriptorResolver {
var i = 0 var i = 0
serializableClass.declaredTypeParameters.forEach { it -> serializableClass.declaredTypeParameters.forEach { it ->
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(f, Annotations.EMPTY, false, Variance.INVARIANT, val targ = TypeParameterDescriptorImpl.createWithDefaultBound(
Name.identifier("T$i"), i) f, Annotations.EMPTY, false, Variance.INVARIANT,
Name.identifier("T$i"), i
)
val pType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType))) val pType =
KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType)))
args.add(ValueParameterDescriptorImpl( args.add(
ValueParameterDescriptorImpl(
f, f,
null, null,
i, i,
Annotations.EMPTY, Annotations.EMPTY,
Name.identifier("$typeArgPrefix${i}"), Name.identifier("$typeArgPrefix$i"),
pType, pType,
false, false,
false, false,
false, false,
null, null,
f.source f.source
)) )
)
typeArgs.add(targ) typeArgs.add(targ)
i++ i++
} }
val newSerializableType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializableClass, typeArgs.map { TypeProjectionImpl(it.defaultType) }) val newSerializableType =
val serialReturnType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(newSerializableType))) KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializableClass, typeArgs.map { TypeProjectionImpl(it.defaultType) })
val serialReturnType =
KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(newSerializableType)))
f.initialize(null, thisClass.thisAsReceiverParameter, typeArgs, args, serialReturnType, Modality.FINAL, Visibilities.PUBLIC) f.initialize(null, thisClass.thisAsReceiverParameter, typeArgs, args, serialReturnType, Modality.FINAL, Visibilities.PUBLIC)
return f return f
@@ -19,51 +19,52 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) { class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
private val primaryConstructorParameters: List<ValueParameterDescriptor> = private val primaryConstructorParameters: List<ValueParameterDescriptor> =
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList() serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean> = private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean> =
primaryConstructorParameters.asSequence() primaryConstructorParameters.asSequence()
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.hasDefaultValue() } .map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() }
.mapNotNull { (a, b) -> if (a == null) null else a to b } .mapNotNull { (a, b) -> if (a == null) null else a to b }
.toMap() .toMap()
val isExternallySerializable: Boolean = val isExternallySerializable: Boolean =
primaryConstructorParameters.size == primaryConstructorProperties.size primaryConstructorParameters.size == primaryConstructorProperties.size
val serializableProperties: List<SerializableProperty> = val serializableProperties: List<SerializableProperty> =
serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.asSequence() .asSequence()
.filterIsInstance<PropertyDescriptor>() .filterIsInstance<PropertyDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION } .filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
.filter(this::isPropSerializable) .filter(this::isPropSerializable)
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) } .map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) }
.partition { primaryConstructorProperties.contains(it.descriptor) } .partition { primaryConstructorProperties.contains(it.descriptor) }
.run { .run {
val supers = serializableClass.getSuperClassNotAny() val supers = serializableClass.getSuperClassNotAny()
if (supers == null || !supers.isInternalSerializable) if (supers == null || !supers.isInternalSerializable)
first + second first + second
else else
SerializableProperties(supers, bindingContext).serializableProperties + first + second SerializableProperties(supers, bindingContext).serializableProperties + first + second
} }
private fun isPropSerializable(it: PropertyDescriptor) = private fun isPropSerializable(it: PropertyDescriptor) =
if (serializableClass.isInternalSerializable) !it.annotations.serialTransient if (serializableClass.isInternalSerializable) !it.annotations.serialTransient
else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(it)) else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(
it
))
val serializableConstructorProperties: List<SerializableProperty> = val serializableConstructorProperties: List<SerializableProperty> =
serializableProperties.asSequence() serializableProperties.asSequence()
.filter { primaryConstructorProperties.contains(it.descriptor) } .filter { primaryConstructorProperties.contains(it.descriptor) }
.toList() .toList()
val serializableStandaloneProperties: List<SerializableProperty> = val serializableStandaloneProperties: List<SerializableProperty> =
serializableProperties.minus(serializableConstructorProperties) serializableProperties.minus(serializableConstructorProperties)
val size = serializableProperties.size val size = serializableProperties.size
val indices = serializableProperties.indices val indices = serializableProperties.indices
@@ -34,12 +34,13 @@ class KotlinSerializationJpsPlugin : KotlinJpsCompilerArgumentsProvider {
override fun getClasspath(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List<String> { override fun getClasspath(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List<String> {
val inJar = File(PathUtil.getJarPathForClass(this::class.java)).isFile val inJar = File(PathUtil.getJarPathForClass(this::class.java)).isFile
return listOf( return listOf(
if (inJar) { if (inJar) {
File(PathUtil.getJarPathForClass(this::class.java)).absolutePath File(PathUtil.getJarPathForClass(this::class.java)).absolutePath
} else { } else {
// We're in tests now // We're in tests now
val kotlinProjectDirectory = File(PathUtil.getJarPathForClass(javaClass)).parentFile.parentFile.parentFile val kotlinProjectDirectory = File(PathUtil.getJarPathForClass(javaClass)).parentFile.parentFile.parentFile
File(kotlinProjectDirectory, "dist/artifacts/Serialization/lib/$JAR_FILE_NAME").absolutePath File(kotlinProjectDirectory, "dist/artifacts/Serialization/lib/$JAR_FILE_NAME").absolutePath
}) }
)
} }
} }
+2 -1
View File
@@ -17,9 +17,10 @@ val intellijUltimateEnabled : Boolean by rootProject.extra
val ideaUltimatePluginDir: File by rootProject.extra val ideaUltimatePluginDir: File by rootProject.extra
val ideaUltimateSandboxDir: File by rootProject.extra val ideaUltimateSandboxDir: File by rootProject.extra
val serialPluginDir: File by rootProject.extra
if (intellijUltimateEnabled) { if (intellijUltimateEnabled) {
runIdeTask("runUltimate", ideaUltimatePluginDir, ideaUltimateSandboxDir) { runIdeTask("runUltimate", ideaUltimatePluginDir, ideaUltimateSandboxDir, serialPluginDir) {
dependsOn(":dist", ":ideaPlugin", ":ultimate:ideaUltimatePlugin") dependsOn(":dist", ":ideaPlugin", ":ultimate:ideaUltimatePlugin")
} }
} }