Remove KForeignMemberProperty and KClassOrigin, use KMemberPropertyImpl instead
This commit is contained in:
@@ -9,8 +9,8 @@ fun box(): String {
|
||||
val s = J::s
|
||||
|
||||
// Check that correct reflection objects are created
|
||||
assert(i.javaClass.getSimpleName() == "KForeignMemberProperty", "Fail i class")
|
||||
assert(s.javaClass.getSimpleName() == "KMutableForeignMemberProperty", "Fail s class")
|
||||
assert(i.javaClass.getSimpleName() == "KMemberPropertyImpl", "Fail i class")
|
||||
assert(s.javaClass.getSimpleName() == "KMutableMemberPropertyImpl", "Fail s class")
|
||||
|
||||
// Check that no Method objects are created for such properties
|
||||
assert(i.javaGetter == null, "Fail i getter")
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package test;
|
||||
|
||||
public class equalsHashCodeToString {
|
||||
public final boolean b;
|
||||
public char c;
|
||||
|
||||
public equalsHashCodeToString() {
|
||||
this.b = false;
|
||||
this.c = '0';
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
|
||||
import kotlin.test.*
|
||||
import test.equalsHashCodeToString as J
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("val test.equalsHashCodeToString.b", (J::b).toString())
|
||||
assertEquals("var test.equalsHashCodeToString.c", (J::c).toString())
|
||||
|
||||
assertTrue(J::b == J::b)
|
||||
assertFalse(J::c == J::b)
|
||||
|
||||
assertTrue(J::b.hashCode() == J::b.hashCode())
|
||||
assertFalse(J::b.hashCode() == J::c.hashCode())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+16
@@ -332,6 +332,7 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({
|
||||
Reflection.Mapping.class,
|
||||
Reflection.Properties.class,
|
||||
})
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Reflection extends AbstractBlackBoxCodegenTest {
|
||||
@@ -359,6 +360,21 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod
|
||||
doTestAgainstJava(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxAgainstJava/reflection/properties")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Properties extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInProperties() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/reflection/properties"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("equalsHashCodeToString.kt")
|
||||
public void testEqualsHashCodeToString() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/reflection/properties/equalsHashCodeToString.kt");
|
||||
doTestAgainstJava(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxAgainstJava/sam")
|
||||
|
||||
@@ -24,44 +24,48 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
|
||||
abstract class DescriptorBasedProperty(computeDescriptor: () -> PropertyDescriptor) {
|
||||
protected abstract val container: KCallableContainerImpl
|
||||
|
||||
data class PropertyProtoData(
|
||||
protected abstract val name: String
|
||||
|
||||
private data class PropertyProtoData(
|
||||
val proto: ProtoBuf.Callable,
|
||||
val nameResolver: NameResolver,
|
||||
val signature: JvmProtoBuf.JvmPropertySignature
|
||||
)
|
||||
|
||||
protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft { computeDescriptor() }
|
||||
protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft(computeDescriptor)
|
||||
|
||||
protected val protoData: PropertyProtoData by ReflectProperties.lazyWeak {
|
||||
// null if this is a property declared in a foreign (Java) class
|
||||
private val protoData: PropertyProtoData? by ReflectProperties.lazyWeak @p {(): PropertyProtoData? ->
|
||||
val property = DescriptorUtils.unwrapFakeOverride(descriptor) as? DeserializedPropertyDescriptor
|
||||
?: throw KotlinReflectionInternalError("Member property resolved incorrectly: $descriptor")
|
||||
val proto = property.proto
|
||||
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
|
||||
throw KotlinReflectionInternalError("Member property lacks JVM signature: $descriptor")
|
||||
if (property != null) {
|
||||
val proto = property.proto
|
||||
if (proto.hasExtension(JvmProtoBuf.propertySignature)) {
|
||||
return@p PropertyProtoData(proto, property.nameResolver, proto.getExtension(JvmProtoBuf.propertySignature))
|
||||
}
|
||||
}
|
||||
PropertyProtoData(proto, property.nameResolver, proto.getExtension(JvmProtoBuf.propertySignature))
|
||||
null
|
||||
}
|
||||
|
||||
val field: Field? by ReflectProperties.lazySoft {
|
||||
open val field: Field? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (!proto.signature.hasField()) null
|
||||
if (proto == null) container.jClass.getField(name)
|
||||
else if (!proto.signature.hasField()) null
|
||||
else container.findFieldBySignature(proto.proto, proto.signature.getField(), proto.nameResolver)
|
||||
}
|
||||
|
||||
open val getter: Method? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (!proto.signature.hasGetter()) null
|
||||
if (proto == null || !proto.signature.hasGetter()) null
|
||||
else container.findMethodBySignature(proto.signature.getGetter(), proto.nameResolver)
|
||||
}
|
||||
|
||||
open val setter: Method? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (!proto.signature.hasSetter()) null
|
||||
if (proto == null || !proto.signature.hasSetter()) null
|
||||
else container.findMethodBySignature(proto.signature.getSetter(), proto.nameResolver)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,26 +16,18 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
import kotlin.jvm.internal.KotlinClass
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMemberProperty
|
||||
import kotlin.reflect.KMutableMemberProperty
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
|
||||
enum class KClassOrigin {
|
||||
BUILT_IN
|
||||
KOTLIN
|
||||
FOREIGN
|
||||
}
|
||||
|
||||
class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), KClass<T> {
|
||||
// Don't use kotlin.properties.Delegates here because it's a Kotlin class which will invoke KClassImpl() in <clinit>,
|
||||
// resulting in infinite recursion
|
||||
|
||||
val descriptor by ReflectProperties.lazySoft {(): ClassDescriptor ->
|
||||
val descriptor by ReflectProperties.lazySoft {
|
||||
val moduleData = jClass.getOrCreateModule()
|
||||
val classId = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass)
|
||||
|
||||
@@ -48,36 +40,12 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
|
||||
override val scope: JetScope get() = descriptor.getDefaultType().getMemberScope()
|
||||
|
||||
private val origin by ReflectProperties.lazy {(): KClassOrigin ->
|
||||
if (jClass.isAnnotationPresent(javaClass<KotlinClass>())) {
|
||||
KClassOrigin.KOTLIN
|
||||
}
|
||||
else {
|
||||
KClassOrigin.FOREIGN
|
||||
// TODO: built-in classes
|
||||
}
|
||||
}
|
||||
|
||||
fun memberProperty(name: String): KMemberProperty<T, *> {
|
||||
val computeDescriptor = findPropertyDescriptor(name)
|
||||
|
||||
if (origin === KClassOrigin.KOTLIN) {
|
||||
return KMemberPropertyImpl<T, Any>(this, computeDescriptor)
|
||||
}
|
||||
else {
|
||||
return KForeignMemberProperty<T, Any>(name, this)
|
||||
}
|
||||
return KMemberPropertyImpl<T, Any>(this, findPropertyDescriptor(name))
|
||||
}
|
||||
|
||||
fun mutableMemberProperty(name: String): KMutableMemberProperty<T, *> {
|
||||
val computeDescriptor = findPropertyDescriptor(name)
|
||||
|
||||
if (origin === KClassOrigin.KOTLIN) {
|
||||
return KMutableMemberPropertyImpl<T, Any>(this, computeDescriptor)
|
||||
}
|
||||
else {
|
||||
return KMutableForeignMemberProperty<T, Any>(name, this)
|
||||
}
|
||||
return KMutableMemberPropertyImpl<T, Any>(this, findPropertyDescriptor(name))
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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 java.lang.reflect.*
|
||||
import kotlin.reflect.*
|
||||
|
||||
open class KForeignMemberProperty<T : Any, out R>(
|
||||
override val name: String,
|
||||
protected val owner: KClassImpl<T>
|
||||
) : KMemberProperty<T, R>, KPropertyImpl<R> {
|
||||
override val field: Field = try {
|
||||
owner.jClass.getField(name)
|
||||
}
|
||||
catch (e: NoSuchFieldException) {
|
||||
throw NoSuchPropertyException(e)
|
||||
}
|
||||
|
||||
override val getter: Method? get() = null
|
||||
|
||||
override fun get(receiver: T): R {
|
||||
try {
|
||||
return field.get(receiver) as R
|
||||
}
|
||||
catch (e: IllegalAccessException) {
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KForeignMemberProperty<*, *> && name == other.name && owner == other.owner
|
||||
|
||||
override fun hashCode(): Int =
|
||||
name.hashCode() * 31 + owner.hashCode()
|
||||
|
||||
// TODO: include visibility, return type
|
||||
override fun toString(): String =
|
||||
"val ${owner.jClass.getName()}.$name"
|
||||
}
|
||||
|
||||
class KMutableForeignMemberProperty<T : Any, R>(
|
||||
name: String,
|
||||
owner: KClassImpl<T>
|
||||
) : KMutableMemberProperty<T, R>, KMutablePropertyImpl<R>, KForeignMemberProperty<T, R>(name, owner) {
|
||||
override val setter: Method? get() = null
|
||||
|
||||
override fun set(receiver: T, value: R) {
|
||||
try {
|
||||
field.set(receiver, value)
|
||||
}
|
||||
catch (e: IllegalAccessException) {
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"var ${owner.jClass.getName()}.$name"
|
||||
}
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
package kotlin.reflect.jvm
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.internal.*
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.jvm.internal.KMemberPropertyImpl
|
||||
import kotlin.reflect.jvm.internal.KMutableMemberPropertyImpl
|
||||
|
||||
public var <R> KProperty<R>.accessible: Boolean
|
||||
get() {
|
||||
@@ -29,7 +30,6 @@ public var <R> KProperty<R>.accessible: Boolean
|
||||
is KMemberPropertyImpl<*, R> ->
|
||||
field?.isAccessible() ?: true &&
|
||||
getter?.isAccessible() ?: true
|
||||
is KForeignMemberProperty<*, R> -> field.isAccessible()
|
||||
else -> {
|
||||
// Non-member properties always have public visibility on JVM, thus accessible has no effect on them
|
||||
true
|
||||
@@ -47,8 +47,5 @@ public var <R> KProperty<R>.accessible: Boolean
|
||||
field?.setAccessible(value)
|
||||
getter?.setAccessible(value)
|
||||
}
|
||||
is KForeignMemberProperty<*, R> -> {
|
||||
field.setAccessible(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user