Fix KProperty.javaField for fake overrides
#KT-8131 Fixed
This commit is contained in:
Vendored
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// KT-8131 Cannot find backing field in ancestor class via reflection
|
||||||
|
|
||||||
|
import kotlin.reflect.*
|
||||||
|
import kotlin.reflect.jvm.*
|
||||||
|
|
||||||
|
open class TestBase {
|
||||||
|
var id = 0L
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestChild : TestBase()
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val property = TestChild::class.memberProperties.first { it.name == "id" } as KMutableProperty<*>
|
||||||
|
if (property.javaField == null)
|
||||||
|
return "Fail: no field"
|
||||||
|
if (property.javaGetter == null)
|
||||||
|
return "Fail: no getter"
|
||||||
|
if (property.javaSetter == null)
|
||||||
|
return "Fail: no setter"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
import kotlin.reflect.*
|
||||||
|
import kotlin.reflect.jvm.*
|
||||||
|
|
||||||
|
open class TestBase {
|
||||||
|
fun id() = 0L
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestChild : TestBase()
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (TestChild::class.memberFunctions.first { it.name == "id" }.javaMethod == null)
|
||||||
|
return "No method for TestChild.id()"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+21
@@ -3987,6 +3987,27 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
doTestWithStdlib(fileName);
|
doTestWithStdlib(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/fakeOverrides")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FakeOverrides extends AbstractBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInFakeOverrides() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/mapping/fakeOverrides"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaFieldGetterSetter.kt")
|
||||||
|
public void testJavaFieldGetterSetter() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/fakeOverrides/javaFieldGetterSetter.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaMethod.kt")
|
||||||
|
public void testJavaMethod() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/fakeOverrides/javaMethod.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/jvmStatic")
|
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/jvmStatic")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package kotlin.reflect.jvm.internal
|
package kotlin.reflect.jvm.internal
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||||
@@ -50,17 +51,29 @@ internal abstract class DescriptorBasedProperty<out R> protected constructor(
|
|||||||
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
|
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
|
||||||
when (jvmSignature) {
|
when (jvmSignature) {
|
||||||
is KotlinProperty -> {
|
is KotlinProperty -> {
|
||||||
|
val descriptor = jvmSignature.descriptor
|
||||||
JvmProtoBufUtil.getJvmFieldSignature(jvmSignature.proto, jvmSignature.nameResolver, jvmSignature.typeTable)?.let {
|
JvmProtoBufUtil.getJvmFieldSignature(jvmSignature.proto, jvmSignature.nameResolver, jvmSignature.typeTable)?.let {
|
||||||
container.findFieldBySignature(
|
val owner = if (JvmAbi.isCompanionObjectWithBackingFieldsInOuter(descriptor.containingDeclaration)) {
|
||||||
it.name, JvmAbi.isCompanionObjectWithBackingFieldsInOuter(descriptor.containingDeclaration)
|
container.jClass.enclosingClass
|
||||||
)
|
}
|
||||||
|
else descriptor.containingDeclaration.let { containingDeclaration ->
|
||||||
|
if (containingDeclaration is ClassDescriptor) containingDeclaration.toJavaClass()
|
||||||
|
else container.jClass
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
owner?.getDeclaredField(it.name)
|
||||||
|
}
|
||||||
|
catch (e: NoSuchFieldException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is JavaField -> jvmSignature.field
|
is JavaField -> jvmSignature.field
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used in subclasses as an implementation of an irrelevant property from KPropertyImpl
|
@Suppress("unused") // Used in subclasses as an implementation of an irrelevant property from KPropertyImpl
|
||||||
val javaField: Field? get() = javaField_()
|
val javaField: Field? get() = javaField_()
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
|||||||
@@ -21,11 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
|||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.load.java.reflect.tryLoadClass
|
import org.jetbrains.kotlin.load.java.reflect.tryLoadClass
|
||||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaClass
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
|
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||||
@@ -122,22 +118,14 @@ internal class KClassImpl<T : Any>(override val jClass: Class<T>) : KDeclaration
|
|||||||
override val nestedClasses: Collection<KClass<*>>
|
override val nestedClasses: Collection<KClass<*>>
|
||||||
get() = descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors().filterNot(DescriptorUtils::isEnumEntry).mapNotNull {
|
get() = descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors().filterNot(DescriptorUtils::isEnumEntry).mapNotNull {
|
||||||
nestedClass ->
|
nestedClass ->
|
||||||
val source = (nestedClass as DeclarationDescriptorWithSource).source
|
(nestedClass as ClassDescriptor).toJavaClass() ?: run {
|
||||||
when (source) {
|
// If neither a Kotlin class nor a Java class, it must be a built-in
|
||||||
is KotlinJvmBinarySourceElement ->
|
val classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(nestedClass))
|
||||||
(source.binaryClass as ReflectKotlinClass).klass
|
?: throw KotlinReflectionInternalError("Class with no source must be a built-in: $nestedClass")
|
||||||
is JavaSourceElement ->
|
val packageName = classId.packageFqName.asString()
|
||||||
(source.javaElement as ReflectJavaClass).element
|
val className = classId.relativeClassName.asString().replace('.', '$')
|
||||||
SourceElement.NO_SOURCE -> {
|
// All pseudo-classes like String.Companion must be accessible from the current class loader
|
||||||
// If neither a Kotlin class nor a Java class, it must be a built-in
|
(this as Any).javaClass.safeClassLoader.tryLoadClass("$packageName.$className")
|
||||||
val classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(nestedClass))
|
|
||||||
?: throw KotlinReflectionInternalError("Class with no source must be a built-in: $nestedClass")
|
|
||||||
val packageName = classId.packageFqName.asString()
|
|
||||||
val className = classId.relativeClassName.asString().replace('.', '$')
|
|
||||||
// All pseudo-classes like String.Companion must be accessible from the current class loader
|
|
||||||
(this as Any).javaClass.safeClassLoader.tryLoadClass("$packageName.$className")
|
|
||||||
}
|
|
||||||
else -> throw KotlinReflectionInternalError("Unsupported class: $nestedClass (source = $source)")
|
|
||||||
}
|
}
|
||||||
}.map { KClassImpl(it) }
|
}.map { KClassImpl(it) }
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.load.kotlin.reflect.RuntimeModuleData
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import java.lang.reflect.Constructor
|
import java.lang.reflect.Constructor
|
||||||
import java.lang.reflect.Field
|
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import kotlin.jvm.internal.ClassBasedDeclarationContainer
|
import kotlin.jvm.internal.ClassBasedDeclarationContainer
|
||||||
import kotlin.reflect.KCallable
|
import kotlin.reflect.KCallable
|
||||||
@@ -235,18 +234,6 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check resulting field's type
|
|
||||||
fun findFieldBySignature(name: String, isCompanionOfClass: Boolean): Field? {
|
|
||||||
val owner = if (isCompanionOfClass) jClass.enclosingClass else jClass
|
|
||||||
|
|
||||||
return try {
|
|
||||||
owner.getDeclaredField(name)
|
|
||||||
}
|
|
||||||
catch (e: NoSuchFieldException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker")
|
private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ package kotlin.reflect.jvm.internal
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
@@ -109,9 +107,7 @@ private fun KPropertyImpl.Accessor<*>.computeCallerForAccessor(isGetter: Boolean
|
|||||||
|
|
||||||
fun computeFieldCaller(field: Field): FunctionCaller<Field> = when {
|
fun computeFieldCaller(field: Field): FunctionCaller<Field> = when {
|
||||||
isInsideClassCompanionObject() -> {
|
isInsideClassCompanionObject() -> {
|
||||||
val containingDeclaration = descriptor.containingDeclaration as ClassDescriptor
|
val klass = (descriptor.containingDeclaration as ClassDescriptor).toJavaClass()!!
|
||||||
val sourceElement = containingDeclaration.source as KotlinJvmBinarySourceElement
|
|
||||||
val klass = (sourceElement.binaryClass as ReflectKotlinClass).klass
|
|
||||||
if (isGetter) FunctionCaller.ClassCompanionFieldGetter(field, klass)
|
if (isGetter) FunctionCaller.ClassCompanionFieldGetter(field, klass)
|
||||||
else FunctionCaller.ClassCompanionFieldSetter(field, klass)
|
else FunctionCaller.ClassCompanionFieldSetter(field, klass)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
|
|
||||||
package kotlin.reflect.jvm.internal
|
package kotlin.reflect.jvm.internal
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.load.java.components.RuntimeSourceElementFactory
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaClass
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import kotlin.jvm.internal.FunctionReference
|
import kotlin.jvm.internal.FunctionReference
|
||||||
import kotlin.jvm.internal.PropertyReference
|
import kotlin.jvm.internal.PropertyReference
|
||||||
@@ -23,6 +28,22 @@ import kotlin.reflect.IllegalCallableAccessException
|
|||||||
|
|
||||||
internal val JVM_STATIC = FqName("kotlin.jvm.JvmStatic")
|
internal val JVM_STATIC = FqName("kotlin.jvm.JvmStatic")
|
||||||
|
|
||||||
|
internal fun ClassDescriptor.toJavaClass(): Class<*>? {
|
||||||
|
val source = source
|
||||||
|
return when (source) {
|
||||||
|
is KotlinJvmBinarySourceElement -> {
|
||||||
|
(source.binaryClass as ReflectKotlinClass).klass
|
||||||
|
}
|
||||||
|
is RuntimeSourceElementFactory.RuntimeSourceElement -> {
|
||||||
|
(source.javaElement as ReflectJavaClass).element
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// This is a built-in class
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: wrap other exceptions
|
// TODO: wrap other exceptions
|
||||||
internal inline fun <R> reflectionCall(block: () -> R): R =
|
internal inline fun <R> reflectionCall(block: () -> R): R =
|
||||||
try {
|
try {
|
||||||
@@ -34,7 +55,7 @@ internal inline fun <R> reflectionCall(block: () -> R): R =
|
|||||||
|
|
||||||
internal fun Any?.asKFunctionImpl(): KFunctionImpl? =
|
internal fun Any?.asKFunctionImpl(): KFunctionImpl? =
|
||||||
this as? KFunctionImpl ?:
|
this as? KFunctionImpl ?:
|
||||||
(this as? FunctionReference)?.compute() as? KFunctionImpl //
|
(this as? FunctionReference)?.compute() as? KFunctionImpl
|
||||||
|
|
||||||
internal fun Any?.asKPropertyImpl(): KPropertyImpl<*>? =
|
internal fun Any?.asKPropertyImpl(): KPropertyImpl<*>? =
|
||||||
this as? KPropertyImpl<*> ?:
|
this as? KPropertyImpl<*> ?:
|
||||||
|
|||||||
Reference in New Issue
Block a user