Add KFunction.name, support reflection for function references
#KT-7694 Fixed
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classLoader
|
||||
@@ -29,8 +30,8 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmType.PrimitiveType.*
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
import kotlin.reflect.KDeclarationContainer
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
|
||||
abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
// Note: this is stored here on a soft reference to prevent GC from destroying the weak reference to it in the moduleByClassLoader cache
|
||||
@@ -44,7 +45,7 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
|
||||
fun findPropertyDescriptor(name: String, receiverDesc: String? = null): PropertyDescriptor {
|
||||
val properties = scope
|
||||
.getProperties(Name.identifier(name))
|
||||
.getProperties(Name.guess(name))
|
||||
.filter { descriptor ->
|
||||
descriptor is PropertyDescriptor &&
|
||||
descriptor.getName().asString() == name &&
|
||||
@@ -55,16 +56,34 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
}
|
||||
|
||||
if (properties.size() != 1) {
|
||||
val debugText = if (receiverDesc == null) name else "$receiverDesc.$name"
|
||||
val debugText = if (receiverDesc == null) name else "'$receiverDesc.$name'"
|
||||
throw KotlinReflectionInternalError(
|
||||
if (properties.isEmpty()) "Property '$debugText' not resolved in $this"
|
||||
else "${properties.size()} properties '$debugText' resolved in $this"
|
||||
if (properties.isEmpty()) "Property $debugText not resolved in $this"
|
||||
else "${properties.size()} properties $debugText resolved in $this: $properties"
|
||||
)
|
||||
}
|
||||
|
||||
return properties.single() as PropertyDescriptor
|
||||
}
|
||||
|
||||
fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor {
|
||||
val functions = scope
|
||||
.getFunctions(Name.guess(name))
|
||||
.filter { descriptor ->
|
||||
RuntimeTypeMapper.mapSignature(descriptor) == signature
|
||||
}
|
||||
|
||||
if (functions.size() != 1) {
|
||||
val debugText = "'$name' (JVM signature: $signature)"
|
||||
throw KotlinReflectionInternalError(
|
||||
if (functions.isEmpty()) "Function $debugText not resolved in $this"
|
||||
else "${functions.size()} functions $debugText resolved in $this: $functions"
|
||||
)
|
||||
}
|
||||
|
||||
return functions.single()
|
||||
}
|
||||
|
||||
// TODO: check resulting method's return type
|
||||
fun findMethodBySignature(signature: JvmProtoBuf.JvmMethodSignature, nameResolver: NameResolver, declared: Boolean): Method? {
|
||||
val name = nameResolver.getString(signature.getName())
|
||||
|
||||
@@ -19,6 +19,7 @@ package kotlin.reflect.jvm.internal
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
import kotlin.reflect.*
|
||||
@@ -39,7 +40,9 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
|
||||
private val classId: ClassId get() = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass)
|
||||
|
||||
override val scope: JetScope get() = descriptor.getDefaultType().getMemberScope()
|
||||
override val scope: JetScope get() = ChainedScope(
|
||||
descriptor, "KClassImpl scope", descriptor.getDefaultType().getMemberScope(), descriptor.getStaticScope()
|
||||
)
|
||||
|
||||
override val simpleName: String? get() {
|
||||
if (jClass.isAnonymousClass()) return null
|
||||
|
||||
@@ -16,6 +16,41 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import kotlin.jvm.internal.FunctionImpl
|
||||
import kotlin.reflect.KFunction
|
||||
|
||||
abstract class KFunctionImpl<out R> : FunctionImpl()
|
||||
abstract class KFunctionImpl private constructor(
|
||||
container: KCallableContainerImpl,
|
||||
name: String,
|
||||
signature: String,
|
||||
descriptorInitialValue: FunctionDescriptor?
|
||||
) : KFunction<Any?>, FunctionImpl() {
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String): this(container, name, signature, null)
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: FunctionDescriptor): this(
|
||||
container, descriptor.getName().asString(), RuntimeTypeMapper.mapSignature(descriptor), descriptor
|
||||
)
|
||||
|
||||
protected val descriptor: FunctionDescriptor by ReflectProperties.lazySoft<FunctionDescriptor>(descriptorInitialValue) {
|
||||
container.findFunctionDescriptor(name, signature)
|
||||
}
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override fun getArity(): Int {
|
||||
// TODO: test?
|
||||
return descriptor.getValueParameters().size() +
|
||||
(if (descriptor.getDispatchReceiverParameter() != null) 1 else 0) +
|
||||
(if (descriptor.getExtensionReceiverParameter() != null) 1 else 0)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KFunctionImpl && descriptor == other.descriptor
|
||||
|
||||
override fun hashCode(): Int =
|
||||
descriptor.hashCode()
|
||||
|
||||
override fun toString(): String =
|
||||
ReflectionObjectRenderer.renderFunction(descriptor)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
||||
|
||||
@Override
|
||||
public KFunction function(FunctionReference f) {
|
||||
return f;
|
||||
return new KTopLevelFreeFunctionImpl((KPackageImpl) f.getOwner(), f.getName(), f.getSignature());
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
@@ -23,29 +25,47 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
object ReflectionObjectRenderer {
|
||||
private val renderer = DescriptorRenderer.FQ_NAMES_IN_TYPES
|
||||
|
||||
private fun StringBuilder.appendReceiverType(receiver: ReceiverParameterDescriptor?) {
|
||||
if (receiver != null) {
|
||||
append(renderer.renderType(receiver.getType()))
|
||||
append(".")
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendReceiversAndName(callable: CallableDescriptor) {
|
||||
val dispatchReceiver = callable.getDispatchReceiverParameter()
|
||||
val extensionReceiver = callable.getExtensionReceiverParameter()
|
||||
|
||||
appendReceiverType(dispatchReceiver)
|
||||
|
||||
val addParentheses = dispatchReceiver != null && extensionReceiver != null
|
||||
if (addParentheses) append("(")
|
||||
appendReceiverType(extensionReceiver)
|
||||
if (addParentheses) append(")")
|
||||
|
||||
append(renderer.renderName(callable.getName()))
|
||||
}
|
||||
|
||||
// TODO: include visibility, return type
|
||||
fun renderProperty(descriptor: PropertyDescriptor): String {
|
||||
fun StringBuilder.appendReceiverType(receiver: ReceiverParameterDescriptor?) {
|
||||
if (receiver != null) {
|
||||
append(renderer.renderType(receiver.getType()))
|
||||
append(".")
|
||||
}
|
||||
}
|
||||
|
||||
return StringBuilder {
|
||||
append(if (descriptor.isVar()) "var " else "val ")
|
||||
appendReceiversAndName(descriptor)
|
||||
}.toString()
|
||||
}
|
||||
|
||||
val dispatchReceiver = descriptor.getDispatchReceiverParameter()
|
||||
val extensionReceiver = descriptor.getExtensionReceiverParameter()
|
||||
fun renderFunction(descriptor: FunctionDescriptor): String {
|
||||
// TODO: add tests
|
||||
return StringBuilder {
|
||||
append("fun ")
|
||||
appendReceiversAndName(descriptor)
|
||||
|
||||
appendReceiverType(dispatchReceiver)
|
||||
descriptor.getValueParameters().joinTo(this, separator = ", ", prefix = "(", postfix = ")") {
|
||||
renderer.renderType(it.getType()) // TODO: vararg
|
||||
}
|
||||
|
||||
val addParentheses = dispatchReceiver != null && extensionReceiver != null
|
||||
if (addParentheses) append("(")
|
||||
appendReceiverType(extensionReceiver)
|
||||
if (addParentheses) append(")")
|
||||
|
||||
append(renderer.renderName(descriptor.getName()))
|
||||
append(": ")
|
||||
append(renderer.renderType(descriptor.getReturnType()!!))
|
||||
}.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,24 @@ package kotlin.reflect.jvm.internal
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.*
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
|
||||
object RuntimeTypeMapper {
|
||||
// TODO: this logic must be shared with JetTypeMapper
|
||||
@@ -62,6 +70,61 @@ object RuntimeTypeMapper {
|
||||
return classDescriptor.classId.desc
|
||||
}
|
||||
|
||||
fun mapSignature(function: FunctionDescriptor): String {
|
||||
if (function is DeserializedSimpleFunctionDescriptor) {
|
||||
val proto = function.getProto()
|
||||
if (!proto.hasExtension(JvmProtoBuf.methodSignature)) {
|
||||
throw KotlinReflectionInternalError("No metadata found for $function")
|
||||
}
|
||||
val signature = proto.getExtension(JvmProtoBuf.methodSignature)
|
||||
return SignatureDeserializer(function.getNameResolver()).methodSignatureString(signature)
|
||||
}
|
||||
else if (function is JavaMethodDescriptor) {
|
||||
val method = (function.getSource() as? JavaSourceElement)?.javaElement as? JavaMethod ?:
|
||||
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java method $function")
|
||||
|
||||
return StringBuilder {
|
||||
append(method.getName().asString())
|
||||
|
||||
append("(")
|
||||
for (parameter in method.getValueParameters()) {
|
||||
appendJavaType(parameter.getType())
|
||||
}
|
||||
append(")")
|
||||
|
||||
appendJavaType(method.getReturnType())
|
||||
}.toString()
|
||||
}
|
||||
else throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})")
|
||||
}
|
||||
|
||||
// TODO: verify edge cases when it's possible to reference generic functions
|
||||
private tailRecursive fun StringBuilder.appendJavaType(type: JavaType) {
|
||||
when (type) {
|
||||
is JavaPrimitiveType -> {
|
||||
append(type.getType()?.let { JvmPrimitiveType.get(it).getDesc() } ?: "V")
|
||||
}
|
||||
is JavaArrayType -> {
|
||||
append("[")
|
||||
appendJavaType(type.getComponentType())
|
||||
}
|
||||
is JavaWildcardType -> {
|
||||
val bound = type.getBound()
|
||||
if (bound != null && type.isExtends()) appendJavaType(bound)
|
||||
else append("Ljava/lang/Object;")
|
||||
}
|
||||
is JavaClassifierType -> {
|
||||
val classifier = type.getClassifier()
|
||||
when (classifier) {
|
||||
is ReflectJavaClass ->
|
||||
append(classifier.element.desc)
|
||||
is ReflectJavaTypeParameter ->
|
||||
appendJavaType(ReflectJavaType.create(classifier.typeVariable.getBounds().first()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId {
|
||||
if (klass.isArray()) {
|
||||
klass.getComponentType().primitiveType?.let {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
*/
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import kotlin.reflect.KTopLevelFunction
|
||||
|
||||
class KTopLevelFreeFunctionImpl : KFunctionImpl, KTopLevelFunction<Any?> {
|
||||
constructor(container: KPackageImpl, name: String, signature: String): super(container, name, signature)
|
||||
|
||||
constructor(container: KPackageImpl, descriptor: FunctionDescriptor): super(container, descriptor)
|
||||
}
|
||||
Reference in New Issue
Block a user