Compare commits

...

4 Commits

Author SHA1 Message Date
Leonid Startsev
31c7e8e8dd Remove unused declarations 2020-12-10 19:40:10 +03:00
Leonid Startsev
22e24528d8 Update error about unsupported inline classes 2020-12-10 17:25:26 +03:00
Leonid Startsev
8f1559ed5a Support other unsigned types than UInt 2020-12-10 17:25:26 +03:00
Leonid Startsev
ba3cb161ce Support serializable inline classes in IR plugin
as well as standard UInt type.
2020-12-10 17:24:38 +03:00
14 changed files with 244 additions and 93 deletions

View File

@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlinx.serialization.compiler.backend.common
@@ -41,9 +30,12 @@ abstract class SerializableCodegen(
generateSyntheticMethods()
}
private inline fun ClassDescriptor.shouldHaveSpecificSyntheticMethods(functionPresenceChecker: () -> FunctionDescriptor?) =
!isInline && (isAbstractSerializableClass() || isSealedSerializableClass() || functionPresenceChecker() != null)
private fun generateSyntheticInternalConstructor() {
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
if (serializableDescriptor.isAbstractSerializableClass() || serializableDescriptor.isSealedSerializableClass() || SerializerCodegen.getSyntheticLoadMember(serializerDescriptor) != null) {
if (serializableDescriptor.shouldHaveSpecificSyntheticMethods { SerializerCodegen.getSyntheticLoadMember(serializerDescriptor) }) {
val constrDesc = serializableDescriptor.secondaryConstructors.find(ClassConstructorDescriptor::isSerializationCtor) ?: return
generateInternalConstructor(constrDesc)
}
@@ -51,7 +43,7 @@ abstract class SerializableCodegen(
private fun generateSyntheticMethods() {
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
if (serializableDescriptor.isAbstractSerializableClass() || serializableDescriptor.isSealedSerializableClass() || SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) != null) {
if (serializableDescriptor.shouldHaveSpecificSyntheticMethods { SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) }) {
val func = KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(serializableDescriptor)
generateWriteSelfMethod(func)
}

View File

@@ -168,6 +168,10 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
"F", "kotlin.Float" -> "FloatSerializer"
"D", "kotlin.Double" -> "DoubleSerializer"
"C", "kotlin.Char" -> "CharSerializer"
"kotlin.UInt" -> "UIntSerializer"
"kotlin.ULong" -> "ULongSerializer"
"kotlin.UByte" -> "UByteSerializer"
"kotlin.UShort" -> "UShortSerializer"
"kotlin.String" -> "StringSerializer"
"kotlin.Pair" -> "PairSerializer"
"kotlin.Triple" -> "TripleSerializer"

View File

@@ -99,7 +99,7 @@ interface IrBuilderExtension {
typeHint: IrType? = null
): IrMemberAccessExpression<*> {
assert(callee.isBound) { "Symbol $callee expected to be bound" }
val returnType = typeHint ?: callee.run { owner.returnType }
val returnType = typeHint ?: callee.owner.returnType
val call = irCall(callee, type = returnType)
call.dispatchReceiver = dispatchReceiver
args.forEachIndexed(call::putValueArgument)

View File

@@ -31,7 +31,7 @@ class SerialInfoImplJvmIrGenerator(
override val compilerContext: SerializationPluginContext
get() = context
private val jvmNameClass = context.referenceClass(DescriptorUtils.JVM_NAME)!!.owner
private val jvmNameClass get() = context.referenceClass(DescriptorUtils.JVM_NAME)!!.owner
private val implGenerated = mutableSetOf<IrClass>()
private val annotationToImpl = mutableMapOf<IrClass, IrClass>()

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializerForInlineClassGenerator(
irClass: IrClass,
compilerContext: SerializationPluginContext,
bindingContext: BindingContext,
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
) : SerializerIrGenerator(irClass, compilerContext, bindingContext, null, serialInfoJvmGenerator) {
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val encodeInline = encoderClass.referenceMethod(CallingConventions.encodeInline)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
// val inlineEncoder = encoder.encodeInline()
val encodeInlineCall: IrExpression = irInvoke(irGet(saveFunc.valueParameters[0]), encodeInline, serialDescGetter)
val inlineEncoder = irTemporary(encodeInlineCall, nameHint = "inlineEncoder")
val property = serializableProperties.first()
val value = getFromBox(irGet(saveFunc.valueParameters[1]), property)
// inlineEncoder.encodeInt/String/SerializableValue
val elementCall = formEncodeDecodePropertyCall(irGet(inlineEncoder), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
val f =
encoderClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue")
f to listOf(
innerSerial,
value
)
}, {
val f =
encoderClass.referenceMethod("${CallingConventions.encode}${it.elementMethodPrefix}")
val args = if (it.elementMethodPrefix != "Unit") listOf(value) else emptyList()
f to args
})
val actualEncodeCall = irIfNull(compilerContext.irBuiltIns.unitType, irGet(inlineEncoder), irNull(), elementCall)
+actualEncodeCall
}
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc ->
fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val decodeInline = decoderClass.referenceMethod(CallingConventions.decodeInline)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
// val inlineDecoder = decoder.decodeInline()
val inlineDecoder: IrExpression = irInvoke(irGet(loadFunc.valueParameters[0]), decodeInline, serialDescGetter)
val property = serializableProperties.first()
val inlinedType = property.type.toIrType()
val actualCall = formEncodeDecodePropertyCall(inlineDecoder, loadFunc.dispatchReceiverParameter!!, property, { innerSerial, sti ->
decoderClass.referenceMethod( "${CallingConventions.decode}${sti.elementMethodPrefix}SerializableValue") to listOf(innerSerial)
}, {
decoderClass.referenceMethod("${CallingConventions.decode}${it.elementMethodPrefix}") to listOf()
}, returnTypeHint = inlinedType)
val value = coerceToBox(actualCall, inlinedType, loadFunc.returnType)
+irReturn(value)
}
override val serialDescImplClass: ClassDescriptor = serializerDescriptor
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_INLINE)
override fun IrBlockBodyBuilder.instantiateNewDescriptor(
serialDescImplClass: ClassDescriptor,
correctThis: IrExpression
): IrExpression {
val ctor = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe).single { it.owner.isPrimary }
return irInvoke(
null, ctor,
irString(serialName),
correctThis
)
}
// Compiler will elide these in corresponding inline class lowerings (when serialize/deserialize functions will be split in two)
private fun IrBlockBodyBuilder.coerceToBox(expression: IrExpression, propertyType: IrType, inlineClassBoxType: IrType): IrExpression =
irInvoke(
null,
serializableIrClass.constructors.single { it.isPrimary }.symbol,
(inlineClassBoxType as IrSimpleType).arguments.map { it.typeOrNull },
listOf(expression)
)
private fun IrBlockBodyBuilder.getFromBox(expression: IrExpression, serializableProperty: SerializableProperty): IrExpression =
getProperty(expression, serializableProperty.irProp)
}

View File

@@ -25,8 +25,11 @@ import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerForEnumsCodegen
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -39,6 +42,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UN
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER", true)
internal typealias FunctionWithArgs = Pair<IrFunctionSymbol, List<IrExpression>>
open class SerializerIrGenerator(
val irClass: IrClass,
final override val compilerContext: SerializationPluginContext,
@@ -286,22 +291,7 @@ open class SerializerIrGenerator(
// internal serialization via virtual calls?
for ((index, property) in serializableProperties.filter { !it.transient }.withIndex()) {
// output.writeXxxElementValue(classDesc, index, value)
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(
this@SerializerIrGenerator,
saveFunc.dispatchReceiverParameter!!,
sti.serializer,
property.module,
property.type,
genericIndex = property.genericIndex
)
val (writeFunc, args: List<IrExpression>) = if (innerSerial == null) {
val f =
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
if (sti.elementMethodPrefix != "Unit") args.add(property.irGet())
f to args
} else {
val elementCall = formEncodeDecodePropertyCall(irGet(localOutput), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
val f =
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
f to listOf(
@@ -310,9 +300,13 @@ open class SerializerIrGenerator(
innerSerial,
property.irGet()
)
}
val typeArgs = if (writeFunc.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val elementCall = irInvoke(irGet(localOutput), writeFunc, typeArguments = typeArgs, valueArguments = args)
}, {
val f =
kOutputClass.referenceMethod("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}")
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
if (it.elementMethodPrefix != "Unit") args.add(property.irGet())
f to args
})
// check for call to .shouldEncodeElementDefault
if (!property.optional || index < ignoreIndexTo) {
@@ -337,6 +331,28 @@ open class SerializerIrGenerator(
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
}
protected inline fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
encoder: IrExpression,
dispatchReceiver: IrValueParameter,
property: SerializableProperty,
whenHaveSerializer: (serializer: IrExpression, sti: SerialTypeInfo) -> FunctionWithArgs,
whenDoNot: (sti: SerialTypeInfo) -> FunctionWithArgs,
returnTypeHint: IrType? = null
): IrExpression {
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(
this@SerializerIrGenerator,
dispatchReceiver,
sti.serializer,
property.module,
property.type,
genericIndex = property.genericIndex
)
val (functionToCall, args: List<IrExpression>) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti)
val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint)
}
// returns null: Any? for boxed types and 0: <number type> for primitives
private fun IrBuilderWithScope.defaultValueAndType(prop: SerializableProperty): Pair<IrExpression, IrType> {
val kType = prop.descriptor.returnType!!
@@ -403,33 +419,23 @@ open class SerializerIrGenerator(
val decoderCalls: List<Pair<Int, IrExpression>> =
serializableProperties.mapIndexed { index, property ->
val body = irBlock {
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(
this@SerializerIrGenerator,
loadFunc.dispatchReceiverParameter!!,
sti.serializer,
property.module,
property.type,
genericIndex = property.genericIndex
)
val isSerializable = innerSerial != null
val decodeFuncToCall =
(if (isSerializable) "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}"
else "${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
.let {
inputClass.referenceMethod(it) { it.valueParameters.size == if (isSerializable) 4 else 2 }
}
val typeArgs =
if (decodeFuncToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index))
if (isSerializable) {
args.add(innerSerial!!)
args.add(localProps[index].get())
}
val decodeFuncToCall = formEncodeDecodePropertyCall(localInput.get(), loadFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
inputClass.referenceMethod(
"${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}", {it.valueParameters.size == 4}
) to listOf(
localSerialDesc.get(), irInt(index), innerSerial, localProps[index].get()
)
}, {
inputClass.referenceMethod(
"${CallingConventions.decode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}", {it.valueParameters.size == 2}
) to listOf(
localSerialDesc.get(), irInt(index)
)
}, returnTypeHint = property.type.toIrType())
// local$i = localInput.decode...(...)
+irSet(
localProps[index].symbol,
irInvoke(localInput.get(), decodeFuncToCall, typeArgs, args, returnTypeHint = property.type.toIrType())
decodeFuncToCall
)
// bitMask[i] |= 1 << x
val bitPos = 1 shl (index % 32)
@@ -507,11 +513,12 @@ open class SerializerIrGenerator(
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
) {
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
if (serializableDesc.isSerializableEnum()) {
SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator).generate()
} else {
SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator).generate()
val generator = when {
serializableDesc.isSerializableEnum() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
serializableDesc.isInline -> SerializerForInlineClassGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
else -> SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator)
}
generator.generate()
irClass.patchDeclarationParents(irClass.parent)
}
}

View File

@@ -14,7 +14,7 @@ import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
import static org.jetbrains.kotlin.diagnostics.Severity.WARNING;
public interface SerializationErrors {
DiagnosticFactory0<PsiElement> INLINE_CLASSES_NOT_SUPPORTED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory2<PsiElement, String, String> INLINE_CLASSES_NOT_SUPPORTED = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<PsiElement> PLUGIN_IS_NOT_ENABLED = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> EXPLICIT_SERIALIZABLE_IS_REQUIRED = DiagnosticFactory0.create(WARNING);

View File

@@ -123,8 +123,16 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
return false
}
if (descriptor.isInlineClass()) {
trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED)
if (descriptor.isInlineClass() && !canSupportInlineClasses(descriptor.module, trace)) {
descriptor.onSerializableAnnotation {
trace.report(
SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED.on(
it,
VersionReader.minVersionForInlineClasses.toString(),
VersionReader.getVersionsForCurrentModuleFromTrace(descriptor.module, trace)?.implementationVersion.toString()
)
)
}
return false
}
if (!descriptor.hasSerializableAnnotationWithoutArgs) return false
@@ -249,6 +257,11 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
private fun KotlinType.isUnsupportedInlineType() = isInlineClassType() && !KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(this)
private fun canSupportInlineClasses(module: ModuleDescriptor, trace: BindingTrace): Boolean {
if (isIde) return true // do not get version from jar manifest in ide
return VersionReader.canSupportInlineClasses(module, trace)
}
private fun AbstractSerialGenerator.checkType(
module: ModuleDescriptor,
type: KotlinType,
@@ -258,8 +271,12 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
) {
if (type.genericIndex != null) return // type arguments always have serializer stored in class' field
val element = ktType?.typeElement
if (type.isUnsupportedInlineType()) {
trace.report(SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED.on(element ?: fallbackElement))
if (type.isUnsupportedInlineType() && !canSupportInlineClasses(module, trace)) {
trace.report(SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED.on(
element ?: fallbackElement,
VersionReader.minVersionForInlineClasses.toString(),
VersionReader.getVersionsForCurrentModuleFromTrace(module, trace)?.implementationVersion.toString()
))
}
val serializer = findTypeSerializerOrContextUnchecked(module, type)
if (serializer != null) {

View File

@@ -16,7 +16,9 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
init {
MAP.put(
SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED,
"Inline classes are not supported by kotlinx.serialization yet"
"Inline classes require runtime serialization library version at least {0}, while your classpath has {1}.",
Renderers.STRING,
Renderers.STRING,
)
MAP.put(
SerializationErrors.PLUGIN_IS_NOT_ENABLED,

View File

@@ -65,4 +65,13 @@ object VersionReader {
if (!file.exists()) return null
return getVersionsFromManifest(file)
}
internal val minVersionForInlineClasses = ApiVersion.parse("1.1-M1-SNAPSHOT")!!
fun canSupportInlineClasses(module: ModuleDescriptor, trace: BindingTrace): Boolean {
// Klibs do not have manifest file, unfortunately, so we hope for the better
val currentVersion = getVersionsForCurrentModuleFromTrace(module, trace) ?: return true
val implVersion = currentVersion.implementationVersion ?: return false
return implVersion >= minVersionForInlineClasses
}
}

View File

@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlinx.serialization.compiler.extensions
@@ -26,6 +15,7 @@ import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.platform
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.types.KotlinType
@@ -87,6 +77,7 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP
if (thisDescriptor.isInternalSerializable) {
// do not add synthetic deserialization constructor if .deserialize method is customized
if (thisDescriptor.hasCompanionObjectAsSerializer && SerializerCodegen.getSyntheticLoadMember(thisDescriptor.companionObjectDescriptor!!) == null) return
if (thisDescriptor.isInline) return
result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext, metadataPlugin))
}
}

View File

@@ -69,6 +69,7 @@ object SerialEntityNames {
const val SERIAL_DESCRIPTOR_CLASS = "SerialDescriptor"
const val SERIAL_DESCRIPTOR_CLASS_IMPL = "PluginGeneratedSerialDescriptor"
const val SERIAL_DESCRIPTOR_FOR_ENUM = "EnumDescriptor"
const val SERIAL_DESCRIPTOR_FOR_INLINE = "InlineClassDescriptor"
const val PLUGIN_EXCEPTIONS_FILE = "PluginExceptions"
@@ -114,6 +115,8 @@ object CallingConventions {
const val encode = "encode"
const val encodeEnum = "encodeEnum"
const val decodeEnum = "decodeEnum"
const val encodeInline = "encodeInline"
const val decodeInline = "decodeInline"
const val decodeElementIndex = "decodeElementIndex"
const val decodeSequentially = "decodeSequentially"
const val elementPostfix = "Element"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -8,10 +8,12 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
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.idea.runIfEnabledIn
import org.jetbrains.kotlinx.serialization.idea.runIfEnabledOn
class SerializationIDECodegenExtension : SerializationCodegenExtension() {
@@ -31,7 +33,10 @@ class SerializationIDEJsExtension : SerializationJsExtension() {
}
class SerializationIDEIrExtension : SerializationLoweringExtension() {
@OptIn(ObsoleteDescriptorBasedAPI::class)
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
/* No-op don't enable IR extensions in IDE */
runIfEnabledIn(pluginContext.moduleDescriptor) {
super.generate(moduleFragment, pluginContext)
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -7,16 +7,23 @@ package org.jetbrains.kotlinx.serialization.idea
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.idea.core.unwrapModuleSourceInfo
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.resolve.descriptorUtil.module
fun <T> getIfEnabledOn(clazz: ClassDescriptor, body: () -> T): T? {
val module = clazz.module.getCapability(ModuleInfo.Capability)?.unwrapModuleSourceInfo()?.module ?: return null
val facet = KotlinFacet.get(module) ?: return null
val pluginClasspath = facet.configuration.settings.compilerArguments?.pluginClasspaths ?: return null
if (pluginClasspath.none(KotlinSerializationImportHandler::isPluginJarPath)) return null
return body()
private fun isEnabledIn(moduleDescriptor: ModuleDescriptor): Boolean {
val module = moduleDescriptor.getCapability(ModuleInfo.Capability)?.unwrapModuleSourceInfo()?.module ?: return false
val facet = KotlinFacet.get(module) ?: return false
val pluginClasspath = facet.configuration.settings.compilerArguments?.pluginClasspaths ?: return false
if (pluginClasspath.none(KotlinSerializationImportHandler::isPluginJarPath)) return false
return true
}
fun runIfEnabledOn(clazz: ClassDescriptor, body: () -> Unit) { getIfEnabledOn<Unit>(clazz, body) }
fun <T> getIfEnabledOn(clazz: ClassDescriptor, body: () -> T): T? {
return if (isEnabledIn(clazz.module)) body() else null
}
fun runIfEnabledOn(clazz: ClassDescriptor, body: () -> Unit) { getIfEnabledOn<Unit>(clazz, body) }
fun runIfEnabledIn(moduleDescriptor: ModuleDescriptor, block: () -> Unit) { if (isEnabledIn(moduleDescriptor)) block() }