diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/parameters/isOptional.kt b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/isOptional.kt new file mode 100644 index 00000000000..1fe125c3baa --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/isOptional.kt @@ -0,0 +1,24 @@ +import kotlin.test.* + +open class A { + open fun foo(x: Int, y: Int = 1) {} +} + +class B : A() { + override fun foo(x: Int, y: Int) {} +} + +class C : A() + + +fun Int.extFun() {} + +fun box(): String { + assertEquals(listOf(false, false, true), A::foo.parameters.map { it.isOptional }) + assertEquals(listOf(false, false, true), B::foo.parameters.map { it.isOptional }) + assertEquals(listOf(false, false, true), C::foo.parameters.map { it.isOptional }) + + assertFalse(Int::extFun.parameters.single().isOptional) + + 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 da19367c738..8e6eadf60c3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3648,6 +3648,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("isOptional.kt") + public void testIsOptional() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters/isOptional.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("kinds.kt") public void testKinds() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters/kinds.kt"); diff --git a/core/builtins/src/kotlin/reflect/KParameter.kt b/core/builtins/src/kotlin/reflect/KParameter.kt index 4ff91222d43..71db9235cf6 100644 --- a/core/builtins/src/kotlin/reflect/KParameter.kt +++ b/core/builtins/src/kotlin/reflect/KParameter.kt @@ -60,4 +60,13 @@ public interface KParameter : KAnnotatedElement { /** Ordinary named value parameter. */ VALUE, } + + /** + * `true` if this parameter is optional, or `false` otherwise. + * + * A parameter is optional in any of the two cases: + * 1. The default value is provided at the declaration of this parameter. + * 2. The parameter is declared in a member function and one of the corresponding parameters in the super functions is optional. + */ + public val isOptional: Boolean } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt index 60a48e9ac79..9c3410d3f04 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt @@ -19,6 +19,7 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotated +import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import kotlin.reflect.KParameter import kotlin.reflect.KType @@ -42,6 +43,9 @@ class KParameterImpl( override val type: KType get() = KTypeImpl(descriptor.type) { callable.caller.parameterTypes[index] } + override val isOptional: Boolean + get() = (descriptor as? ValueParameterDescriptor)?.hasDefaultValue() ?: false + override fun equals(other: Any?) = other is KParameterImpl && callable == other.callable && descriptor == other.descriptor