Generate separate anonymous class for each property reference
Each property reference obtained by the '::' operator now causes back-end to generate an anonymous subclass of the corresponding KProperty class, with the customized behavior. This fixes a number of issues: - get/set/name of property references now works without kotlin-reflect.jar in the classpath - get/set/name methods are now overridden with statically-generated property access instead of the default KPropertyImpl's behavior of using Java reflection, which should be a lot faster - references to private/protected properties now work without the need to set 'accessible' flag, because corresponding synthetic accessors are generated at compile-time near the target property #KT-6870 Fixed #KT-6873 Fixed #KT-7033 Fixed
This commit is contained in:
@@ -30,17 +30,17 @@ import java.lang.reflect.Method
|
||||
abstract class DescriptorBasedProperty protected constructor(
|
||||
container: KCallableContainerImpl,
|
||||
name: String,
|
||||
receiverParameterDesc: String?,
|
||||
signature: String,
|
||||
descriptorInitialValue: PropertyDescriptor?
|
||||
) {
|
||||
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : this(
|
||||
container, name, receiverParameterClass?.desc, null
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : this(
|
||||
container, name, signature, null
|
||||
)
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this(
|
||||
container,
|
||||
descriptor.getName().asString(),
|
||||
descriptor.getExtensionReceiverParameter()?.getType()?.let { type -> RuntimeTypeMapper.mapTypeToJvmDesc(type) },
|
||||
RuntimeTypeMapper.mapPropertySignature(descriptor),
|
||||
descriptor
|
||||
)
|
||||
|
||||
@@ -51,7 +51,7 @@ abstract class DescriptorBasedProperty protected constructor(
|
||||
)
|
||||
|
||||
protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft<PropertyDescriptor>(descriptorInitialValue) {
|
||||
container.findPropertyDescriptor(name, receiverParameterDesc)
|
||||
container.findPropertyDescriptor(name, signature)
|
||||
}
|
||||
|
||||
// null if this is a property declared in a foreign (Java) class
|
||||
|
||||
@@ -43,20 +43,16 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
|
||||
abstract val scope: JetScope
|
||||
|
||||
fun findPropertyDescriptor(name: String, receiverDesc: String? = null): PropertyDescriptor {
|
||||
fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
|
||||
val properties = scope
|
||||
.getProperties(Name.guess(name))
|
||||
.filter { descriptor ->
|
||||
descriptor is PropertyDescriptor &&
|
||||
descriptor.getName().asString() == name &&
|
||||
with(descriptor.getExtensionReceiverParameter()) {
|
||||
(this == null && receiverDesc == null) ||
|
||||
(this != null && RuntimeTypeMapper.mapTypeToJvmDesc(getType()) == receiverDesc)
|
||||
}
|
||||
RuntimeTypeMapper.mapPropertySignature(descriptor) == signature
|
||||
}
|
||||
|
||||
if (properties.size() != 1) {
|
||||
val debugText = if (receiverDesc == null) name else "'$receiverDesc.$name'"
|
||||
val debugText = "'$name' (JVM signature: $signature)"
|
||||
throw KotlinReflectionInternalError(
|
||||
if (properties.isEmpty()) "Property $debugText not resolved in $this"
|
||||
else "${properties.size()} properties $debugText resolved in $this: $properties"
|
||||
|
||||
@@ -104,12 +104,6 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
.map(create)
|
||||
.toList()
|
||||
|
||||
fun memberProperty(name: String): KProperty1<T, *> =
|
||||
KProperty1Impl<T, Any>(this, name, null)
|
||||
|
||||
fun mutableMemberProperty(name: String): KMutableProperty1<T, *> =
|
||||
KMutableProperty1Impl<T, Any>(this, name, null)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KClassImpl<*> && jClass == other.jClass
|
||||
|
||||
|
||||
@@ -31,18 +31,6 @@ class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KP
|
||||
|
||||
override val scope: JetScope get() = descriptor.memberScope
|
||||
|
||||
fun topLevelVariable(name: String): KProperty0<*> =
|
||||
KProperty0Impl<Any?>(this, name)
|
||||
|
||||
fun mutableTopLevelVariable(name: String): KMutableProperty0<*> =
|
||||
KMutableProperty0Impl<Any?>(this, name)
|
||||
|
||||
fun <T> topLevelExtensionProperty(name: String, receiver: Class<T>): KProperty1<T, *> =
|
||||
KProperty1Impl<T, Any?>(this, name, receiver)
|
||||
|
||||
fun <T> mutableTopLevelExtensionProperty(name: String, receiver: Class<T>): KMutableProperty1<T, *> =
|
||||
KMutableProperty1Impl<T, Any?>(this, name, receiver)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KPackageImpl && jClass == other.jClass
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.jvm.internal.MutablePropertyReference0
|
||||
import kotlin.jvm.internal.PropertyReference0
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KPropertyImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String) : super(container, name, null)
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
@@ -39,8 +41,8 @@ open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KProp
|
||||
}
|
||||
}
|
||||
|
||||
class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String) : super(container, name)
|
||||
open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
override val setter: Method get() = super<KProperty0Impl>.setter!!
|
||||
|
||||
@@ -53,3 +55,33 @@ class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutab
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class KProperty0FromReferenceImpl(
|
||||
val reference: PropertyReference0
|
||||
) : KProperty0Impl<Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(): Any? = reference.get()
|
||||
}
|
||||
|
||||
|
||||
class KMutableProperty0FromReferenceImpl(
|
||||
val reference: MutablePropertyReference0
|
||||
) : KMutableProperty0Impl<Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(): Any? = reference.get()
|
||||
|
||||
override fun set(value: Any?) {
|
||||
reference.set(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.jvm.internal.MutablePropertyReference1
|
||||
import kotlin.jvm.internal.PropertyReference1
|
||||
|
||||
open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>, KPropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super(
|
||||
container, name, receiverParameterClass
|
||||
)
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
@@ -56,10 +56,8 @@ open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>,
|
||||
}
|
||||
|
||||
|
||||
class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super(
|
||||
container, name, receiverParameterClass
|
||||
)
|
||||
open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
@@ -86,3 +84,33 @@ class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class KProperty1FromReferenceImpl(
|
||||
val reference: PropertyReference1
|
||||
) : KProperty1Impl<Any?, Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(receiver: Any?): Any? = reference.get(receiver)
|
||||
}
|
||||
|
||||
|
||||
class KMutableProperty1FromReferenceImpl(
|
||||
val reference: MutablePropertyReference1
|
||||
) : KMutableProperty1Impl<Any?, Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(receiver: Any?): Any? = reference.get(receiver)
|
||||
|
||||
override fun set(receiver: Any?, value: Any?) {
|
||||
reference.set(receiver, value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import kotlin.reflect.KMutableProperty2
|
||||
import kotlin.reflect.KProperty2
|
||||
|
||||
open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D, E, R>, KPropertyImpl<R> {
|
||||
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
|
||||
constructor(container: KClassImpl<D>, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
@@ -47,7 +47,7 @@ open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D,
|
||||
|
||||
|
||||
class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty2<D, E, R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
|
||||
constructor(container: KClassImpl<D>, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal;
|
||||
|
||||
import kotlin.jvm.internal.FunctionReference;
|
||||
import kotlin.jvm.internal.ReflectionFactory;
|
||||
import kotlin.jvm.internal.*;
|
||||
import kotlin.reflect.*;
|
||||
|
||||
/**
|
||||
@@ -50,32 +49,34 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
||||
// Properties
|
||||
|
||||
@Override
|
||||
public KProperty1 memberProperty(String name, KClass owner) {
|
||||
return ((KClassImpl) owner).memberProperty(name);
|
||||
public KProperty0 property0(PropertyReference0 p) {
|
||||
return new KProperty0FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty1 mutableMemberProperty(String name, KClass owner) {
|
||||
return ((KClassImpl) owner).mutableMemberProperty(name);
|
||||
public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
|
||||
return new KMutableProperty0FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty0 topLevelVariable(String name, KPackage owner) {
|
||||
return ((KPackageImpl) owner).topLevelVariable(name);
|
||||
public KProperty1 property1(PropertyReference1 p) {
|
||||
return new KProperty1FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) {
|
||||
return ((KPackageImpl) owner).mutableTopLevelVariable(name);
|
||||
public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
|
||||
return new KMutableProperty1FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return ((KPackageImpl) owner).topLevelExtensionProperty(name, receiver);
|
||||
public KProperty2 property2(PropertyReference2 p) {
|
||||
// TODO: support member extension property references
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return ((KPackageImpl) owner).mutableTopLevelExtensionProperty(name, receiver);
|
||||
public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
|
||||
// TODO: support member extension property references
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,58 +18,25 @@ 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.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
|
||||
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.DeserializedPropertyDescriptor
|
||||
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
|
||||
fun mapTypeToJvmDesc(type: JetType): String {
|
||||
val classifier = type.getConstructor().getDeclarationDescriptor()
|
||||
if (classifier is TypeParameterDescriptor) {
|
||||
return mapTypeToJvmDesc(classifier.getUpperBounds().first())
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isArray(type)) {
|
||||
val elementType = KotlinBuiltIns.getInstance().getArrayElementType(type)
|
||||
// makeNullable is called here to map primitive types to the corresponding wrappers,
|
||||
// because the given type is Array<Something>, not SomethingArray
|
||||
return "[" + mapTypeToJvmDesc(TypeUtils.makeNullable(elementType))
|
||||
}
|
||||
|
||||
val classDescriptor = classifier as ClassDescriptor
|
||||
val fqName = DescriptorUtils.getFqName(classDescriptor)
|
||||
|
||||
KotlinBuiltIns.getPrimitiveTypeByFqName(fqName)?.let { primitiveType ->
|
||||
val jvmType = JvmPrimitiveType.get(primitiveType)
|
||||
return if (TypeUtils.isNullableType(type)) ClassId.topLevel(jvmType.getWrapperFqName()).desc else jvmType.getDesc()
|
||||
}
|
||||
|
||||
KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(fqName)?.let { primitiveType ->
|
||||
return "[" + JvmPrimitiveType.get(primitiveType).getDesc()
|
||||
}
|
||||
|
||||
JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName)?.let { return it.desc }
|
||||
|
||||
return classDescriptor.classId.desc
|
||||
}
|
||||
|
||||
fun mapSignature(function: FunctionDescriptor): String {
|
||||
if (function is DeserializedSimpleFunctionDescriptor) {
|
||||
val proto = function.getProto()
|
||||
@@ -125,6 +92,50 @@ object RuntimeTypeMapper {
|
||||
}
|
||||
}
|
||||
|
||||
fun mapPropertySignature(property: PropertyDescriptor): String {
|
||||
if (property is DeserializedPropertyDescriptor) {
|
||||
val proto = property.proto
|
||||
val nameResolver = property.nameResolver
|
||||
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
|
||||
throw KotlinReflectionInternalError("No metadata found for $property")
|
||||
}
|
||||
val signature = proto.getExtension(JvmProtoBuf.propertySignature)
|
||||
val deserializer = SignatureDeserializer(nameResolver)
|
||||
|
||||
if (signature.hasGetter()) {
|
||||
return deserializer.methodSignatureString(signature.getGetter())
|
||||
}
|
||||
|
||||
// In case the property doesn't have a getter, construct the signature of its imaginary default getter.
|
||||
// See PropertyReference#getSignature
|
||||
val field = signature.getField()
|
||||
|
||||
// TODO: some kind of test on the Java Bean convention?
|
||||
return getterName(nameResolver.getString(field.getName())) +
|
||||
"()" +
|
||||
deserializer.typeDescriptor(field.getType())
|
||||
}
|
||||
else if (property is JavaPropertyDescriptor) {
|
||||
val method = (property.getSource() as? JavaSourceElement)?.javaElement as? JavaField ?:
|
||||
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property")
|
||||
|
||||
return StringBuilder {
|
||||
append(getterName(method.getName().asString()))
|
||||
append("()")
|
||||
appendJavaType(method.getType())
|
||||
}.toString()
|
||||
}
|
||||
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
|
||||
}
|
||||
|
||||
private fun getterName(propertyName: String): String {
|
||||
return JvmAbi.GETTER_PREFIX + propertyName.capitalizeWithJavaBeanConvention()
|
||||
}
|
||||
|
||||
private fun String.capitalizeWithJavaBeanConvention(): String {
|
||||
return if (length() > 1 && this[1].isUpperCase()) this else capitalize()
|
||||
}
|
||||
|
||||
fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId {
|
||||
if (klass.isArray()) {
|
||||
klass.getComponentType().primitiveType?.let {
|
||||
@@ -147,7 +158,4 @@ object RuntimeTypeMapper {
|
||||
|
||||
private val Class<*>.primitiveType: PrimitiveType?
|
||||
get() = if (isPrimitive()) JvmPrimitiveType.get(getSimpleName()).getPrimitiveType() else null
|
||||
|
||||
private val ClassId.desc: String
|
||||
get() = "L${JvmClassName.byClassId(this).getInternalName()};"
|
||||
}
|
||||
|
||||
@@ -95,17 +95,10 @@ public val Field.kotlin: KProperty<*>?
|
||||
get() {
|
||||
if (isSynthetic()) return null
|
||||
|
||||
val clazz = getDeclaringClass()
|
||||
val name = getName()
|
||||
val modifiers = getModifiers()
|
||||
val static = Modifier.isStatic(modifiers)
|
||||
val final = Modifier.isFinal(modifiers)
|
||||
if (static) {
|
||||
val kPackage = clazz.kotlinPackage
|
||||
return if (final) Reflection.topLevelVariable(name, kPackage) else Reflection.mutableTopLevelVariable(name, kPackage)
|
||||
}
|
||||
else {
|
||||
val kClass = clazz.kotlin
|
||||
return if (final) Reflection.memberProperty(name, kClass) else Reflection.mutableMemberProperty(name, kClass)
|
||||
val clazz = getDeclaringClass().kotlin as KClassImpl
|
||||
|
||||
// TODO: optimize (search by name)
|
||||
return clazz.properties.firstOrNull { p: KProperty<*> ->
|
||||
(p as KPropertyImpl<*>).field == this
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user