KJS: allow to use KClass::isInstance; implement isInstance in KClassImpl
This commit is contained in:
+2
-2
@@ -29,6 +29,8 @@ import org.jetbrains.kotlin.storage.StorageManager
|
|||||||
import org.jetbrains.kotlin.storage.getValue
|
import org.jetbrains.kotlin.storage.getValue
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
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.
|
* 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)
|
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) {
|
final override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
if (isWholeReflectionApiAvailable) return
|
if (isWholeReflectionApiAvailable) return
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
|||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
import org.jetbrains.kotlin.storage.getValue
|
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) {
|
class JsReflectionAPICallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : AbstractReflectionApiCallChecker(module, storageManager) {
|
||||||
override val isWholeReflectionApiAvailable: Boolean
|
override val isWholeReflectionApiAvailable: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
@@ -40,5 +42,5 @@ class JsReflectionAPICallChecker(private val module: ModuleDescriptor, storageMa
|
|||||||
|
|
||||||
override fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean =
|
override fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean =
|
||||||
super.isAllowedReflectionApi(descriptor, containingClass) ||
|
super.isAllowedReflectionApi(descriptor, containingClass) ||
|
||||||
DescriptorUtils.isSubclass(containingClass, kClass) && descriptor.name.asString() == "simpleName"
|
DescriptorUtils.isSubclass(containingClass, kClass) && descriptor.name.asString() in ALLOWED_KCLASS_MEMBERS
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ internal class KClassImpl<T : Any>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isInstance(value: Any?): Boolean {
|
override fun isInstance(value: Any?): Boolean {
|
||||||
TODO()
|
return js("Kotlin").isType(value, jClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
|||||||
@@ -6259,6 +6259,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kClassOnReifiedType.kt")
|
||||||
public void testKClassOnReifiedType() throws Exception {
|
public void testKClassOnReifiedType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/kClassOnReifiedType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/kClassOnReifiedType.kt");
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
fun <A : Any, B : A> check(k: KClass<A>, 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"
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ fun testWithInstance() {
|
|||||||
assertEquals("A", A()::class.simpleName)
|
assertEquals("A", A()::class.simpleName)
|
||||||
assertEquals("B", B()::class.simpleName)
|
assertEquals("B", B()::class.simpleName)
|
||||||
assertEquals("O", (O)::class.simpleName)
|
assertEquals("O", (O)::class.simpleName)
|
||||||
|
assertEquals("Q", R()::class.simpleName)
|
||||||
assertEquals("E", E.X::class.simpleName)
|
assertEquals("E", E.X::class.simpleName)
|
||||||
assertEquals("Y", E.Y::class.simpleName)
|
assertEquals("Y", E.Y::class.simpleName)
|
||||||
// TODO uncomment after KT-13338 is fixed
|
// TODO uncomment after KT-13338 is fixed
|
||||||
@@ -26,6 +27,7 @@ fun testWithClassReference() {
|
|||||||
assertEquals("B", B::class.simpleName)
|
assertEquals("B", B::class.simpleName)
|
||||||
assertEquals("O", O::class.simpleName)
|
assertEquals("O", O::class.simpleName)
|
||||||
assertEquals("I", I::class.simpleName)
|
assertEquals("I", I::class.simpleName)
|
||||||
|
assertEquals("Q", R::class.simpleName)
|
||||||
assertEquals("E", E::class.simpleName)
|
assertEquals("E", E::class.simpleName)
|
||||||
assertEquals("undefined", foo.undefined::class.simpleName)
|
assertEquals("undefined", foo.undefined::class.simpleName)
|
||||||
assertEquals("Nested", Outer.Nested::class.simpleName)
|
assertEquals("Nested", Outer.Nested::class.simpleName)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ fun box(): String {
|
|||||||
check(B::class, jsClassbyName("B"))
|
check(B::class, jsClassbyName("B"))
|
||||||
check(O::class, jsClassbyName("O").constructor)
|
check(O::class, jsClassbyName("O").constructor)
|
||||||
check(I::class, jsClassbyName("I"))
|
check(I::class, jsClassbyName("I"))
|
||||||
|
check(R::class, jsClassbyName("Q"))
|
||||||
check(E::class, jsClassbyName("E"))
|
check(E::class, jsClassbyName("E"))
|
||||||
check(E.X::class, jsClassbyName("E").X.constructor)
|
check(E.X::class, jsClassbyName("E").X.constructor)
|
||||||
check(E.Y::class, jsClassbyName("E").Y.constructor)
|
check(E.Y::class, jsClassbyName("E").Y.constructor)
|
||||||
|
|||||||
Reference in New Issue
Block a user