All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationResolveExtension.kt Maven / Gradle / Ivy

/*
 * Copyright 2010-2022 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

import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.platform.jvm.isJvm
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
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializationDescriptorUtils
import org.jetbrains.kotlinx.serialization.compiler.resolve.*

open class SerializationResolveExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : SyntheticResolveExtension {
    override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List = when {
        (thisDescriptor.shouldHaveGeneratedSerializer) && !thisDescriptor.hasCompanionObjectAsSerializer ->
            listOf(SerialEntityNames.SERIALIZER_CLASS_NAME)
        else -> listOf()
    }

    override fun getPossibleSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List? {
        return listOf(SerialEntityNames.SERIALIZER_CLASS_NAME)
    }

    override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = when {
        thisDescriptor.isSerializableObject || thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null ->
            listOf(SerialEntityNames.SERIALIZER_PROVIDER_NAME)
        thisDescriptor.isInternalSerializable && !thisDescriptor.isInlineClass() && thisDescriptor.platform?.isJvm() == true && !hasCustomizedSerializeMethod(thisDescriptor) -> {
            // add write$Self, but only if .serialize was not customized in companion.
            // It works not only on JVM, but I see no reason to enable it on other platforms —
            // private fields there have no access control, and additional function
            // only increases compiled code size.
            listOf(SerialEntityNames.WRITE_SELF_NAME)
        }
        else -> emptyList()
    }

    override fun getSyntheticPropertiesNames(thisDescriptor: ClassDescriptor): List {
        // typeSerial0, typeSerial1, ... for serializers of parameterized classes
        val count = thisDescriptor.declaredTypeParameters.size
        if (count < 1) return emptyList()
        val classDescriptor = getSerializableClassDescriptorBySerializer(thisDescriptor) ?: return emptyList()
        if (!isAllowedToHaveAutoGeneratedSerializerMethods(thisDescriptor, classDescriptor)) return emptyList()
        val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" }.map { Name.identifier(it) }
        return propNames
    }

    private fun hasCustomizedSerializeMethod(serializableClass: ClassDescriptor): Boolean {
        // We cannot check whether companion has @Serializer(MyClass::class) annotation due to recursive resolve problems
        // (apparently, resolve MyClass type asks for all function names, which leads us to this function again)
        // so we rely on less strict check that companion just has non-empty @Serializer annotation.
        // Anyway, I doubt that serializable class companion would ever be serializer for _another_ class.
        val companion = serializableClass.companionObjectDescriptor ?: return false
        return companion.annotations.hasAnnotation(SerializationAnnotations.serializerAnnotationFqName)
    }

    override fun generateSyntheticClasses(
        thisDescriptor: ClassDescriptor,
        name: Name,
        ctx: LazyClassContext,
        declarationProvider: ClassMemberDeclarationProvider,
        result: MutableSet
    ) {
        if (thisDescriptor.shouldHaveGeneratedSerializer && name == SerialEntityNames.SERIALIZER_CLASS_NAME &&
            result.none { it.name == SerialEntityNames.SERIALIZER_CLASS_NAME }
        )
            result.add(KSerializerDescriptorResolver.addSerializerImplClass(thisDescriptor, declarationProvider, ctx))
        return
    }

    override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? =
        if (thisDescriptor.shouldHaveGeneratedMethodsInCompanion && !thisDescriptor.isSerializableObject)
            SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
        else null

    override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList) {
        KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes)
        KSerializerDescriptorResolver.addSerializerFactorySuperType(thisDescriptor, supertypes)
    }

    override fun generateSyntheticSecondaryConstructors(
        thisDescriptor: ClassDescriptor,
        bindingContext: BindingContext,
        result: MutableCollection
    ) {
        if (thisDescriptor.isInternalSerializable) {
            // do not add synthetic deserialization constructor if .deserialize method is customized
            if (thisDescriptor.hasCompanionObjectAsSerializer && SerializationDescriptorUtils.getSyntheticLoadMember(thisDescriptor.companionObjectDescriptor!!) == null) return
            if (thisDescriptor.isInlineClass()) return
            result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext, metadataPlugin))
        }
    }

    override fun generateSyntheticMethods(
        thisDescriptor: ClassDescriptor,
        name: Name,
        bindingContext: BindingContext,
        fromSupertypes: List,
        result: MutableCollection
    ) {
        KSerializerDescriptorResolver.generateSerializerMethods(thisDescriptor, fromSupertypes, name, result)
        KSerializerDescriptorResolver.generateCompanionObjectMethods(thisDescriptor, name, result)
        KSerializerDescriptorResolver.generateSerializableClassMethods(thisDescriptor, name, result)
    }

    override fun generateSyntheticProperties(
        thisDescriptor: ClassDescriptor,
        name: Name,
        bindingContext: BindingContext,
        fromSupertypes: ArrayList,
        result: MutableSet
    ) {
        KSerializerDescriptorResolver.generateSerializerProperties(thisDescriptor, fromSupertypes, name, result)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy