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

.kotlin.kotlin-noarg.1.4.20-RC.source-code.AbstractNoArgExpressionCodegenExtension.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1
Show newest version
/*
 * Copyright 2010-2019 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.kotlin.noarg

import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy.CodegenBased
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.extensions.AnnotationBasedExtension
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Opcodes


class CliNoArgExpressionCodegenExtension(private val annotations: List, invokeInitializers: Boolean = false) :
    AbstractNoArgExpressionCodegenExtension(invokeInitializers) {

    override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List = annotations
}

abstract class AbstractNoArgExpressionCodegenExtension(val invokeInitializers: Boolean) : ExpressionCodegenExtension,
    AnnotationBasedExtension {

    override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) = with(codegen) {
        if (shouldGenerateNoArgConstructor()) {
            generateNoArgConstructor()
        }
    }

    private fun ImplementationBodyCodegen.generateNoArgConstructor() {
        val superClassInternalName = typeMapper.mapClass(descriptor.getSuperClassOrAny()).internalName

        val constructorDescriptor = createNoArgConstructorDescriptor(descriptor)

        val superClass = descriptor.getSuperClassOrAny()

        // If a parent sealed class has not a zero-parameter constructor, user must write @NoArg annotation for the parent class as well,
        // and then we generate ()V
        val isParentASealedClassWithDefaultConstructor =
            superClass.modality == Modality.SEALED && superClass.constructors.any { isZeroParameterConstructor(it) }

        functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, constructorDescriptor, object : CodegenBased(state) {
            override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
                codegen.v.load(0, AsmTypes.OBJECT_TYPE)

                if (isParentASealedClassWithDefaultConstructor) {
                    codegen.v.aconst(null)
                    codegen.v.visitMethodInsn(
                        Opcodes.INVOKESPECIAL, superClassInternalName, "",
                        "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V", false
                    )
                } else {
                    codegen.v.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassInternalName, "", "()V", false)
                }

                if (invokeInitializers) {
                    generateInitializers(codegen)
                }
                codegen.v.visitInsn(Opcodes.RETURN)
            }
        })
    }

    private fun ImplementationBodyCodegen.shouldGenerateNoArgConstructor(): Boolean {
        val origin = myClass as? KtClass ?: return false

        if (descriptor.kind != ClassKind.CLASS || !descriptor.hasSpecialAnnotation(origin)) {
            return false
        }

        return descriptor.constructors.none { isZeroParameterConstructor(it) }
    }

    override val shouldGenerateClassSyntheticPartsInLightClassesMode = true

    companion object {

        fun isZeroParameterConstructor(constructor: ClassConstructorDescriptor): Boolean {
            val parameters = constructor.valueParameters
            return parameters.isEmpty() ||
                    (parameters.all { it.declaresDefaultValue() } && (constructor.isPrimary || constructor.findJvmOverloadsAnnotation() != null))
        }

        fun createNoArgConstructorDescriptor(containingClass: ClassDescriptor): ConstructorDescriptor =
            ClassConstructorDescriptorImpl.createSynthesized(containingClass, Annotations.EMPTY, false, SourceElement.NO_SOURCE).apply {
                initialize(
                    null,
                    calculateDispatchReceiverParameter(),
                    emptyList(),
                    emptyList(),
                    containingClass.builtIns.unitType,
                    Modality.OPEN,
                    DescriptorVisibilities.PUBLIC
                )
            }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy