Support reflection for local delegated properties
#KT-15222 Fixed
This commit is contained in:
@@ -112,8 +112,12 @@ extend TypeParameter {
|
||||
extend Class {
|
||||
// If absent, assumed to be JvmAbi.DEFAULT_MODULE_NAME
|
||||
optional int32 class_module_name = 101 [(string_id_in_table) = true];
|
||||
|
||||
repeated Property class_local_variable = 102;
|
||||
}
|
||||
|
||||
extend Package {
|
||||
optional int32 package_module_name = 101 [(string_id_in_table) = true];
|
||||
|
||||
repeated Property package_local_variable = 102;
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ class JvmMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = JvmMetadataVersion(1, 1, 6)
|
||||
val INSTANCE = JvmMetadataVersion(1, 1, 7)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = JvmMetadataVersion()
|
||||
|
||||
+34
@@ -14,7 +14,9 @@ public final class JvmProtoBuf {
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.isRaw);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.typeParameterAnnotation);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classModuleName);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classLocalVariable);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageModuleName);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageLocalVariable);
|
||||
}
|
||||
public interface StringTableTypesOrBuilder extends
|
||||
// @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.jvm.StringTableTypes)
|
||||
@@ -3901,6 +3903,22 @@ public final class JvmProtoBuf {
|
||||
101,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32,
|
||||
java.lang.Integer.class);
|
||||
public static final int CLASS_LOCAL_VARIABLE_FIELD_NUMBER = 102;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Class { ... }</code>
|
||||
*/
|
||||
public static final
|
||||
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Class,
|
||||
java.util.List<org.jetbrains.kotlin.serialization.ProtoBuf.Property>> classLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessageLite
|
||||
.newRepeatedGeneratedExtension(
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Class.getDefaultInstance(),
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.getDefaultInstance(),
|
||||
null,
|
||||
102,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.MESSAGE,
|
||||
false,
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.class);
|
||||
public static final int PACKAGE_MODULE_NAME_FIELD_NUMBER = 101;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
|
||||
@@ -3917,6 +3935,22 @@ public final class JvmProtoBuf {
|
||||
101,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32,
|
||||
java.lang.Integer.class);
|
||||
public static final int PACKAGE_LOCAL_VARIABLE_FIELD_NUMBER = 102;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
|
||||
*/
|
||||
public static final
|
||||
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Package,
|
||||
java.util.List<org.jetbrains.kotlin.serialization.ProtoBuf.Property>> packageLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessageLite
|
||||
.newRepeatedGeneratedExtension(
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Package.getDefaultInstance(),
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.getDefaultInstance(),
|
||||
null,
|
||||
102,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.MESSAGE,
|
||||
false,
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.class);
|
||||
|
||||
static {
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.types.TypeSubstitution;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface CallableMemberDescriptor extends CallableDescriptor, MemberDescriptor {
|
||||
@NotNull
|
||||
@@ -70,6 +71,9 @@ public interface CallableMemberDescriptor extends CallableDescriptor, MemberDesc
|
||||
@NotNull
|
||||
CopyBuilder<D> setKind(@NotNull Kind kind);
|
||||
|
||||
@NotNull
|
||||
CopyBuilder<D> setTypeParameters(@NotNull List<TypeParameterDescriptor> parameters);
|
||||
|
||||
@NotNull
|
||||
CopyBuilder<D> setDispatchReceiverParameter(@Nullable ReceiverParameterDescriptor dispatchReceiverParameter);
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ public interface FunctionDescriptor extends CallableMemberDescriptor {
|
||||
CopyBuilder<D> setValueParameters(@NotNull List<ValueParameterDescriptor> parameters);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
CopyBuilder<D> setTypeParameters(@NotNull List<TypeParameterDescriptor> parameters);
|
||||
|
||||
@NotNull
|
||||
|
||||
+14
-10
@@ -237,24 +237,20 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
|
||||
return newCopyBuilder()
|
||||
.setSubstitution(originalSubstitutor.getSubstitution())
|
||||
.setOwner(getContainingDeclaration())
|
||||
.setModality(modality)
|
||||
.setVisibility(visibility)
|
||||
.setOriginal(getOriginal())
|
||||
.setCopyOverrides(true)
|
||||
.setKind(getKind())
|
||||
.build();
|
||||
}
|
||||
|
||||
public class CopyConfiguration implements PropertyDescriptor.CopyBuilder<PropertyDescriptor> {
|
||||
private DeclarationDescriptor owner;
|
||||
private Modality modality;
|
||||
private Visibility visibility;
|
||||
private DeclarationDescriptor owner = getContainingDeclaration();
|
||||
private Modality modality = getModality();
|
||||
private Visibility visibility = getVisibility();
|
||||
private PropertyDescriptor original = null;
|
||||
private Kind kind;
|
||||
private Kind kind = getKind();
|
||||
private TypeSubstitution substitution = TypeSubstitution.EMPTY;
|
||||
private boolean copyOverrides = true;
|
||||
private ReceiverParameterDescriptor dispatchReceiverParameter = PropertyDescriptorImpl.this.dispatchReceiverParameter;
|
||||
private List<TypeParameterDescriptor> newTypeParameters = null;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -290,6 +286,13 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CopyBuilder<PropertyDescriptor> setTypeParameters(@NotNull List<TypeParameterDescriptor> typeParameters) {
|
||||
this.newTypeParameters = typeParameters;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CopyConfiguration setDispatchReceiverParameter(@Nullable ReceiverParameterDescriptor dispatchReceiverParameter) {
|
||||
@@ -330,7 +333,8 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
copyConfiguration.owner, copyConfiguration.modality, copyConfiguration.visibility,
|
||||
copyConfiguration.original, copyConfiguration.kind);
|
||||
|
||||
List<TypeParameterDescriptor> originalTypeParameters = getTypeParameters();
|
||||
List<TypeParameterDescriptor> originalTypeParameters =
|
||||
copyConfiguration.newTypeParameters == null ? getTypeParameters() : copyConfiguration.newTypeParameters;
|
||||
List<TypeParameterDescriptor> substitutedTypeParameters = new ArrayList<TypeParameterDescriptor>(originalTypeParameters.size());
|
||||
TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(
|
||||
originalTypeParameters, copyConfiguration.substitution, substitutedDescriptor, substitutedTypeParameters
|
||||
|
||||
@@ -36,6 +36,10 @@ internal object EmptyContainerForLocal : KDeclarationContainerImpl() {
|
||||
|
||||
override fun getFunctions(name: Name): Collection<FunctionDescriptor> = fail()
|
||||
|
||||
private fun fail(): Nothing = throw KotlinReflectionInternalError("Introspecting local functions, lambdas and anonymous functions " +
|
||||
"is not yet fully supported in Kotlin reflection")
|
||||
}
|
||||
override fun getLocalProperty(index: Int): PropertyDescriptor? = null
|
||||
|
||||
private fun fail(): Nothing = throw KotlinReflectionInternalError(
|
||||
"Introspecting local functions, lambdas, anonymous functions and local variables " +
|
||||
"is not yet fully supported in Kotlin reflection"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -268,6 +268,11 @@ internal abstract class FunctionCaller<out M : Member?>(
|
||||
}
|
||||
}
|
||||
|
||||
object ThrowingCaller : FunctionCaller<Nothing?>(null, Void.TYPE, null, emptyArray()) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
throw UnsupportedOperationException("call/callBy are not supported for this declaration.")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// TODO lazily allocate array at bound callers?
|
||||
|
||||
@@ -30,9 +30,13 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.utils.compactIfPossible
|
||||
import kotlin.jvm.internal.TypeIntrinsics
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.deserializeToDescriptor
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.INHERITED
|
||||
|
||||
@@ -195,6 +199,14 @@ internal class KClassImpl<T : Any>(override val jClass: Class<T>) : KDeclaration
|
||||
memberScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION) +
|
||||
staticScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION)
|
||||
|
||||
override fun getLocalProperty(index: Int): PropertyDescriptor? {
|
||||
return (descriptor as? DeserializedClassDescriptor)?.let { descriptor ->
|
||||
val proto = descriptor.classProto.getExtension(JvmProtoBuf.classLocalVariable, index)
|
||||
val nameResolver = descriptor.c.nameResolver
|
||||
deserializeToDescriptor(jClass, proto, nameResolver, descriptor.c.typeTable, MemberDeserializer::loadProperty)
|
||||
}
|
||||
}
|
||||
|
||||
override val simpleName: String? get() = data().simpleName
|
||||
|
||||
override val qualifiedName: String? get() = data().qualifiedName
|
||||
|
||||
@@ -45,6 +45,8 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
|
||||
abstract fun getFunctions(name: Name): Collection<FunctionDescriptor>
|
||||
|
||||
abstract fun getLocalProperty(index: Int): PropertyDescriptor?
|
||||
|
||||
protected fun getMembers(scope: MemberScope, belonginess: MemberBelonginess): Collection<KCallableImpl<*>> {
|
||||
val visitor = object : DeclarationDescriptorVisitorEmptyBodies<KCallableImpl<*>, Unit>() {
|
||||
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit): KCallableImpl<*> =
|
||||
@@ -95,9 +97,15 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
}
|
||||
|
||||
fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
|
||||
val match = LOCAL_PROPERTY_SIGNATURE.matchEntire(signature)
|
||||
if (match != null) {
|
||||
val (number) = match.destructured
|
||||
return getLocalProperty(number.toInt())
|
||||
?: throw KotlinReflectionInternalError("Local property #$number not found in $jClass")
|
||||
}
|
||||
|
||||
val properties = getProperties(Name.identifier(name))
|
||||
.filter { descriptor ->
|
||||
descriptor is PropertyDescriptor &&
|
||||
RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature
|
||||
}
|
||||
|
||||
@@ -279,5 +287,7 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker")
|
||||
|
||||
internal val LOCAL_PROPERTY_SIGNATURE = "<v#(\\d+)>".toRegex()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,14 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.PackageData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.jvm.deserializeToDescriptor
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED
|
||||
|
||||
internal class KPackageImpl(
|
||||
@@ -33,7 +39,7 @@ internal class KPackageImpl(
|
||||
@Suppress("unused") val usageModuleName: String? = null // may be useful for debug
|
||||
) : KDeclarationContainerImpl() {
|
||||
private inner class Data : KDeclarationContainerImpl.Data() {
|
||||
val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft {
|
||||
private val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft {
|
||||
// TODO: do not read ReflectKotlinClass multiple times
|
||||
ReflectKotlinClass.create(jClass)
|
||||
}
|
||||
@@ -57,6 +63,17 @@ internal class KPackageImpl(
|
||||
}
|
||||
}
|
||||
|
||||
val metadata: PackageData? by ReflectProperties.lazy {
|
||||
kotlinClass?.classHeader?.let { header ->
|
||||
val data = header.data
|
||||
val strings = header.strings
|
||||
if (data != null && strings != null) {
|
||||
JvmProtoBufUtil.readPackageDataFrom(data, strings)
|
||||
}
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
val members: Collection<KCallableImpl<*>> by ReflectProperties.lazySoft {
|
||||
getMembers(scope, DECLARED).filter { member ->
|
||||
val callableDescriptor = member.descriptor as DeserializedCallableMemberDescriptor
|
||||
@@ -84,6 +101,13 @@ internal class KPackageImpl(
|
||||
override fun getFunctions(name: Name): Collection<FunctionDescriptor> =
|
||||
scope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION)
|
||||
|
||||
override fun getLocalProperty(index: Int): PropertyDescriptor? {
|
||||
return data().metadata?.let { (nameResolver, packageProto) ->
|
||||
val proto = packageProto.getExtension(JvmProtoBuf.packageLocalVariable, index)
|
||||
deserializeToDescriptor(jClass, proto, nameResolver, TypeTable(packageProto.typeTable), MemberDeserializer::loadProperty)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KPackageImpl && jClass == other.jClass
|
||||
|
||||
|
||||
@@ -178,12 +178,14 @@ internal abstract class KPropertyImpl<out R> private constructor(
|
||||
|
||||
|
||||
private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Boolean): FunctionCaller<*> {
|
||||
if (KDeclarationContainerImpl.LOCAL_PROPERTY_SIGNATURE.matches(property.signature)) {
|
||||
return FunctionCaller.ThrowingCaller
|
||||
}
|
||||
|
||||
fun isInsideClassCompanionObject(): Boolean {
|
||||
val possibleCompanionObject = property.descriptor.containingDeclaration
|
||||
if (DescriptorUtils.isCompanionObject(possibleCompanionObject) && !DescriptorUtils.isInterface(possibleCompanionObject.containingDeclaration)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return DescriptorUtils.isCompanionObject(possibleCompanionObject) &&
|
||||
!DescriptorUtils.isInterface(possibleCompanionObject.containingDeclaration)
|
||||
}
|
||||
|
||||
fun isJvmStaticProperty() =
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
|
||||
package kotlin.reflect.jvm
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfoTable
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
@@ -44,12 +47,32 @@ fun <R> Function<R>.reflect(): KFunction<R>? {
|
||||
val stringTableTypes = JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
||||
val nameResolver = JvmNameResolver(stringTableTypes, annotation.d2)
|
||||
val proto = ProtoBuf.Function.parseFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
||||
val moduleData = javaClass.getOrCreateModule()
|
||||
val context = DeserializationContext(
|
||||
moduleData.deserialization, nameResolver, moduleData.module, TypeTable(proto.typeTable), SinceKotlinInfoTable.EMPTY,
|
||||
containerSource = null, parentTypeDeserializer = null, typeParameters = proto.typeParameterList
|
||||
)
|
||||
val descriptor = MemberDeserializer(context).loadFunction(proto)
|
||||
|
||||
val descriptor = deserializeToDescriptor(javaClass, proto, nameResolver, TypeTable(proto.typeTable), MemberDeserializer::loadFunction)
|
||||
?: return null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return KFunctionImpl(EmptyContainerForLocal, descriptor) as KFunction<R>
|
||||
}
|
||||
|
||||
internal fun <M : MessageLite, D : CallableDescriptor> deserializeToDescriptor(
|
||||
moduleAnchor: Class<*>,
|
||||
proto: M,
|
||||
nameResolver: NameResolver,
|
||||
typeTable: TypeTable,
|
||||
createDescriptor: MemberDeserializer.(M) -> D
|
||||
): D? {
|
||||
val moduleData = moduleAnchor.getOrCreateModule()
|
||||
|
||||
val typeParameters = when (proto) {
|
||||
is ProtoBuf.Function -> proto.typeParameterList
|
||||
is ProtoBuf.Property -> proto.typeParameterList
|
||||
else -> error("Unsupported message: $proto")
|
||||
}
|
||||
|
||||
val context = DeserializationContext(
|
||||
moduleData.deserialization, nameResolver, moduleData.module, typeTable, SinceKotlinInfoTable.EMPTY,
|
||||
containerSource = null, parentTypeDeserializer = null, typeParameters = typeParameters
|
||||
)
|
||||
return MemberDeserializer(context).createDescriptor(proto)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user