Add kotlinx.cinterop.getOriginalKotlinClass(objCClass/objCProtocol)
Enables getting KClass for Kotlin classes produced to Objective-C header
This commit is contained in:
committed by
SvyatoslavScherbina
parent
d1222907d4
commit
95a04cc804
@@ -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)),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user