Add kotlinx.cinterop.getOriginalKotlinClass(objCClass/objCProtocol)

Enables getting KClass for Kotlin classes produced to Objective-C header
This commit is contained in:
Svyatoslav Scherbina
2019-05-30 10:30:08 +03:00
committed by SvyatoslavScherbina
parent d1222907d4
commit 95a04cc804
7 changed files with 112 additions and 2 deletions
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlinx.cinterop
import kotlin.native.internal.KClassImpl
import kotlin.reflect.KClass
/**
* If [objCClass] is a class generated to Objective-C header for Kotlin class,
* returns [KClass] for that original Kotlin class.
*
* Otherwise returns `null`.
*/
fun getOriginalKotlinClass(objCClass: ObjCClass): KClass<*>? {
val typeInfo = getTypeInfoForClass(objCClass.objcPtr())
if (typeInfo.isNull()) return null
return KClassImpl<Any>(typeInfo)
}
/**
* If [objCProtocol] is a protocol generated to Objective-C header for Kotlin class,
* returns [KClass] for that original Kotlin class.
*
* Otherwise returns `null`.
*/
fun getOriginalKotlinClass(objCProtocol: ObjCProtocol): KClass<*>? {
val typeInfo = getTypeInfoForProtocol(objCProtocol.objcPtr())
if (typeInfo.isNull()) return null
return KClassImpl<Any>(typeInfo)
}
@SymbolName("Kotlin_ObjCInterop_getTypeInfoForClass")
private external fun getTypeInfoForClass(ptr: NativePtr): NativePtr
@SymbolName("Kotlin_ObjCInterop_getTypeInfoForProtocol")
private external fun getTypeInfoForProtocol(ptr: NativePtr): NativePtr
@@ -526,6 +526,22 @@ __attribute__((swift_name("MyAbstractList")))
@interface ValuesMyAbstractList : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestKClass")))
@interface ValuesTestKClass : KotlinBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
- (id<ValuesKotlinKClass> _Nullable)getKotlinClassClazz:(Class)clazz __attribute__((swift_name("getKotlinClass(clazz:)")));
- (id<ValuesKotlinKClass> _Nullable)getKotlinClassProtocol:(Protocol *)protocol __attribute__((swift_name("getKotlinClass(protocol:)")));
- (BOOL)isTestKClassKClass:(id<ValuesKotlinKClass>)kClass __attribute__((swift_name("isTestKClass(kClass:)")));
- (BOOL)isIKClass:(id<ValuesKotlinKClass>)kClass __attribute__((swift_name("isI(kClass:)")));
@end;
__attribute__((swift_name("TestKClassI")))
@protocol ValuesTestKClassI
@required
@end;
@interface ValuesEnumeration (ValuesKt)
- (ValuesEnumeration *)getAnswer __attribute__((swift_name("getAnswer()")));
@end;
@@ -11,7 +11,9 @@ package conversions
import kotlin.native.concurrent.freeze
import kotlin.native.concurrent.isFrozen
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlinx.cinterop.*
// Constants
const val dbl: Double = 3.14
@@ -426,3 +428,13 @@ abstract class MyAbstractList : List<Any?>
fun takeForwardDeclaredClass(obj: objcnames.classes.ForwardDeclaredClass) {}
fun takeForwardDeclaredProtocol(obj: objcnames.protocols.ForwardDeclaredProtocol) {}
class TestKClass {
fun getKotlinClass(clazz: ObjCClass) = getOriginalKotlinClass(clazz)
fun getKotlinClass(protocol: ObjCProtocol) = getOriginalKotlinClass(protocol)
fun isTestKClass(kClass: KClass<*>): Boolean = (kClass == TestKClass::class)
fun isI(kClass: KClass<*>): Boolean = (kClass == TestKClass.I::class)
interface I
}
@@ -583,6 +583,27 @@ func testGH2959() throws {
try assertEquals(actual: GH2959().getI(id: 2959)[0].id, expected: 2959)
}
func testKClass() throws {
let test = TestKClass()
let testKClass = test.getKotlinClass(clazz: TestKClass.self)!
try assertTrue(test.isTestKClass(kClass: testKClass))
try assertFalse(test.isI(kClass: testKClass))
try assertEquals(actual: testKClass.simpleName, expected: "TestKClass")
let iKClass = test.getKotlinClass(protocol: TestKClassI.self)!
try assertFalse(test.isTestKClass(kClass: iKClass))
try assertTrue(test.isI(kClass: iKClass))
try assertEquals(actual: iKClass.simpleName, expected: "I")
try assertTrue(test.getKotlinClass(clazz: NSObject.self) == nil)
try assertTrue(test.getKotlinClass(clazz: PureSwiftClass.self) == nil)
try assertTrue(test.getKotlinClass(clazz: PureSwiftKotlinInterfaceImpl.self) == nil)
try assertTrue(test.getKotlinClass(clazz: Base123.self) == nil)
try assertTrue(test.getKotlinClass(protocol: NSObjectProtocol.self) == nil)
}
// See https://github.com/JetBrains/kotlin-native/issues/2931
func testGH2931() throws {
for i in 0..<50000 {
@@ -646,6 +667,7 @@ class ValuesTests : TestProvider {
TestCase(name: "TestGH2945", method: withAutorelease(testGH2945)),
TestCase(name: "TestGH2830", method: withAutorelease(testGH2830)),
TestCase(name: "TestGH2959", method: withAutorelease(testGH2959)),
TestCase(name: "TestKClass", method: withAutorelease(testKClass)),
TestCase(name: "TestGH2931", method: withAutorelease(testGH2931)),
]
}
+17 -1
View File
@@ -350,6 +350,22 @@ static void addProtocolForInterface(Class clazz, const TypeInfo* interfaceInfo)
}
}
extern "C" const TypeInfo* Kotlin_ObjCInterop_getTypeInfoForClass(Class clazz) {
const TypeInfo* candidate = getAssociatedTypeInfo(clazz);
if (candidate != nullptr && (candidate->flags_ & TF_OBJC_DYNAMIC) == 0) {
return candidate;
} else {
return nullptr;
}
}
extern "C" const TypeInfo* Kotlin_ObjCInterop_getTypeInfoForProtocol(Protocol* protocol) {
const ObjCTypeAdapter* typeAdapter = findProtocolAdapter(protocol);
return (typeAdapter != nullptr) ? typeAdapter->kotlinTypeInfo : nullptr;
}
static const TypeInfo* getOrCreateTypeInfo(Class clazz);
static void initializeClass(Class clazz) {
@@ -714,7 +730,7 @@ static const TypeInfo* createTypeInfo(
TypeInfo* result = (TypeInfo*)konanAllocMemory(sizeof(TypeInfo) + vtable.size() * sizeof(void*));
result->typeInfo_ = result;
result->flags_ = 0;
result->flags_ = TF_OBJC_DYNAMIC;
result->instanceSize_ = superType->instanceSize_;
result->superType_ = superType;
+2 -1
View File
@@ -55,7 +55,8 @@ enum Konan_RuntimeType {
enum Konan_TypeFlags {
TF_IMMUTABLE = 1 << 0,
TF_ACYCLIC = 1 << 1,
TF_INTERFACE = 1 << 2
TF_INTERFACE = 1 << 2,
TF_OBJC_DYNAMIC = 1 << 3
};
enum Konan_MetaFlags {
@@ -26,6 +26,8 @@ class NativePtr @PublishedApi internal constructor(private val value: NonNullNat
override fun hashCode() = this.toLong().hashCode()
override fun toString() = "0x${this.toLong().toString(16)}"
internal fun isNull(): Boolean = (value == null)
}
@PublishedApi