From a085df914f06c1f21b204df4fa005d7d897a621b Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Sat, 15 Oct 2016 17:36:06 +0300 Subject: [PATCH] KJS: allow to use KClass::isInstance; implement isInstance in KClassImpl --- .../AbstractReflectionApiCallChecker.kt | 4 ++-- .../diagnostics/JsReflectionAPICallChecker.kt | 4 +++- js/js.libraries/src/reflect/KClassImpl.kt | 2 +- .../js/test/semantics/BoxJsTestGenerated.java | 6 +++++ .../box/reflection/kClassIsInstance.kt | 22 +++++++++++++++++++ .../box/reflection/kClassSimpleName.kt | 2 ++ .../box/reflection/kClassToAndFromJsClass.kt | 1 + 7 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 js/js.translator/testData/box/reflection/kClassIsInstance.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt index 8a80a8d94ef..a8f6d13e569 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt @@ -29,6 +29,8 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.util.OperatorNameConventions +private val ANY_MEMBER_NAMES = setOf("equals", "hashCode", "toString") + /** * Checks that there are no usages of reflection API which will fail at runtime. */ @@ -41,8 +43,6 @@ abstract class AbstractReflectionApiCallChecker(private val module: ModuleDescri setOf(reflectionTypes.kProperty0, reflectionTypes.kProperty1, reflectionTypes.kProperty2) } - private val ANY_MEMBER_NAMES = setOf("equals", "hashCode", "toString") - final override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { if (isWholeReflectionApiAvailable) return diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt index 735b5e12fa5..e6e396ed75c 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt @@ -28,6 +28,8 @@ import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue +private val ALLOWED_KCLASS_MEMBERS = setOf("simpleName", "isInstance") + class JsReflectionAPICallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : AbstractReflectionApiCallChecker(module, storageManager) { override val isWholeReflectionApiAvailable: Boolean get() = false @@ -40,5 +42,5 @@ class JsReflectionAPICallChecker(private val module: ModuleDescriptor, storageMa override fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean = super.isAllowedReflectionApi(descriptor, containingClass) || - DescriptorUtils.isSubclass(containingClass, kClass) && descriptor.name.asString() == "simpleName" + DescriptorUtils.isSubclass(containingClass, kClass) && descriptor.name.asString() in ALLOWED_KCLASS_MEMBERS } diff --git a/js/js.libraries/src/reflect/KClassImpl.kt b/js/js.libraries/src/reflect/KClassImpl.kt index b85773887a1..d32d03d30f2 100644 --- a/js/js.libraries/src/reflect/KClassImpl.kt +++ b/js/js.libraries/src/reflect/KClassImpl.kt @@ -71,7 +71,7 @@ internal class KClassImpl( } override fun isInstance(value: Any?): Boolean { - TODO() + return js("Kotlin").isType(value, jClass) } override fun toString(): String { diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 13096e0a2f7..0204bdd55d5 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -6259,6 +6259,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("kClassIsInstance.kt") + public void testKClassIsInstance() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/kClassIsInstance.kt"); + doTest(fileName); + } + @TestMetadata("kClassOnReifiedType.kt") public void testKClassOnReifiedType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/kClassOnReifiedType.kt"); diff --git a/js/js.translator/testData/box/reflection/kClassIsInstance.kt b/js/js.translator/testData/box/reflection/kClassIsInstance.kt new file mode 100644 index 00000000000..a6be9ac4445 --- /dev/null +++ b/js/js.translator/testData/box/reflection/kClassIsInstance.kt @@ -0,0 +1,22 @@ +package foo + +import kotlin.reflect.KClass + +fun check(k: KClass, instance: B, nonInstance: Any) { + assertTrue(k.isInstance(instance)) + assertFalse(k.isInstance(nonInstance)) + assertFalse(k.isInstance(null)) +} + +fun box(): String { + check(A::class, A(), O) + check(A::class, B(), O) + check(O::class, O, object {}) + check(I::class, object : I {}, object {}) + check(E::class, E.X, A()) + check(E::class, E.Y, B()) + check(E::class, E.Z, O) + check(E.Y::class, E.Y, E.X) + + return "OK" +} diff --git a/js/js.translator/testData/box/reflection/kClassSimpleName.kt b/js/js.translator/testData/box/reflection/kClassSimpleName.kt index 3d2047acef1..ab1e60d690c 100644 --- a/js/js.translator/testData/box/reflection/kClassSimpleName.kt +++ b/js/js.translator/testData/box/reflection/kClassSimpleName.kt @@ -12,6 +12,7 @@ fun testWithInstance() { assertEquals("A", A()::class.simpleName) assertEquals("B", B()::class.simpleName) assertEquals("O", (O)::class.simpleName) + assertEquals("Q", R()::class.simpleName) assertEquals("E", E.X::class.simpleName) assertEquals("Y", E.Y::class.simpleName) // TODO uncomment after KT-13338 is fixed @@ -26,6 +27,7 @@ fun testWithClassReference() { assertEquals("B", B::class.simpleName) assertEquals("O", O::class.simpleName) assertEquals("I", I::class.simpleName) + assertEquals("Q", R::class.simpleName) assertEquals("E", E::class.simpleName) assertEquals("undefined", foo.undefined::class.simpleName) assertEquals("Nested", Outer.Nested::class.simpleName) diff --git a/js/js.translator/testData/box/reflection/kClassToAndFromJsClass.kt b/js/js.translator/testData/box/reflection/kClassToAndFromJsClass.kt index 8fd0e9d7bbb..f6ce557c530 100644 --- a/js/js.translator/testData/box/reflection/kClassToAndFromJsClass.kt +++ b/js/js.translator/testData/box/reflection/kClassToAndFromJsClass.kt @@ -19,6 +19,7 @@ fun box(): String { check(B::class, jsClassbyName("B")) check(O::class, jsClassbyName("O").constructor) check(I::class, jsClassbyName("I")) + check(R::class, jsClassbyName("Q")) check(E::class, jsClassbyName("E")) check(E.X::class, jsClassbyName("E").X.constructor) check(E.Y::class, jsClassbyName("E").Y.constructor)