diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/functions/privateMemberFunction.kt b/compiler/testData/codegen/boxWithStdlib/reflection/functions/privateMemberFunction.kt new file mode 100644 index 00000000000..313b1cbe0bb --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/functions/privateMemberFunction.kt @@ -0,0 +1,22 @@ +import kotlin.reflect.* +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +class A { + private fun foo() = "A" +} + +fun box(): String { + val f = A::class.declaredFunctions.single() as KFunction + + try { + f.call(A()) + return "Fail: no exception was thrown" + } catch (e: IllegalCallableAccessException) {} + + f.isAccessible = true + + assertEquals("A", f.call(A())) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt index 984b66a6191..5e48be92c03 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt @@ -9,7 +9,7 @@ fun box(): String { try { return p.get(K("Fail: private property should not be accessible by default")) } - catch (e: IllegalPropertyAccessException) { + catch (e: IllegalCallableAccessException) { // OK } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt index 3c3bbbf25b7..2eea52e18cd 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt @@ -12,7 +12,7 @@ fun box(): String { try { p.get(Result()) return "Fail: private property is accessible by default" - } catch(e: IllegalPropertyAccessException) { } + } catch(e: IllegalCallableAccessException) { } p.isAccessible = true @@ -22,7 +22,7 @@ fun box(): String { try { p.get(Result()) return "Fail: setAccessible(false) had no effect" - } catch(e: IllegalPropertyAccessException) { } + } catch(e: IllegalCallableAccessException) { } return r } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt index 3bd9f4d3321..e33d6e8f321 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt @@ -13,7 +13,7 @@ fun box(): String { try { p.set(a, 1) return "Fail: private property is accessible by default" - } catch(e: IllegalPropertyAccessException) { } + } catch(e: IllegalCallableAccessException) { } p.isAccessible = true @@ -24,7 +24,7 @@ fun box(): String { try { p.set(a, 3) return "Fail: setAccessible(false) had no effect" - } catch(e: IllegalPropertyAccessException) { } + } catch(e: IllegalCallableAccessException) { } return "OK" } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt index d8797af8f1f..cd2f7f9f6ae 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt @@ -14,12 +14,12 @@ fun box(): String { try { f.get(a) return "Fail: protected property getter is accessible by default" - } catch (e: IllegalPropertyAccessException) { } + } catch (e: IllegalCallableAccessException) { } try { f.set(a, ":D") return "Fail: protected property setter is accessible by default" - } catch (e: IllegalPropertyAccessException) { } + } catch (e: IllegalCallableAccessException) { } f.isAccessible = true diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 09efea600b9..5bc5c3b1ef6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3126,6 +3126,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("privateMemberFunction.kt") + public void testPrivateMemberFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/functions/privateMemberFunction.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("simpleGetFunctions.kt") public void testSimpleGetFunctions() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/functions/simpleGetFunctions.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/exceptions.kt b/core/reflection.jvm/src/kotlin/reflect/exceptions.kt index 2f934081bc9..185eb7d6daa 100644 --- a/core/reflection.jvm/src/kotlin/reflect/exceptions.kt +++ b/core/reflection.jvm/src/kotlin/reflect/exceptions.kt @@ -17,14 +17,14 @@ package kotlin.reflect /** - * An exception that is thrown when `get` or `set` is called on a property - * and that property is not accessible (in JVM terms) from the calling method. + * An exception that is thrown when `call` is invoked on a callable or `get` or `set` is invoked on a property + * and that callable is not accessible (in JVM terms) from the calling method. * * @param cause the original exception thrown by the JVM. * * @see [kotlin.reflect.jvm.isAccessible] */ -public class IllegalPropertyAccessException(cause: IllegalAccessException) : Exception(cause.getMessage()) { +public class IllegalCallableAccessException(cause: IllegalAccessException) : Exception(cause.getMessage()) { init { @suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (this as java.lang.Throwable).initCause(cause) 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 ca3a5117ad3..3427875af20 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -74,7 +74,9 @@ open class KFunctionImpl protected constructor( } } - override fun call(vararg args: Any?): Any? = caller.call(args) + override fun call(vararg args: Any?): Any? = reflectionCall { + caller.call(args) + } override fun getArity(): Int { return descriptor.valueParameters.size() + 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 93f02c4c4df..7ba6d0802f0 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor 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 @@ -35,14 +34,9 @@ open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KP override val javaGetter: Method get() = super.javaGetter!! - override fun get(): R { - try { - @suppress("UNCHECKED_CAST") - return javaGetter.invoke(null) as R - } - catch (e: IllegalAccessException) { - throw IllegalPropertyAccessException(e) - } + @suppress("UNCHECKED_CAST") + override fun get(): R = reflectionCall { + return javaGetter.invoke(null) as R } override fun call(vararg args: Any?): R { @@ -65,12 +59,9 @@ open class KMutableProperty0Impl : KProperty0Impl, KMutableProperty0, K override val javaSetter: Method get() = super.javaSetter!! override fun set(value: R) { - try { + reflectionCall { javaSetter.invoke(null, value) } - catch (e: IllegalAccessException) { - throw IllegalPropertyAccessException(e) - } } class Setter(override val property: KMutableProperty0Impl) : KMutablePropertyImpl.Setter(), KMutableProperty0.Setter { 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 ae2e7797749..5484412278d 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor import java.lang.reflect.Modifier import kotlin.jvm.internal.MutablePropertyReference1 import kotlin.jvm.internal.PropertyReference1 -import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty1 @@ -34,26 +33,18 @@ open class KProperty1Impl : DescriptorBasedProperty, KProperty1 javaField!!.get(receiver) + Modifier.isStatic(getter.modifiers) -> { // Workaround the case of platformStatic property in object, getter of which doesn't take a receiver - if (getter.getParameterTypes().isEmpty()) { - return getter.invoke(null) as R - } - - return getter.invoke(null, receiver) as R + if (getter.parameterTypes.isEmpty()) getter.invoke(null) + else getter.invoke(null, receiver) } - - return getter.invoke(receiver) as R - } - catch (e: IllegalAccessException) { - throw IllegalPropertyAccessException(e) - } + else -> getter.invoke(receiver) + } as R } @suppress("UNCHECKED_CAST") @@ -76,25 +67,17 @@ open class KMutableProperty1Impl : KProperty1Impl, KMutableProperty1 override val setter by ReflectProperties.lazy { Setter(this) } override fun set(receiver: T, value: R) { - try { - val setter = javaSetter ?: - return javaField!!.set(receiver, value) - - if (Modifier.isStatic(setter.getModifiers())) { - // Workaround the case of platformStatic property in object, setter of which doesn't take a receiver - if (setter.getParameterTypes().size() == 1) { - setter.invoke(null, value) - } - else { - setter.invoke(null, receiver, value) + reflectionCall { + val setter = javaSetter + when { + setter == null -> javaField!!.set(receiver, value) + Modifier.isStatic(setter.modifiers) -> { + // Workaround the case of platformStatic property in object, setter of which doesn't take a receiver + if (setter.parameterTypes.size() == 1) setter.invoke(null, value) + else setter.invoke(null, receiver, value) } + else -> setter.invoke(receiver, value) } - else { - setter.invoke(receiver, value) - } - } - catch (e: IllegalAccessException) { - throw IllegalPropertyAccessException(e) } } 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 cb0a4558b41..38810e99194 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt @@ -19,7 +19,6 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.PropertyDescriptor import java.lang.reflect.Field import java.lang.reflect.Method -import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KProperty2 @@ -36,14 +35,9 @@ open class KProperty2Impl : DescriptorBasedProperty, KProperty2< override val javaField: Field? get() = null - override fun get(receiver1: D, receiver2: E): R { - try { - @suppress("UNCHECKED_CAST") - return javaGetter.invoke(receiver1, receiver2) as R - } - catch (e: IllegalAccessException) { - throw IllegalPropertyAccessException(e) - } + @suppress("UNCHECKED_CAST") + override fun get(receiver1: D, receiver2: E): R = reflectionCall { + return javaGetter.invoke(receiver1, receiver2) as R } @suppress("UNCHECKED_CAST") @@ -68,12 +62,9 @@ class KMutableProperty2Impl : KProperty2Impl, KMutableProperty override val javaSetter: Method get() = super.javaSetter!! override fun set(receiver1: D, receiver2: E, value: R) { - try { + reflectionCall { javaSetter.invoke(receiver1, receiver2, value) } - catch (e: IllegalAccessException) { - throw IllegalPropertyAccessException(e) - } } class Setter(override val property: KMutableProperty2Impl) : KMutablePropertyImpl.Setter(), KMutableProperty2.Setter { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt new file mode 100644 index 00000000000..74d287b4066 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -0,0 +1,28 @@ +/* + * 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 kotlin.reflect.IllegalCallableAccessException + +// TODO: wrap other exceptions +internal inline fun reflectionCall(block: () -> R): R = + try { + block() + } + catch (e: IllegalAccessException) { + throw IllegalCallableAccessException(e) + }