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

kotlin.reflect.jvm.internal.KCallableImpl.kt Maven / Gradle / Ivy

There is a newer version: 2.0.20
Show newest version
/*
 * Copyright 2010-2018 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 kotlin.reflect.jvm.internal

import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import java.lang.reflect.Array as ReflectArray
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.lang.reflect.WildcardType
import java.util.*
import kotlin.coroutines.Continuation
import kotlin.reflect.*
import kotlin.reflect.jvm.internal.calls.Caller
import kotlin.reflect.jvm.javaType
import kotlin.reflect.jvm.jvmErasure

internal abstract class KCallableImpl : KCallable, KTypeParameterOwnerImpl {
    abstract val descriptor: CallableMemberDescriptor

    // The instance which is used to perform a positional call, i.e. `call`
    abstract val caller: Caller<*>

    // The instance which is used to perform a call "by name", i.e. `callBy`
    abstract val defaultCaller: Caller<*>?

    abstract val container: KDeclarationContainerImpl

    abstract val isBound: Boolean

    private val _annotations = ReflectProperties.lazySoft { descriptor.computeAnnotations() }

    override val annotations: List get() = _annotations()

    private val _parameters = ReflectProperties.lazySoft {
        val descriptor = descriptor
        val result = ArrayList()
        var index = 0

        if (!isBound) {
            val instanceReceiver = descriptor.instanceReceiverParameter
            if (instanceReceiver != null) {
                result.add(KParameterImpl(this, index++, KParameter.Kind.INSTANCE) { instanceReceiver })
            }

            val extensionReceiver = descriptor.extensionReceiverParameter
            if (extensionReceiver != null) {
                result.add(KParameterImpl(this, index++, KParameter.Kind.EXTENSION_RECEIVER) { extensionReceiver })
            }
        }

        for (i in descriptor.valueParameters.indices) {
            result.add(KParameterImpl(this, index++, KParameter.Kind.VALUE) { descriptor.valueParameters[i] })
        }

        // Constructor parameters of Java annotations are not ordered in any way, we order them by name here to be more stable.
        // Note that positional call (via "call") is not allowed unless there's a single non-"value" parameter,
        // so the order of parameters of Java annotation constructors here can be arbitrary
        if (isAnnotationConstructor && descriptor is JavaCallableMemberDescriptor) {
            result.sortBy { it.name }
        }

        result.trimToSize()
        result
    }

    override val parameters: List
        get() = _parameters()

    private val _returnType = ReflectProperties.lazySoft {
        KTypeImpl(descriptor.returnType!!) {
            extractContinuationArgument() ?: caller.returnType
        }
    }

    override val returnType: KType
        get() = _returnType()

    private val _typeParameters = ReflectProperties.lazySoft {
        descriptor.typeParameters.map { descriptor -> KTypeParameterImpl(this, descriptor) }
    }

    override val typeParameters: List
        get() = _typeParameters()

    override val visibility: KVisibility?
        get() = descriptor.visibility.toKVisibility()

    override val isFinal: Boolean
        get() = descriptor.modality == Modality.FINAL

    override val isOpen: Boolean
        get() = descriptor.modality == Modality.OPEN

    override val isAbstract: Boolean
        get() = descriptor.modality == Modality.ABSTRACT

    protected val isAnnotationConstructor: Boolean
        get() = name == "" && container.jClass.isAnnotation

    @Suppress("UNCHECKED_CAST")
    override fun call(vararg args: Any?): R = reflectionCall {
        return caller.call(args) as R
    }

    override fun callBy(args: Map): R {
        return if (isAnnotationConstructor) callAnnotationConstructor(args) else callDefaultMethod(args, null)
    }

    // See ArgumentGenerator#generate
    internal fun callDefaultMethod(args: Map, continuationArgument: Continuation<*>?): R {
        val parameters = parameters
        val arguments = ArrayList(parameters.size)
        var mask = 0
        val masks = ArrayList(1)
        var index = 0
        var anyOptional = false

        for (parameter in parameters) {
            if (index != 0 && index % Integer.SIZE == 0) {
                masks.add(mask)
                mask = 0
            }

            when {
                args.containsKey(parameter) -> {
                    arguments.add(args[parameter])
                }
                parameter.isOptional -> {
                    // For inline class types, the javaType refers to the underlying type of the inline class,
                    // but we have to pass null in order to mark the argument as absent for InlineClassAwareCaller.
                    arguments.add(if (parameter.type.isInlineClassType) null else defaultPrimitiveValue(parameter.type.javaType))
                    mask = mask or (1 shl (index % Integer.SIZE))
                    anyOptional = true
                }
                parameter.isVararg -> {
                    arguments.add(defaultEmptyArray(parameter.type))
                }
                else -> {
                    throw IllegalArgumentException("No argument provided for a required parameter: $parameter")
                }
            }

            if (parameter.kind == KParameter.Kind.VALUE) {
                index++
            }
        }

        if (continuationArgument != null) {
            arguments.add(continuationArgument)
        }

        if (!anyOptional) {
            return call(*arguments.toTypedArray())
        }

        masks.add(mask)

        val caller = defaultCaller ?: throw KotlinReflectionInternalError("This callable does not support a default call: $descriptor")

        arguments.addAll(masks)

        // DefaultConstructorMarker or MethodHandle
        arguments.add(null)

        @Suppress("UNCHECKED_CAST")
        return reflectionCall {
            caller.call(arguments.toTypedArray()) as R
        }
    }

    private fun callAnnotationConstructor(args: Map): R {
        val arguments = parameters.map { parameter ->
            when {
                args.containsKey(parameter) -> {
                    args[parameter] ?: throw IllegalArgumentException("Annotation argument value cannot be null ($parameter)")
                }
                parameter.isOptional -> null
                parameter.isVararg -> defaultEmptyArray(parameter.type)
                else -> throw IllegalArgumentException("No argument provided for a required parameter: $parameter")
            }
        }

        val caller = defaultCaller ?: throw KotlinReflectionInternalError("This callable does not support a default call: $descriptor")

        @Suppress("UNCHECKED_CAST")
        return reflectionCall {
            caller.call(arguments.toTypedArray()) as R
        }
    }

    private fun defaultEmptyArray(type: KType): Any =
        type.jvmErasure.java.run {
            if (isArray) ReflectArray.newInstance(componentType, 0)
            else throw KotlinReflectionInternalError(
                "Cannot instantiate the default empty array of type $simpleName, because it is not an array type"
            )
        }

    private fun extractContinuationArgument(): Type? {
        if ((descriptor as? FunctionDescriptor)?.isSuspend == true) {
            // kotlin.coroutines.Continuation
            val continuationType = caller.parameterTypes.lastOrNull() as? ParameterizedType
            if (continuationType?.rawType == Continuation::class.java) {
                // ? super java.lang.String
                val wildcard = continuationType.actualTypeArguments.single() as? WildcardType
                // java.lang.String
                return wildcard?.lowerBounds?.first()
            }
        }

        return null
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy