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
|
@interface ValuesMyAbstractList : NSObject
|
||||||
@end;
|
@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)
|
@interface ValuesEnumeration (ValuesKt)
|
||||||
- (ValuesEnumeration *)getAnswer __attribute__((swift_name("getAnswer()")));
|
- (ValuesEnumeration *)getAnswer __attribute__((swift_name("getAnswer()")));
|
||||||
@end;
|
@end;
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ package conversions
|
|||||||
import kotlin.native.concurrent.freeze
|
import kotlin.native.concurrent.freeze
|
||||||
import kotlin.native.concurrent.isFrozen
|
import kotlin.native.concurrent.isFrozen
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlinx.cinterop.*
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const val dbl: Double = 3.14
|
const val dbl: Double = 3.14
|
||||||
@@ -426,3 +428,13 @@ abstract class MyAbstractList : List<Any?>
|
|||||||
|
|
||||||
fun takeForwardDeclaredClass(obj: objcnames.classes.ForwardDeclaredClass) {}
|
fun takeForwardDeclaredClass(obj: objcnames.classes.ForwardDeclaredClass) {}
|
||||||
fun takeForwardDeclaredProtocol(obj: objcnames.protocols.ForwardDeclaredProtocol) {}
|
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)
|
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
|
// See https://github.com/JetBrains/kotlin-native/issues/2931
|
||||||
func testGH2931() throws {
|
func testGH2931() throws {
|
||||||
for i in 0..<50000 {
|
for i in 0..<50000 {
|
||||||
@@ -646,6 +667,7 @@ class ValuesTests : TestProvider {
|
|||||||
TestCase(name: "TestGH2945", method: withAutorelease(testGH2945)),
|
TestCase(name: "TestGH2945", method: withAutorelease(testGH2945)),
|
||||||
TestCase(name: "TestGH2830", method: withAutorelease(testGH2830)),
|
TestCase(name: "TestGH2830", method: withAutorelease(testGH2830)),
|
||||||
TestCase(name: "TestGH2959", method: withAutorelease(testGH2959)),
|
TestCase(name: "TestGH2959", method: withAutorelease(testGH2959)),
|
||||||
|
TestCase(name: "TestKClass", method: withAutorelease(testKClass)),
|
||||||
TestCase(name: "TestGH2931", method: withAutorelease(testGH2931)),
|
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 const TypeInfo* getOrCreateTypeInfo(Class clazz);
|
||||||
|
|
||||||
static void initializeClass(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*));
|
TypeInfo* result = (TypeInfo*)konanAllocMemory(sizeof(TypeInfo) + vtable.size() * sizeof(void*));
|
||||||
result->typeInfo_ = result;
|
result->typeInfo_ = result;
|
||||||
|
|
||||||
result->flags_ = 0;
|
result->flags_ = TF_OBJC_DYNAMIC;
|
||||||
|
|
||||||
result->instanceSize_ = superType->instanceSize_;
|
result->instanceSize_ = superType->instanceSize_;
|
||||||
result->superType_ = superType;
|
result->superType_ = superType;
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ enum Konan_RuntimeType {
|
|||||||
enum Konan_TypeFlags {
|
enum Konan_TypeFlags {
|
||||||
TF_IMMUTABLE = 1 << 0,
|
TF_IMMUTABLE = 1 << 0,
|
||||||
TF_ACYCLIC = 1 << 1,
|
TF_ACYCLIC = 1 << 1,
|
||||||
TF_INTERFACE = 1 << 2
|
TF_INTERFACE = 1 << 2,
|
||||||
|
TF_OBJC_DYNAMIC = 1 << 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Konan_MetaFlags {
|
enum Konan_MetaFlags {
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ class NativePtr @PublishedApi internal constructor(private val value: NonNullNat
|
|||||||
override fun hashCode() = this.toLong().hashCode()
|
override fun hashCode() = this.toLong().hashCode()
|
||||||
|
|
||||||
override fun toString() = "0x${this.toLong().toString(16)}"
|
override fun toString() = "0x${this.toLong().toString(16)}"
|
||||||
|
|
||||||
|
internal fun isNull(): Boolean = (value == null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
|
|||||||
Reference in New Issue
Block a user