diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt new file mode 100644 index 00000000000..3d101c0a46d --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt @@ -0,0 +1,27 @@ +import kotlin.reflect.* +import kotlin.test.assertEquals + +fun foo(bar: String): Int = bar.length() + +class A(val c: String) { + fun foz(baz: Int) {} +} + +fun Int.qux(zux: String) {} + +fun checkParameters(f: KFunction<*>, names: List) { + val params = f.parameters + assertEquals(names, params.map { it.name }) + assertEquals((0..params.size() - 1).toList(), params.mapIndexed { index, element -> index }) +} + +fun box(): String { + checkParameters(::box, listOf()) + checkParameters(::foo, listOf("bar")) + checkParameters(A::foz, listOf(null, "baz")) + checkParameters(Int::qux, listOf(null, "zux")) + + checkParameters(::A, listOf("c")) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/parameters/propertySetter.kt b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/propertySetter.kt new file mode 100644 index 00000000000..1c53cda44b8 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/propertySetter.kt @@ -0,0 +1,24 @@ +import kotlin.reflect.* +import kotlin.test.assertEquals + +var default: Int = 0 + +var defaultAnnotated: Int = 0 + public set + +var custom: Int = 0 + set(myName: Int) {} + +fun checkPropertySetterParam(property: KMutableProperty<*>, name: String?) { + val parameter = property.setter.parameters.single() + assertEquals(0, parameter.index) + assertEquals(name, parameter.name) +} + +fun box(): String { + checkPropertySetterParam(::default, null) + checkPropertySetterParam(::defaultAnnotated, null) + checkPropertySetterParam(::custom, "myName") + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 53462eac3a2..74ec03218ec 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3196,6 +3196,27 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Parameters extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInParameters() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("functionParameterNameAndIndex.kt") + public void testFunctionParameterNameAndIndex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("propertySetter.kt") + public void testPropertySetter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters/propertySetter.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/builtins/src/kotlin/reflect/KCallable.kt b/core/builtins/src/kotlin/reflect/KCallable.kt index b5e23954ab4..74a70de4641 100644 --- a/core/builtins/src/kotlin/reflect/KCallable.kt +++ b/core/builtins/src/kotlin/reflect/KCallable.kt @@ -31,4 +31,9 @@ public interface KCallable { * the setter, similarly, will have the name "". */ public val name: String + + /** + * Parameters required to make a call to this callable. + */ + public val parameters: List } diff --git a/core/builtins/src/kotlin/reflect/KParameter.kt b/core/builtins/src/kotlin/reflect/KParameter.kt new file mode 100644 index 00000000000..552bee4da25 --- /dev/null +++ b/core/builtins/src/kotlin/reflect/KParameter.kt @@ -0,0 +1,37 @@ +/* + * 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 + +/** + * Represents a parameter passed to a function or a property getter/setter, + * including `this` and extension receiver parameters. + */ +public interface KParameter { + /** + * 0-based index of this parameter in the parameter list of its containing callable. + */ + public val index: Int + + /** + * Name of this parameter as it was declared in the source code, + * or `null` if the parameter has no name or its name is not available at runtime. + * Examples of nameless parameters include `this` instance for member functions, + * extension receiver for extension functions or properties, parameters of Java methods + * compiled without the debug information, and others. + */ + public val name: String? +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt index 87ebafd26a1..9e4bf5b8b1e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt @@ -18,7 +18,6 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.load.java.structure.reflect.desc import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.deserialization.NameResolver @@ -27,12 +26,12 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf import java.lang.reflect.Field import java.lang.reflect.Method -abstract class DescriptorBasedProperty protected constructor( +abstract class DescriptorBasedProperty protected constructor( container: KCallableContainerImpl, name: String, signature: String, descriptorInitialValue: PropertyDescriptor? -) { +) : KCallableImpl { constructor(container: KCallableContainerImpl, name: String, signature: String) : this( container, name, signature, null ) @@ -50,7 +49,7 @@ abstract class DescriptorBasedProperty protected constructor( val signature: JvmProtoBuf.JvmPropertySignature ) - protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) { + override val descriptor: PropertyDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) { container.findPropertyDescriptor(name, signature) } @@ -88,7 +87,7 @@ abstract class DescriptorBasedProperty protected constructor( } override fun equals(other: Any?): Boolean = - other is DescriptorBasedProperty && descriptor == other.descriptor + other is DescriptorBasedProperty<*> && descriptor == other.descriptor override fun hashCode(): Int = descriptor.hashCode() diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index d98e816c3d7..e312e76a79d 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -16,6 +16,32 @@ package kotlin.reflect.jvm.internal +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import java.util.ArrayList import kotlin.reflect.KCallable +import kotlin.reflect.KParameter -interface KCallableImpl : KCallable +interface KCallableImpl : KCallable { + val descriptor: CallableMemberDescriptor + + override val parameters: List + get() { + val result = ArrayList() + var index = 0 + + if (descriptor.dispatchReceiverParameter != null) { + result.add(KParameterImpl(index++) { descriptor.dispatchReceiverParameter!! }) + } + + if (descriptor.extensionReceiverParameter != null) { + result.add(KParameterImpl(index++) { descriptor.extensionReceiverParameter!! }) + } + + for (i in descriptor.valueParameters.indices) { + result.add(KParameterImpl(index++) { descriptor.valueParameters[i] }) + } + + result.trimToSize() + return result + } +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt index 875804fcd52..18532e385cd 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.FunctionDescriptor @@ -25,7 +26,7 @@ open class KFunctionImpl protected constructor( name: String, signature: String, descriptorInitialValue: FunctionDescriptor? -) : KFunction, FunctionImpl(), +) : KFunction, KCallableImpl, FunctionImpl(), KLocalFunction, KMemberFunction, KTopLevelExtensionFunction, KTopLevelFunction { constructor(container: KCallableContainerImpl, name: String, signature: String) : this(container, name, signature, null) @@ -33,7 +34,7 @@ open class KFunctionImpl protected constructor( container, descriptor.getName().asString(), RuntimeTypeMapper.mapSignature(descriptor), descriptor ) - protected val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) { + override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) { container.findFunctionDescriptor(name, signature) } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt new file mode 100644 index 00000000000..517d387055c --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt @@ -0,0 +1,35 @@ +/* + * 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.ParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import kotlin.reflect.KParameter + +class KParameterImpl( + override val index: Int, + private val computeDescriptor: () -> ParameterDescriptor +) : KParameter { + private val descriptor: ParameterDescriptor by ReflectProperties.lazySoft(computeDescriptor) + + override val name: String? get() { + val valueParameter = descriptor as? ValueParameterDescriptor ?: return null + if (valueParameter.containingDeclaration.hasSynthesizedParameterNames()) return null + val name = valueParameter.name + return if (name.isSpecial) null else name.asString() + } +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt index 2877a9111ed..14fac033c94 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt @@ -23,7 +23,7 @@ import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KProperty0 -open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KPropertyImpl { +open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KPropertyImpl { constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) override val name: String get() = descriptor.getName().asString() @@ -42,7 +42,7 @@ open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KProp } } - class Getter(override val property: KProperty0Impl) : KPropertyImpl.Getter, KProperty0.Getter { + class Getter(override val property: KProperty0Impl) : KPropertyImpl.Getter(), KProperty0.Getter { override fun invoke(): R = property.get() } } @@ -63,7 +63,7 @@ open class KMutableProperty0Impl : KProperty0Impl, KMutableProperty0, K } } - class Setter(override val property: KMutableProperty0Impl) : KMutablePropertyImpl.Setter, KMutableProperty0.Setter { + class Setter(override val property: KMutableProperty0Impl) : KMutablePropertyImpl.Setter(), KMutableProperty0.Setter { override fun invoke(value: R): Unit = property.set(value) } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt index a4bde8fcfd9..23fa200ee0b 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt @@ -24,7 +24,7 @@ import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty1 -open class KProperty1Impl : DescriptorBasedProperty, KProperty1, KPropertyImpl { +open class KProperty1Impl : DescriptorBasedProperty, KProperty1, KPropertyImpl { constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) @@ -56,7 +56,7 @@ open class KProperty1Impl : DescriptorBasedProperty, KProperty1, } } - class Getter(override val property: KProperty1Impl) : KPropertyImpl.Getter, KProperty1.Getter { + class Getter(override val property: KProperty1Impl) : KPropertyImpl.Getter(), KProperty1.Getter { override fun invoke(receiver: T): R = property.get(receiver) } } @@ -92,7 +92,7 @@ open class KMutableProperty1Impl : KProperty1Impl, KMutableProperty1 } } - class Setter(override val property: KMutableProperty1Impl) : KMutablePropertyImpl.Setter, KMutableProperty1.Setter { + class Setter(override val property: KMutableProperty1Impl) : KMutablePropertyImpl.Setter(), KMutableProperty1.Setter { override fun invoke(receiver: T, value: R): Unit = property.set(receiver, value) } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt index 02de0088c96..aaa13a41154 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt @@ -23,7 +23,7 @@ import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KProperty2 -open class KProperty2Impl : DescriptorBasedProperty, KProperty2, KPropertyImpl { +open class KProperty2Impl : DescriptorBasedProperty, KProperty2, KPropertyImpl { constructor(container: KClassImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KClassImpl, descriptor: PropertyDescriptor) : super(container, descriptor) @@ -46,7 +46,7 @@ open class KProperty2Impl : DescriptorBasedProperty, KProperty2(override val property: KProperty2Impl) : KPropertyImpl.Getter, KProperty2.Getter { + class Getter(override val property: KProperty2Impl) : KPropertyImpl.Getter(), KProperty2.Getter { override fun invoke(receiver1: D, receiver2: E): R = property.get(receiver1, receiver2) } } @@ -70,7 +70,7 @@ class KMutableProperty2Impl : KProperty2Impl, KMutableProperty } } - class Setter(override val property: KMutableProperty2Impl) : KMutablePropertyImpl.Setter, KMutableProperty2.Setter { + class Setter(override val property: KMutableProperty2Impl) : KMutablePropertyImpl.Setter(), KMutableProperty2.Setter { override fun invoke(receiver1: D, receiver2: E, value: R): Unit = property.set(receiver1, receiver2, value) } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index cca0803d778..9e1d36c4a4a 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -16,8 +16,14 @@ package kotlin.reflect.jvm.internal -import java.lang.reflect.* -import kotlin.reflect.* +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor +import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor +import org.jetbrains.kotlin.resolve.DescriptorFactory +import java.lang.reflect.Field +import java.lang.reflect.Method +import kotlin.reflect.KMutableProperty +import kotlin.reflect.KProperty interface KPropertyImpl : KProperty, KCallableImpl { val javaField: Field? @@ -26,12 +32,19 @@ interface KPropertyImpl : KProperty, KCallableImpl { override val getter: Getter + override val descriptor: PropertyDescriptor + interface Accessor : KProperty.Accessor { override val property: KPropertyImpl } - interface Getter : KProperty.Getter, KCallableImpl { + abstract class Getter : KProperty.Getter, Accessor, KCallableImpl { override val name: String get() = "" + + override val descriptor: PropertyGetterDescriptor by ReflectProperties.lazySoft { + // TODO: default getter created this way won't have any source information + property.descriptor.getGetter() ?: DescriptorFactory.createDefaultGetter(property.descriptor) + } } } @@ -41,7 +54,12 @@ interface KMutablePropertyImpl : KMutableProperty, KPropertyImpl { override val setter: Setter - interface Setter : KMutableProperty.Setter, KPropertyImpl.Accessor, KCallableImpl { + abstract class Setter : KMutableProperty.Setter, KPropertyImpl.Accessor, KCallableImpl { override val name: String get() = "" + + override val descriptor: PropertySetterDescriptor by ReflectProperties.lazySoft { + // TODO: default setter created this way won't have any source information + property.descriptor.getSetter() ?: DescriptorFactory.createDefaultSetter(property.descriptor) + } } } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java index d0bb16a299b..d4b3d495bd7 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java @@ -19,6 +19,9 @@ package kotlin.jvm.internal; import kotlin.jvm.KotlinReflectionNotSupportedError; import kotlin.reflect.KCallable; import kotlin.reflect.KDeclarationContainer; +import kotlin.reflect.KParameter; + +import java.util.List; /** * A superclass for all classes generated by Kotlin compiler for callable references. @@ -60,7 +63,10 @@ public abstract class CallableReference implements KCallable { // The following methods are the stub implementations of reflection functions. // They are called when you're using reflection on a property reference without the reflection implementation in the classpath. - // (nothing here yet) + @Override + public List getParameters() { + throw error(); + } protected static Error error() { throw new KotlinReflectionNotSupportedError(); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java index bdf895a0a43..64cee9ed4a0 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java @@ -19,6 +19,8 @@ package kotlin.jvm.internal; import kotlin.jvm.KotlinReflectionNotSupportedError; import kotlin.reflect.*; +import java.util.List; + @SuppressWarnings("deprecation") public class FunctionReference extends FunctionImpl @@ -58,6 +60,11 @@ public class FunctionReference throw error(); } + @Override + public List getParameters() { + throw error(); + } + protected static Error error() { throw new KotlinReflectionNotSupportedError(); }