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 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
dependsOn(":dist", ":ideaPlugin", ":kotlinx-serialization-compiler-plugin:dist")
}
@@ -19,7 +19,7 @@
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-maven-serialization-plugin</artifactId>
<packaging>jar</packaging>
<version>0.3</version>
<version>0.5.0</version>
<description>Serialization plugin for Maven</description>
<repositories>
@@ -8,7 +8,7 @@ configureJvmProject(project)
configurePublishing(project)
group = 'org.jetbrains.kotlinx'
version = '0.3'
version = '0.5.0'
if (!project.hasProperty("deploy")) {
version = "$version-SNAPSHOT"
}
@@ -1,11 +1,16 @@
description = "Kotlin Serialization Compiler Plugin"
apply { plugin("kotlin") }
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(ideaSdkCoreDeps("intellij-core"))
compileOnly(ideaPluginDeps("maven", plugin = "maven"))
// val compileOnly by configurations
// val runtime by configurations
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep())
compileOnly(intellijPluginDep("maven"))
compileOnly(project(":jps-plugin"))
compileOnly(project(":compiler:plugin-api"))
compileOnly(project(":compiler:frontend"))
@@ -19,8 +24,6 @@ dependencies {
runtime(projectRuntimeJar(":kotlin-compiler"))
runtime(projectDist(":kotlin-stdlib"))
// val compileOnly by configurations
// val runtime by configurations
}
sourceSets {
@@ -1,7 +1,7 @@
<idea-plugin url="https://github.com/Kotlin/kotlinx.serialization" >
<name>Kotlin-serialization</name>
<id>org.jetbrains.kotlinx.serialization</id>
<version>0.3</version>
<version>0.5.0</version>
<depends>org.jetbrains.kotlin</depends>
<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.lazy.descriptors.LazyAnnotationDescriptor
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.enumSerializerId
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.*
open class SerialTypeInfo(
val property: SerializableProperty,
val elementMethodPrefix: String,
val serializer: ClassDescriptor? = null,
val unit: Boolean = false
val property: SerializableProperty,
val elementMethodPrefix: String,
val serializer: ClassDescriptor? = null,
val unit: Boolean = false
)
fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
val T = property.type
return when {
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(property,
T.nameIfStandardType.toString().capitalize())
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
property,
T.nameIfStandardType.toString().capitalize()
)
KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String")
KotlinBuiltIns.isUnit(T) -> SerialTypeInfo(property, "Unit", unit = true)
KotlinBuiltIns.isPrimitiveArray(T) -> TODO("primitive arrays are not supported yet")
KotlinBuiltIns.isNonPrimitiveArray(T.toClassDescriptor!!) -> {
val serializer = property.serializableWith?.toClassDescriptor ?:
property.module.findClassAcrossModuleDependencies(referenceArraySerializerId)
val serializer = property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(
referenceArraySerializerId
)
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
}
T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> {
val serializer = property.serializableWith?.toClassDescriptor ?:
property.module.findClassAcrossModuleDependencies(enumSerializerId)
val serializer =
property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(enumSerializerId)
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
}
else -> {
@@ -72,9 +78,9 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescri
return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module)
else if (kType.isTypeParameter()) return null
else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type
?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer
?: findEnumTypeSerializer(module, kType)
?: module.findClassAcrossModuleDependencies(contextSerializerId)
?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer
?: findEnumTypeSerializer(module, kType)
?: module.findClassAcrossModuleDependencies(contextSerializerId)
}
fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
@@ -110,8 +116,8 @@ fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDe
fun KotlinType.requiresPolymorphism(): Boolean {
return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true
|| (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class
|| this.containsTypeProjectionsInTopLevelArguments() // List<*>
|| (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class
|| this.containsTypeProjectionsInTopLevelArguments() // List<*>
}
fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor {
@@ -119,20 +125,23 @@ fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor {
}
fun KtPureClassOrObject.bodyPropertiesDescriptorsMap(bindingContext: BindingContext): Map<PropertyDescriptor, KtProperty> = declarations
.asSequence()
.filterIsInstance<KtProperty>()
.associateBy { (bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? PropertyDescriptor)!! }
.asSequence()
.filterIsInstance<KtProperty>()
// 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()
.filter { it.hasValOrVar() }
.associateBy { bindingContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!! }
fun KtPureClassOrObject.anonymousInitializers() = declarations
.asSequence()
.filterIsInstance<KtAnonymousInitializer>()
.mapNotNull { it.body }
.toList()
.asSequence()
.filterIsInstance<KtAnonymousInitializer>()
.mapNotNull { it.body }
.toList()
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()
@@ -16,10 +16,12 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.js
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
internal class JsBlockBuilder {
@@ -91,4 +93,12 @@ internal fun propNotSeenTest(seenVar: JsNameRef, index: Int): JsBinaryOperation
JsIntLiteral(1 shl (index % 32))
),
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
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
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.JsNameRef
import org.jetbrains.kotlin.js.backend.ast.JsReturn
@@ -33,8 +35,8 @@ class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
val f = context.buildFunction(methodDescriptor) {jsFun, context ->
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
val stmt = if (serializableDescriptor.declaredTypeParameters.isEmpty()) {
context.getQualifiedReference(serializer)
val stmt: JsExpression = if (serializer.kind == ClassKind.OBJECT) {
context.serializerObjectGetter(serializer)
} else {
val args = jsFun.parameters.map { JsNameRef(it.name) }
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.isInternalSerializable
class SerializableJsTranslator(val declaration: KtPureClassOrObject,
val translator: DeclarationBodyVisitor,
val context: TranslationContext) : SerializableCodegen(declaration, context.bindingContext()) {
class SerializableJsTranslator(
val declaration: KtPureClassOrObject,
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 } +
primaryPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.defaultValue })
primaryPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.defaultValue })
}
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) {
val missingExceptionClassRef = serializableDescriptor.getClassFromSerializationPackage("MissingFieldException")
.let { context.getQualifiedReference(it) }
.let { context.translateQualifiedReference(it) }
val f = context.buildFunction(constructorDescriptor) { jsFun, context ->
val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef()
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()
for ((index, prop) in properties.serializableProperties.withIndex()) {
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 initExpr = Translation.translateAsExpression(initializer, context)
TranslationUtils.assignmentToBackingField(context, prop.descriptor, initExpr).makeStmt()
}
else {
} else {
JsThrow(JsNew(missingExceptionClassRef, listOf(JsStringLiteral(prop.name))))
}
// (seen & 1 << i == 0) -- not seen
@@ -75,14 +81,14 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject,
//transient initializers and init blocks
val serialDescs = properties.serializableProperties.map { it.descriptor }
(initMap - serialDescs).forEach { (desc, expr) ->
val e = requireNotNull(expr) {"transient without an initializer"}
(initMap - serialDescs).forEach { (desc, expr) ->
val e = requireNotNull(expr) { "transient without an initializer" }
val initExpr = Translation.translateAsExpression(e, context)
+TranslationUtils.assignmentToBackingField(context, desc, initExpr).makeStmt()
}
declaration.anonymousInitializers()
.forEach { Translation.translateAsExpression(it, context, this.block) }
.forEach { Translation.translateAsExpression(it, context, this.block) }
+JsReturn(thiz)
}
@@ -96,7 +102,12 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject,
}
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)
SerializableJsTranslator(declaration, translator, context).generate()
}
@@ -80,7 +80,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
val argExprs = args.map { arg ->
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))
translator.addInitializerStatement(invok.makeStmt())
}
@@ -101,7 +101,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
val f = context.buildFunction(typedConstructorDescriptor) { jsFun, context ->
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 ->
val thisFRef = JsNameRef(context.scope().declareName("$typeArgPrefix$i"), thiz)
+JsAstUtils.assignment(thisFRef, JsNameRef(parameter.name)).makeStmt()
@@ -170,19 +170,15 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
+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? {
val nullableSerClass = getQualifiedClassReferenceName(requireNotNull(
val nullableSerClass = context.translateQualifiedReference(requireNotNull(
module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier("NullableSerializer")))))
if (serializerClass == null) {
if (genericIndex == null) return null
return JsNameRef(context.scope().declareName("$typeArgPrefix$genericIndex"), JsThisRef())
}
if (serializerClass.kind == ClassKind.OBJECT) {
return getQualifiedClassReferenceName(serializerClass)
return context.serializerObjectGetter(serializerClass)
}
else {
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
@@ -197,9 +193,9 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
JsInvocation(context.getInnerNameForDescriptor(desc).makeRef(), args)
JsInvocation(context.getInnerReference(desc), args)
} else {
JsNew(getQualifiedClassReferenceName(serializerClass), args)
JsNew(context.translateQualifiedReference(serializerClass), args)
}
return ref
}
@@ -207,7 +203,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
private fun createGetKClassExpression(classDescriptor: ClassDescriptor): JsExpression =
JsInvocation(context.namer().kotlin("getKClass"),
getQualifiedClassReferenceName(classDescriptor))
context.translateQualifiedReference(classDescriptor))
override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context ->
@@ -312,9 +308,15 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
}
// char unboxing crutch
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(
localProps[i],
TranslationUtils.coerce(context, localProps[i], context.currentModule.builtIns.charType)
TranslationUtils.coerce(context, localProps[i], coerceTo)
).makeStmt()
}
@@ -335,7 +337,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
// default: throw
default {
val excClassRef = serializableDescriptor.getClassFromSerializationPackage("UnknownFieldException")
.let { context.getQualifiedReference(it) }
.let { context.translateQualifiedReference(it) }
+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.psi.KtParameter
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.module
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" })
// 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
}
else {
@@ -30,4 +30,7 @@ class SerializationCodegenExtension : ExpressionCodegenExtension {
SerializerCodegenImpl.generateSerializerExtensions(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.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
@@ -42,30 +43,49 @@ class SerializationResolveExtension : SyntheticResolveExtension {
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)
result.add(KSerializerDescriptorResolver.addSerialInfoImplClass(thisDescriptor, declarationProvider, ctx))
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))
return
}
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? =
if (thisDescriptor.isInternalSerializable) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
else null
if (thisDescriptor.isInternalSerializable) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
else null
override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
KSerializerDescriptorResolver.addSerialInfoSuperType(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.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.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.declarations.ClassMemberDeclarationProvider
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.makeNullable
import java.util.*
@@ -74,7 +77,7 @@ object KSerializerDescriptorResolver {
val interfaceDecl = declarationProvider.correspondingClassOrObject!!
val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor)
return SyntheticClassOrObjectDescriptor(ctx,
val descriptor = SyntheticClassOrObjectDescriptor(ctx,
interfaceDecl,
interfaceDesc,
IMPL_NAME,
@@ -85,18 +88,35 @@ object KSerializerDescriptorResolver {
Visibilities.PRIVATE,
ClassKind.CLASS,
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 scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor)
val serializerKind = if (thisDescriptor.declaredTypeParameters.isNotEmpty()) ClassKind.CLASS else ClassKind.OBJECT
return SyntheticClassOrObjectDescriptor(ctx,
thisDeclaration,
thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source,
scope,
Modality.FINAL, Visibilities.PUBLIC, Visibilities.PRIVATE,
serializerKind, false)
val serializerDescriptor = SyntheticClassOrObjectDescriptor(
ctx,
thisDeclaration,
thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source,
scope,
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,
@@ -110,10 +130,12 @@ object KSerializerDescriptorResolver {
}
fun generateCompanionObjectMethods(thisDescriptor: ClassDescriptor,
fromSupertypes: List<SimpleFunctionDescriptor>,
name: Name,
result: MutableCollection<SimpleFunctionDescriptor>) {
fun generateCompanionObjectMethods(
thisDescriptor: ClassDescriptor,
fromSupertypes: List<SimpleFunctionDescriptor>,
name: Name,
result: MutableCollection<SimpleFunctionDescriptor>
) {
val classDescriptor = getSerializableClassDescriptorByCompanion(thisDescriptor) ?: return
if (name == SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == classDescriptor.declaredTypeParameters.size }) {
@@ -248,24 +270,32 @@ object KSerializerDescriptorResolver {
return functionDescriptor
}
fun createTypedSerializerConstructorDescriptor(classDescriptor: ClassDescriptor, serializableDescriptor: ClassDescriptor): ConstructorDescriptor {
fun createTypedSerializerConstructorDescriptor(
classDescriptor: ClassDescriptor,
serializableDescriptor: ClassDescriptor
): ConstructorDescriptor {
val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor,
Annotations.EMPTY,
false,
classDescriptor.source
classDescriptor,
Annotations.EMPTY,
false,
classDescriptor.source
)
val serializerClass = classDescriptor.getClassFromSerializationPackage("KSerializer")
val targs = mutableListOf<TypeParameterDescriptor>()
val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, _ ->
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(constrDesc, Annotations.EMPTY, false, Variance.INVARIANT,
Name.identifier("T$index"), index)
val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, param ->
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(
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)
ValueParameterDescriptorImpl(constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType,
false, false, false, null, constrDesc.source)
ValueParameterDescriptorImpl(
constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType,
false, false, false, null, constrDesc.source
)
}
constrDesc.initialize(args, Visibilities.PUBLIC, targs)
@@ -274,7 +304,13 @@ object KSerializerDescriptorResolver {
}
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 args = mutableListOf<ValueParameterDescriptor>()
@@ -282,31 +318,38 @@ object KSerializerDescriptorResolver {
var i = 0
serializableClass.declaredTypeParameters.forEach { it ->
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(f, Annotations.EMPTY, false, Variance.INVARIANT,
Name.identifier("T$i"), i)
val targ = TypeParameterDescriptorImpl.createWithDefaultBound(
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,
null,
i,
Annotations.EMPTY,
Name.identifier("$typeArgPrefix${i}"),
Name.identifier("$typeArgPrefix$i"),
pType,
false,
false,
false,
null,
f.source
))
)
)
typeArgs.add(targ)
i++
}
val newSerializableType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializableClass, typeArgs.map { TypeProjectionImpl(it.defaultType) })
val serialReturnType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(newSerializableType)))
val 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)
return f
@@ -19,51 +19,52 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.BindingContext
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.scopes.DescriptorKindFilter
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
private val primaryConstructorParameters: List<ValueParameterDescriptor> =
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean> =
primaryConstructorParameters.asSequence()
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.hasDefaultValue() }
.mapNotNull { (a, b) -> if (a == null) null else a to b }
.toMap()
primaryConstructorParameters.asSequence()
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() }
.mapNotNull { (a, b) -> if (a == null) null else a to b }
.toMap()
val isExternallySerializable: Boolean =
primaryConstructorParameters.size == primaryConstructorProperties.size
primaryConstructorParameters.size == primaryConstructorProperties.size
val serializableProperties: List<SerializableProperty> =
serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.asSequence()
.filterIsInstance<PropertyDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
.filter(this::isPropSerializable)
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) }
.partition { primaryConstructorProperties.contains(it.descriptor) }
.run {
val supers = serializableClass.getSuperClassNotAny()
if (supers == null || !supers.isInternalSerializable)
first + second
else
SerializableProperties(supers, bindingContext).serializableProperties + first + second
}
serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.asSequence()
.filterIsInstance<PropertyDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
.filter(this::isPropSerializable)
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) }
.partition { primaryConstructorProperties.contains(it.descriptor) }
.run {
val supers = serializableClass.getSuperClassNotAny()
if (supers == null || !supers.isInternalSerializable)
first + second
else
SerializableProperties(supers, bindingContext).serializableProperties + first + second
}
private fun isPropSerializable(it: PropertyDescriptor) =
if (serializableClass.isInternalSerializable) !it.annotations.serialTransient
else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(it))
if (serializableClass.isInternalSerializable) !it.annotations.serialTransient
else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(
it
))
val serializableConstructorProperties: List<SerializableProperty> =
serializableProperties.asSequence()
.filter { primaryConstructorProperties.contains(it.descriptor) }
.toList()
serializableProperties.asSequence()
.filter { primaryConstructorProperties.contains(it.descriptor) }
.toList()
val serializableStandaloneProperties: List<SerializableProperty> =
serializableProperties.minus(serializableConstructorProperties)
serializableProperties.minus(serializableConstructorProperties)
val size = serializableProperties.size
val indices = serializableProperties.indices
@@ -34,12 +34,13 @@ class KotlinSerializationJpsPlugin : KotlinJpsCompilerArgumentsProvider {
override fun getClasspath(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List<String> {
val inJar = File(PathUtil.getJarPathForClass(this::class.java)).isFile
return listOf(
if (inJar) {
File(PathUtil.getJarPathForClass(this::class.java)).absolutePath
} else {
// We're in tests now
val kotlinProjectDirectory = File(PathUtil.getJarPathForClass(javaClass)).parentFile.parentFile.parentFile
File(kotlinProjectDirectory, "dist/artifacts/Serialization/lib/$JAR_FILE_NAME").absolutePath
})
if (inJar) {
File(PathUtil.getJarPathForClass(this::class.java)).absolutePath
} else {
// We're in tests now
val kotlinProjectDirectory = File(PathUtil.getJarPathForClass(javaClass)).parentFile.parentFile.parentFile
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 ideaUltimateSandboxDir: File by rootProject.extra
val serialPluginDir: File by rootProject.extra
if (intellijUltimateEnabled) {
runIdeTask("runUltimate", ideaUltimatePluginDir, ideaUltimateSandboxDir) {
runIdeTask("runUltimate", ideaUltimatePluginDir, ideaUltimateSandboxDir, serialPluginDir) {
dependsOn(":dist", ":ideaPlugin", ":ultimate:ideaUltimatePlugin")
}
}