kotlin.reflect.jvm.internal.KCallableImpl.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-reflect Show documentation
Show all versions of kotlin-reflect Show documentation
Kotlin Full Reflection Library
/*
* 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
}
}