JPS plugin
Breaking changes in compiler plugin: * Remove java.Serializable supertype * Move serializer impl from companion to special inner class * Add generic serializer fields in $serializer and serializer getter in companion kotlin.Pair serializer Generating getter also for non-generic serializers Generic serializers in JS
This commit is contained in:
@@ -5,6 +5,7 @@ apply { plugin("kotlin") }
|
||||
|
||||
dependencies {
|
||||
compileOnly(ideaSdkCoreDeps("intellij-core"))
|
||||
compileOnly(project(":jps-plugin"))
|
||||
compileOnly(project(":compiler:plugin-api"))
|
||||
compileOnly(project(":compiler:frontend"))
|
||||
compileOnly(project(":compiler:backend"))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<idea-plugin>
|
||||
<name>Kotlin-serialization</name>
|
||||
<id>org.jetbrains.kotlinx.serialization</id>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<version>0.2</version>
|
||||
|
||||
<depends>org.jetbrains.kotlin</depends>
|
||||
<idea-version since-build="172"/>
|
||||
@@ -11,4 +11,9 @@
|
||||
<syntheticResolveExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationResolveExtension"/>
|
||||
<jsSyntheticTranslateExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationJsExtension"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<compileServer.plugin classpath="kotlinx-serialization-compiler-plugin.jar"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright 2010-2017 JetBrains s.r.o.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
org.jetbrains.kotlinx.serialization.jps.KotlinSerializationJpsPlugin
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
|
||||
abstract class SerializableCompanionCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
|
||||
protected val companionDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
||||
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
|
||||
|
||||
fun generate() {
|
||||
val fser = KSerializerDescriptorResolver.createSerializerGetterDescriptor(companionDescriptor, serializableDescriptor)
|
||||
generateSerializerGetter(fser)
|
||||
}
|
||||
|
||||
protected abstract fun generateSerializerGetter(methodDescriptor: FunctionDescriptor)
|
||||
}
|
||||
+6
-1
@@ -25,8 +25,8 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
|
||||
|
||||
abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
|
||||
@@ -43,12 +43,17 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
|
||||
val load = generateLoadIfNeeded()
|
||||
if (save || load || prop)
|
||||
generateSerialDesc()
|
||||
if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) {
|
||||
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
|
||||
}
|
||||
}
|
||||
|
||||
protected val serialDescPropertyDescriptor = getPropertyToGenerate(serializerDescriptor, KSerializerDescriptorResolver.SERIAL_DESC_FIELD,
|
||||
serializerDescriptor::checkSerializableClassPropertyResult)
|
||||
protected abstract fun generateSerialDesc()
|
||||
|
||||
protected abstract fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor)
|
||||
|
||||
protected abstract fun generateSerializableClassProperty(property: PropertyDescriptor)
|
||||
|
||||
protected abstract fun generateSave(function: FunctionDescriptor)
|
||||
|
||||
+4
-3
@@ -28,9 +28,7 @@ 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.containsTypeProjectionsInTopLevelArguments
|
||||
import org.jetbrains.kotlin.types.typeUtil.isBoolean
|
||||
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
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
|
||||
@@ -47,6 +45,7 @@ open class SerialTypeInfo(
|
||||
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())
|
||||
KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String")
|
||||
@@ -71,6 +70,7 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
||||
|
||||
fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
|
||||
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)
|
||||
@@ -89,6 +89,7 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
|
||||
"D", "kotlin.Double" -> "DoubleSerializer"
|
||||
"C", "kotlin.Char" -> "CharSerializer"
|
||||
"kotlin.String" -> "StringSerializer"
|
||||
"kotlin.Pair" -> "PairSerializer"
|
||||
"kotlin.collections.Collection", "kotlin.collections.List", "kotlin.collections.ArrayList" -> "ArrayListSerializer"
|
||||
"kotlin.collections.Set", "kotlin.collections.LinkedHashSet" -> "LinkedHashSetSerializer"
|
||||
"kotlin.collections.HashSet" -> "HashSetSerializer"
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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.JsInvocation
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsReturn
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
|
||||
val translator: DeclarationBodyVisitor,
|
||||
val context: TranslationContext): SerializableCompanionCodegen(declaration, context.bindingContext()) {
|
||||
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)
|
||||
} else {
|
||||
val args = jsFun.parameters.map { JsNameRef(it.name) }
|
||||
val ref = context.getInnerNameForDescriptor(
|
||||
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializer, serializableDescriptor))
|
||||
JsInvocation(ref.makeRef(), args)
|
||||
}
|
||||
+JsReturn(stmt)
|
||||
}
|
||||
translator.addFunction(methodDescriptor, f, null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun translate(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
|
||||
val serializableClass = getSerializableClassDescriptorByCompanion(descriptor) ?: return
|
||||
if (serializableClass.isInternalSerializable)
|
||||
SerializableCompanionJsTranslator(declaration, translator, context).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
-8
@@ -19,12 +19,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.js
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||
import org.jetbrains.kotlin.js.translate.declaration.DefaultPropertyTranslator
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
@@ -39,6 +41,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerialize
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix
|
||||
|
||||
class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
||||
val translator: DeclarationBodyVisitor,
|
||||
@@ -94,6 +97,22 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
||||
translator.addProperty(propDesc, getterExpr, null)
|
||||
}
|
||||
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
|
||||
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))))
|
||||
jsFun.parameters.forEachIndexed { i, parameter ->
|
||||
val thisFRef = JsNameRef(context.scope().declareName("$typeArgPrefix$i"), thiz)
|
||||
+JsAstUtils.assignment(thisFRef, JsNameRef(parameter.name)).makeStmt()
|
||||
}
|
||||
+JsReturn(thiz)
|
||||
}
|
||||
|
||||
f.name = context.getInnerNameForDescriptor(typedConstructorDescriptor);
|
||||
context.addDeclarationStatement(f.makeStmt())
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.getFuncDesc(funcName: String) =
|
||||
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }
|
||||
|
||||
@@ -120,7 +139,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
||||
if (property.transient) continue
|
||||
// output.writeXxxElementValue(classDesc, index, value)
|
||||
val sti = getSerialTypeInfo(property)
|
||||
val innerSerial = if (sti.serializer == null) null else serializerInstance(sti.serializer, property.module, property.type)
|
||||
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
|
||||
if (innerSerial == null) {
|
||||
val writeFunc =
|
||||
kOutputClass.getFuncDesc("write${sti.elementMethodPrefix}ElementValue").single()
|
||||
@@ -152,9 +171,13 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
||||
return context.getQualifiedReference(classDescriptor)
|
||||
}
|
||||
|
||||
private fun serializerInstance(serializerClass: ClassDescriptor, module: ModuleDescriptor, kType: KotlinType): JsExpression? {
|
||||
val nullableSerClass = getQualifiedClassReferenceName(
|
||||
serializerClass.getClassFromInternalSerializationPackage("NullableSerializer"))
|
||||
private fun serializerInstance(serializerClass: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, genericIndex: Int? = null): JsExpression? {
|
||||
val nullableSerClass = getQualifiedClassReferenceName(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)
|
||||
}
|
||||
@@ -162,13 +185,20 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
||||
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
|
||||
listOf(createGetKClassExpression(kType.toClassDescriptor!!))
|
||||
else kType.arguments.map {
|
||||
val argSer = findTypeSerializer(module, it.type) ?: return null
|
||||
val expr = serializerInstance(argSer, module, it.type) ?: return null
|
||||
val argSer = findTypeSerializer(module, it.type)
|
||||
val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null
|
||||
if (it.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
|
||||
}
|
||||
if (serializerClass.classId == referenceArraySerializerId)
|
||||
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
|
||||
return JsNew(getQualifiedClassReferenceName(serializerClass), args)
|
||||
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
|
||||
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
|
||||
val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
|
||||
JsInvocation(context.getInnerNameForDescriptor(desc).makeRef(), args)
|
||||
} else {
|
||||
JsNew(getQualifiedClassReferenceName(serializerClass), args)
|
||||
}
|
||||
return ref
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +259,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
||||
case(JsIntLiteral(i)) {
|
||||
// input.readXxxElementValue
|
||||
val sti = getSerialTypeInfo(property)
|
||||
val innerSerial = if (sti.serializer == null) null else serializerInstance(sti.serializer, property.module, property.type)
|
||||
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
|
||||
val call = if (innerSerial == null) {
|
||||
val unknownSer = (sti.elementMethodPrefix.isEmpty())
|
||||
val readFunc =
|
||||
|
||||
+32
-11
@@ -32,6 +32,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.findEnumTypeS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findPolymorphicSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.requiresPolymorphism
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
@@ -71,10 +72,12 @@ internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, messag
|
||||
athrow()
|
||||
}
|
||||
|
||||
fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen, propertyOwnerType: Type, ownerVar: Int) {
|
||||
fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen,
|
||||
propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null) {
|
||||
val propertyType = classCodegen.typeMapper.mapType(property.type)
|
||||
val sti = getSerialTypeInfo(property, propertyType)
|
||||
val useSerializer = stackValueSerializerInstance(classCodegen, sti)
|
||||
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti)
|
||||
else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar)
|
||||
if (!sti.unit) classCodegen.genPropertyOnStack(this, expressionCodegen.context, property.descriptor, propertyOwnerType, ownerVar)
|
||||
invokevirtual(kOutputType.internalName,
|
||||
"write" + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + "ElementValue",
|
||||
@@ -114,16 +117,32 @@ internal val polymorphicSerializerId = ClassId(packageFqName, Name.identifier("P
|
||||
internal val referenceArraySerializerId = ClassId(internalPackageFqName, Name.identifier("ReferenceArraySerializer"))
|
||||
internal val contextSerializerId = ClassId(packageFqName, Name.identifier("ContextSerializer"))
|
||||
|
||||
// returns false is property should not use serializer
|
||||
internal fun InstructionAdapter.stackValueSerializerInstance(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean {
|
||||
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, varIndexStart: Int): Boolean {
|
||||
val serializer = sti.serializer ?: return false
|
||||
return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this)
|
||||
return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this, sti.property.genericIndex) { idx ->
|
||||
load(varIndexStart + idx, kSerializerType)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean {
|
||||
val serializer = sti.serializer ?: return false
|
||||
return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this, sti.property.genericIndex) { idx ->
|
||||
load(0, kSerializerType)
|
||||
getfield(codegen.typeMapper.mapClass(codegen.descriptor).internalName, "$typeArgPrefix$idx", kSerializerType.descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
// returns false is cannot not use serializer
|
||||
// use iv == null to check only (do not emit serializer onto stack)
|
||||
internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, serializer: ClassDescriptor,
|
||||
iv: InstructionAdapter?): Boolean {
|
||||
internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
|
||||
iv: InstructionAdapter?, genericIndex: Int? = null, genericSerializerFieldGetter: (InstructionAdapter.(Int) -> Unit)? = null): Boolean {
|
||||
if (genericIndex != null) {
|
||||
// get field from serializer object
|
||||
iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex) }
|
||||
return true
|
||||
}
|
||||
val serializer = requireNotNull(maybeSerializer)
|
||||
if (serializer.kind == ClassKind.OBJECT) {
|
||||
// singleton serializer -- just get it
|
||||
if (iv != null)
|
||||
@@ -133,11 +152,12 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
|
||||
// serializer is not singleton object and shall be instantiated
|
||||
val argSerializers = kType.arguments.map { projection ->
|
||||
// bail out from stackValueSerializerInstance if any type argument is not serializable
|
||||
val argSerializer = findTypeSerializer(module, projection.type, codegen.typeMapper.mapType(projection.type)) ?: return false
|
||||
val argType = projection.type
|
||||
val argSerializer = findTypeSerializer(module, argType, codegen.typeMapper.mapType(argType)) ?: return false
|
||||
// check if it can be properly serialized with its args recursively
|
||||
if (!stackValueSerializerInstance(codegen, module, projection.type, argSerializer, null))
|
||||
if (!stackValueSerializerInstance(codegen, module, argType, argSerializer, null, argType.genericIndex, genericSerializerFieldGetter))
|
||||
return false
|
||||
Pair(projection.type, argSerializer)
|
||||
Pair(argType, argSerializer)
|
||||
}
|
||||
// new serializer if needed
|
||||
iv?.apply {
|
||||
@@ -163,7 +183,7 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
|
||||
}
|
||||
// all serializers get arguments with serializers of their generic types
|
||||
argSerializers.forEach { (argType, argSerializer) ->
|
||||
assert(stackValueSerializerInstance(codegen, module, argType, argSerializer, this))
|
||||
assert(stackValueSerializerInstance(codegen, module, argType, argSerializer, this, argType.genericIndex, genericSerializerFieldGetter))
|
||||
// wrap into nullable serializer if argType is nullable
|
||||
if (argType.isMarkedNullable) {
|
||||
invokestatic("kotlinx/serialization/internal/BuiltinSerializersKt", "makeNullable",
|
||||
@@ -261,5 +281,6 @@ internal val org.jetbrains.org.objectweb.asm.Type.standardSerializer: String? ge
|
||||
"Ljava/util/Map;", "Ljava/util/LinkedHashMap;" -> "LinkedHashMapSerializer"
|
||||
"Ljava/util/HashMap;" -> "HashMapSerializer"
|
||||
"Ljava/util/Map\$Entry;" -> "MapEntrySerializer"
|
||||
"Lkotlin/Pair;" -> "PairSerializer"
|
||||
else -> null
|
||||
}
|
||||
|
||||
+14
-8
@@ -26,14 +26,13 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.anonymousInitializers
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryPropertiesDescriptorsMap
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
@@ -73,22 +72,29 @@ class SerializableCodegenImpl(
|
||||
val thisI = 0
|
||||
val outputI = 1
|
||||
val serialDescI = 2
|
||||
// val offsetI = 3
|
||||
val offsetI = 3
|
||||
|
||||
val superClass = serializableDescriptor.getSuperClassOrAny()
|
||||
val myPropsStart: Int
|
||||
if (superClass.isInternalSerializable) {
|
||||
myPropsStart = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties.size
|
||||
val superTypeArguments = serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
|
||||
//super.writeSelf(output, serialDesc)
|
||||
load(thisI, thisAsmType)
|
||||
load(outputI, kOutputType)
|
||||
load(serialDescI, descType)
|
||||
invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, signature.asmMethod.name, signature.asmMethod.descriptor, false)
|
||||
superTypeArguments.forEach {
|
||||
val genericIdx = serializableDescriptor.defaultType.arguments.indexOf(it).let { if (it == -1) null else it }
|
||||
val serial = findTypeSerializer(serializableDescriptor.module, it.type, classCodegen.typeMapper.mapType(it.type))
|
||||
stackValueSerializerInstance(classCodegen, serializableDescriptor.module, it.type, serial, this, genericIdx) {
|
||||
load(offsetI + it, kSerializerType)
|
||||
}
|
||||
}
|
||||
val superSignature = classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass))
|
||||
invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, superSignature.asmMethod.name, superSignature.asmMethod.descriptor, false)
|
||||
}
|
||||
else {
|
||||
myPropsStart = 0
|
||||
// offset = 0
|
||||
// iconst(0)
|
||||
}
|
||||
|
||||
for (i in myPropsStart until properties.serializableProperties.size) {
|
||||
@@ -97,7 +103,7 @@ class SerializableCodegenImpl(
|
||||
load(outputI, kOutputType)
|
||||
load(serialDescI, descType)
|
||||
iconst(i)
|
||||
genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI)
|
||||
genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI)
|
||||
}
|
||||
|
||||
areturn(Type.VOID_TYPE)
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) :
|
||||
SerializableCompanionCodegen(codegen.myClass, codegen.bindingContext) {
|
||||
|
||||
companion object {
|
||||
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
|
||||
val serializableClass = getSerializableClassDescriptorByCompanion(codegen.descriptor) ?: return
|
||||
if (serializableClass.isInternalSerializable)
|
||||
SerializableCompanionCodegenImpl(codegen).generate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
val serial = serializableDescriptor.classSerializer?.toClassDescriptor ?: return
|
||||
codegen.generateMethod(methodDescriptor) {sig, expr ->
|
||||
stackValueSerializerInstance(codegen, serializableDescriptor.module, serializableDescriptor.defaultType, serial, this, null) {
|
||||
load(it+1, kSerializerType)
|
||||
}
|
||||
areturn(kSerializerType)
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-2
@@ -18,6 +18,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.annotationVarsAndDesc
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorBySerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
@@ -50,6 +52,25 @@ class SerializerCodegenImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
|
||||
serializableDescriptor.declaredTypeParameters.forEachIndexed { i, _ ->
|
||||
codegen.v.newField(OtherOrigin(codegen.myClass.psiOrParent), ACC_PRIVATE or ACC_SYNTHETIC,
|
||||
"$typeArgPrefix$i", kSerializerType.descriptor, null, null )
|
||||
}
|
||||
|
||||
codegen.generateMethod(typedConstructorDescriptor) { sig, exprCodegen ->
|
||||
load(0, serializerAsmType)
|
||||
invokespecial("java/lang/Object", "<init>", "()V", false)
|
||||
serializableDescriptor.declaredTypeParameters.forEachIndexed { i, _ ->
|
||||
load(0, serializerAsmType)
|
||||
load(i+1, kSerializerType)
|
||||
putfield(serializerAsmType.internalName, "$typeArgPrefix$i", kSerializerType.descriptor)
|
||||
}
|
||||
areturn(Type.VOID_TYPE)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun generateSerialDesc() {
|
||||
codegen.v.newField(OtherOrigin(codegen.myClass.psiOrParent), ACC_PRIVATE or ACC_STATIC or ACC_FINAL or ACC_SYNTHETIC,
|
||||
serialDescField, descType.descriptor, null, null)
|
||||
@@ -126,12 +147,19 @@ class SerializerCodegenImpl(
|
||||
")" + kOutputType.descriptor, false)
|
||||
store(outputVar, kOutputType)
|
||||
if (serializableDescriptor.isInternalSerializable) {
|
||||
val sig = StringBuilder("(${kOutputType.descriptor}${descType.descriptor}")
|
||||
// call obj.write$Self(output, classDesc)
|
||||
load(objVar, objType)
|
||||
load(outputVar, kOutputType)
|
||||
load(descVar, descType)
|
||||
serializableDescriptor.declaredTypeParameters.forEachIndexed {i, _ ->
|
||||
load(0, kSerializerType)
|
||||
getfield(codegen.typeMapper.mapClass(codegen.descriptor).internalName, "$typeArgPrefix$i", kSerializerType.descriptor)
|
||||
sig.append(kSerializerType.descriptor)
|
||||
}
|
||||
sig.append(")V")
|
||||
invokevirtual(objType.internalName, KSerializerDescriptorResolver.WRITE_SELF_NAME.asString(),
|
||||
"(${kOutputType.descriptor}${descType.descriptor})V", false)
|
||||
sig.toString(), false)
|
||||
}
|
||||
else {
|
||||
// loop for all properties
|
||||
@@ -235,7 +263,7 @@ class SerializerCodegenImpl(
|
||||
iconst(labelNum)
|
||||
|
||||
val sti = getSerialTypeInfo(property, propertyType)
|
||||
val useSerializer = stackValueSerializerInstance(codegen, sti)
|
||||
val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti)
|
||||
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
|
||||
if (unknownSer) {
|
||||
aconst(codegen.typeMapper.mapType(property.type))
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerialInfoCodegenImpl
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCompanionCodegenImpl
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl
|
||||
|
||||
class SerializationCodegenExtension : ExpressionCodegenExtension {
|
||||
@@ -27,5 +28,6 @@ class SerializationCodegenExtension : ExpressionCodegenExtension {
|
||||
SerialInfoCodegenImpl.generateSerialInfoImplBody(codegen)
|
||||
SerializableCodegenImpl.generateSerializableExtensions(codegen)
|
||||
SerializerCodegenImpl.generateSerializerExtensions(codegen)
|
||||
SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen)
|
||||
}
|
||||
}
|
||||
+2
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||
import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableCompanionJsTranslator
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableJsTranslator
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializerJsTranslator
|
||||
|
||||
@@ -28,5 +29,6 @@ class SerializationJsExtension: JsSyntheticTranslateExtension {
|
||||
override fun generateClassSyntheticParts(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
|
||||
SerializerJsTranslator.translate(declaration, descriptor, translator, context)
|
||||
SerializableJsTranslator.translate(declaration, descriptor, translator, context)
|
||||
SerializableCompanionJsTranslator.translate(declaration, descriptor, translator, context)
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -31,16 +31,17 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.serialInfoFqName
|
||||
import java.util.*
|
||||
|
||||
class SerializationResolveExtension : SyntheticResolveExtension {
|
||||
override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> {
|
||||
if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName))
|
||||
return listOf(KSerializerDescriptorResolver.IMPL_NAME)
|
||||
else
|
||||
return listOf()
|
||||
override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> = when {
|
||||
thisDescriptor.annotations.hasAnnotation(serialInfoFqName) -> listOf(KSerializerDescriptorResolver.IMPL_NAME)
|
||||
thisDescriptor.isInternalSerializable -> listOf(KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME)
|
||||
else -> listOf()
|
||||
}
|
||||
|
||||
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.add(KSerializerDescriptorResolver.addSerializerImplClass(thisDescriptor, declarationProvider, ctx))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -50,12 +51,12 @@ class SerializationResolveExtension : SyntheticResolveExtension {
|
||||
|
||||
override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
|
||||
KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes)
|
||||
KSerializerDescriptorResolver.addSerializableSupertypes(thisDescriptor, supertypes)
|
||||
KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes)
|
||||
}
|
||||
|
||||
override fun generateSyntheticMethods(thisDescriptor: ClassDescriptor, name: Name, 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>) {
|
||||
|
||||
+16
-6
@@ -17,17 +17,16 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME
|
||||
|
||||
internal val packageFqName = FqName("kotlinx.serialization")
|
||||
internal val internalPackageFqName = FqName("kotlinx.serialization.internal")
|
||||
@@ -123,7 +122,9 @@ internal val ClassDescriptor?.classSerializer: KotlinType?
|
||||
// serializer annotation on class?
|
||||
annotations.serializableWith?.let { return it }
|
||||
// default serializable?
|
||||
if (isInternalSerializable) return companionObjectDescriptor?.defaultType
|
||||
if (isInternalSerializable) return this.unsubstitutedMemberScope
|
||||
.getDescriptorsFiltered(nameFilter = {it == SERIALIZER_CLASS_NAME})
|
||||
.filterIsInstance<ClassDescriptor>().singleOrNull()?.defaultType
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -131,11 +132,20 @@ internal val ClassDescriptor?.classSerializer: KotlinType?
|
||||
val KotlinType.typeSerializer: KotlinType?
|
||||
get() = this.annotations.serializableWith ?: (this.toClassDescriptor).classSerializer
|
||||
|
||||
val KotlinType.genericIndex: Int?
|
||||
get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index
|
||||
|
||||
fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? {
|
||||
if (!thisDescriptor.isCompanionObject) return null
|
||||
val classDescriptor = (thisDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
|
||||
if (!classDescriptor.isInternalSerializable) return null
|
||||
return classDescriptor
|
||||
}
|
||||
|
||||
fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? {
|
||||
val serializerForClass = serializerDescriptor.annotations.serializerForClass
|
||||
if (serializerForClass != null) return serializerForClass.toClassDescriptor
|
||||
if (!serializerDescriptor.isCompanionObject) return null
|
||||
if (serializerDescriptor.name != SERIALIZER_CLASS_NAME) return null
|
||||
val classDescriptor = (serializerDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
|
||||
if (!classDescriptor.isInternalSerializable) return null
|
||||
return classDescriptor
|
||||
|
||||
+115
-12
@@ -28,8 +28,7 @@ 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.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import java.util.*
|
||||
@@ -39,6 +38,9 @@ object KSerializerDescriptorResolver {
|
||||
val SERIAL_DESC_FIELD = "serialClassDesc"
|
||||
val SAVE = "save"
|
||||
val LOAD = "load"
|
||||
val SERIALIZER_CLASS = "\$serializer"
|
||||
|
||||
internal val typeArgPrefix = "typeSerial"
|
||||
|
||||
val SERIAL_DESC_FIELD_NAME = Name.identifier(SERIAL_DESC_FIELD)
|
||||
val SAVE_NAME = Name.identifier(SAVE)
|
||||
@@ -46,13 +48,8 @@ object KSerializerDescriptorResolver {
|
||||
val DUMMY_PARAM_NAME = Name.identifier("serializationConstructorMarker")
|
||||
val WRITE_SELF_NAME = Name.identifier("write\$Self") //todo: add it as a supertype to synthetic resolving
|
||||
val IMPL_NAME = Name.identifier("Impl")
|
||||
|
||||
|
||||
fun addSerializableSupertypes(classDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
|
||||
if (classDescriptor.isInternalSerializable && supertypes.none(::isJavaSerializable)) {
|
||||
classDescriptor.getJavaSerializableType()?.let { supertypes.add(it) }
|
||||
}
|
||||
}
|
||||
val SERIALIZER_CLASS_NAME = Name.identifier(SERIALIZER_CLASS)
|
||||
val SERIALIZER_PROVIDER_NAME = Name.identifier("serializer")
|
||||
|
||||
fun isSerialInfoImpl(thisDescriptor: ClassDescriptor): Boolean {
|
||||
return thisDescriptor.name == IMPL_NAME
|
||||
@@ -90,17 +87,40 @@ object KSerializerDescriptorResolver {
|
||||
false)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun generateSerializerProperties(thisDescriptor: ClassDescriptor,
|
||||
fromSupertypes: ArrayList<PropertyDescriptor>,
|
||||
name: Name,
|
||||
result: MutableSet<PropertyDescriptor>) {
|
||||
val classDescriptor = getSerializableClassDescriptorBySerializer(thisDescriptor) ?: return
|
||||
val classDescriptor = getSerializableClassDescriptorBySerializer(thisDescriptor) ?: return
|
||||
if (name == SERIAL_DESC_FIELD_NAME && result.none(thisDescriptor::checkSerializableClassPropertyResult) &&
|
||||
fromSupertypes.none { thisDescriptor.checkSerializableClassPropertyResult(it) && it.modality == Modality.FINAL} )
|
||||
result.add(createSerializableClassPropertyDescriptor(thisDescriptor, classDescriptor))
|
||||
fromSupertypes.none { thisDescriptor.checkSerializableClassPropertyResult(it) && it.modality == Modality.FINAL })
|
||||
result.add(createSerializableClassPropertyDescriptor(thisDescriptor, classDescriptor))
|
||||
|
||||
}
|
||||
|
||||
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 }) {
|
||||
result.add(createSerializerGetterDescriptor(thisDescriptor, classDescriptor))
|
||||
}
|
||||
}
|
||||
|
||||
fun generateSerializerMethods(thisDescriptor: ClassDescriptor,
|
||||
fromSupertypes: List<SimpleFunctionDescriptor>,
|
||||
name: Name,
|
||||
@@ -228,6 +248,71 @@ object KSerializerDescriptorResolver {
|
||||
return functionDescriptor
|
||||
}
|
||||
|
||||
fun createTypedSerializerConstructorDescriptor(classDescriptor: ClassDescriptor, serializableDescriptor: ClassDescriptor): ConstructorDescriptor {
|
||||
val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
|
||||
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 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)
|
||||
}
|
||||
|
||||
constrDesc.initialize(args, Visibilities.PUBLIC, targs)
|
||||
constrDesc.returnType = classDescriptor.defaultType
|
||||
return constrDesc
|
||||
}
|
||||
|
||||
fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor {
|
||||
val f = SimpleFunctionDescriptorImpl.create(thisClass, Annotations.EMPTY, SERIALIZER_PROVIDER_NAME, CallableMemberDescriptor.Kind.SYNTHESIZED, thisClass.source)
|
||||
val serializerClass = thisClass.getClassFromSerializationPackage("KSerializer")
|
||||
|
||||
val args = mutableListOf<ValueParameterDescriptor>()
|
||||
val typeArgs = mutableListOf<TypeParameterDescriptor>()
|
||||
var i = 0
|
||||
|
||||
serializableClass.declaredTypeParameters.forEach { it ->
|
||||
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)))
|
||||
|
||||
args.add(ValueParameterDescriptorImpl(
|
||||
f,
|
||||
null,
|
||||
i,
|
||||
Annotations.EMPTY,
|
||||
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)))
|
||||
|
||||
f.initialize(null, thisClass.thisAsReceiverParameter, typeArgs, args, serialReturnType, Modality.FINAL, Visibilities.PUBLIC)
|
||||
return f
|
||||
}
|
||||
|
||||
|
||||
private fun KotlinType.makeNullableIfNotPrimitive() =
|
||||
if (KotlinBuiltIns.isPrimitiveType(this)) this
|
||||
else this.makeNullable()
|
||||
@@ -266,6 +351,24 @@ object KSerializerDescriptorResolver {
|
||||
f.source)
|
||||
)
|
||||
|
||||
val kSerialClass = thisClass.getClassFromSerializationPackage("KSerializer").toSimpleType(false)
|
||||
|
||||
thisClass.declaredTypeParameters.forEach {
|
||||
args.add(ValueParameterDescriptorImpl(
|
||||
f,
|
||||
null,
|
||||
i++,
|
||||
Annotations.EMPTY,
|
||||
Name.identifier("$typeArgPrefix${i-3}"),
|
||||
kSerialClass,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
f.source
|
||||
))
|
||||
}
|
||||
|
||||
f.initialize(
|
||||
null,
|
||||
thisClass.thisAsReceiverParameter,
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructorParameterWithDefault: Boolean) {
|
||||
val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
||||
val type = descriptor.type
|
||||
val genericIndex = type.genericIndex
|
||||
val module = descriptor.module
|
||||
val serializableWith = descriptor.annotations.serializableWith
|
||||
val optional = descriptor.annotations.serialOptional
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.jps
|
||||
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.jps.incremental.CompileContext
|
||||
import org.jetbrains.jps.incremental.ModuleBuildTarget
|
||||
import org.jetbrains.kotlin.jps.build.KotlinJpsCompilerArgumentsProvider
|
||||
import java.io.File
|
||||
|
||||
class KotlinSerializationJpsPlugin : KotlinJpsCompilerArgumentsProvider {
|
||||
val JAR_FILE_NAME = "kotlinx-serialization-compiler-plugin.jar"
|
||||
|
||||
override fun getExtraArguments(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List<String> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user