Improve interop with headers generated by Swift
Support `objc_runtime_name` attribute on Objective-C classes thus enabling interop with `@objc` Swift classes without explicitly specified name. See https://github.com/JetBrains/kotlin-native/issues/1841#issuecomment-411346727
This commit is contained in:
committed by
SvyatoslavScherbina
parent
4ec1ec05cf
commit
803620f423
+13
-3
@@ -60,7 +60,8 @@ private class ObjCProtocolImpl(
|
||||
private class ObjCClassImpl(
|
||||
name: String,
|
||||
override val location: Location,
|
||||
override val isForwardDeclaration: Boolean
|
||||
override val isForwardDeclaration: Boolean,
|
||||
override val binaryName: String?
|
||||
) : ObjCClass(name), ObjCContainerImpl {
|
||||
override val protocols = mutableListOf<ObjCProtocol>()
|
||||
override val methods = mutableListOf<ObjCMethod>()
|
||||
@@ -302,12 +303,13 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
|
||||
|
||||
if (isObjCInterfaceDeclForward(cursor)) {
|
||||
return objCClassRegistry.getOrPut(cursor) {
|
||||
ObjCClassImpl(name, getLocation(cursor), isForwardDeclaration = true)
|
||||
ObjCClassImpl(name, getLocation(cursor), isForwardDeclaration = true, binaryName = null)
|
||||
}
|
||||
}
|
||||
|
||||
return objCClassRegistry.getOrPut(cursor, {
|
||||
ObjCClassImpl(name, getLocation(cursor), isForwardDeclaration = false)
|
||||
ObjCClassImpl(name, getLocation(cursor), isForwardDeclaration = false,
|
||||
binaryName = getObjCBinaryName(cursor).takeIf { it != name })
|
||||
}) {
|
||||
addChildrenToObjCContainer(cursor, it)
|
||||
}
|
||||
@@ -336,6 +338,14 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getObjCBinaryName(cursor: CValue<CXCursor>): String {
|
||||
val prefix = "_OBJC_CLASS_\$_"
|
||||
val symbolName = clang_Cursor_getObjCManglings(cursor)!!.convertAndDispose()
|
||||
.single { it.startsWith(prefix) }
|
||||
|
||||
return symbolName.substring(prefix.length)
|
||||
}
|
||||
|
||||
private fun getObjCCategoryAt(cursor: CValue<CXCursor>): ObjCCategoryImpl? {
|
||||
assert(cursor.kind == CXCursorKind.CXCursor_ObjCCategoryDecl) { cursor.kind }
|
||||
|
||||
|
||||
+1
@@ -163,6 +163,7 @@ data class ObjCProperty(val name: String, val getter: ObjCMethod, val setter: Ob
|
||||
}
|
||||
|
||||
abstract class ObjCClass(name: String) : ObjCClassOrProtocol(name) {
|
||||
abstract val binaryName: String?
|
||||
abstract val baseClass: ObjCClass?
|
||||
}
|
||||
abstract class ObjCProtocol(name: String) : ObjCClassOrProtocol(name)
|
||||
|
||||
@@ -38,6 +38,14 @@ internal fun CValue<CXString>.convertAndDispose(): String {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun CPointer<CXStringSet>.convertAndDispose(): Set<String> = try {
|
||||
(0 until this.pointed.Count).mapTo(mutableSetOf()) {
|
||||
clang_getCString(this.pointed.Strings!![it].readValue())!!.toKString()
|
||||
}
|
||||
} finally {
|
||||
clang_disposeStringSet(this)
|
||||
}
|
||||
|
||||
internal fun getCursorSpelling(cursor: CValue<CXCursor>) =
|
||||
clang_getCursorSpelling(cursor).convertAndDispose()
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ typealias ObjCBlockVar<T> = ObjCNotImplementedVar<T>
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ExternalObjCClass(val protocolGetter: String = "")
|
||||
annotation class ExternalObjCClass(val protocolGetter: String = "", val binaryName: String = "")
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
|
||||
+20
-13
@@ -505,21 +505,28 @@ abstract class ObjCContainerStub(stubGenerator: StubGenerator,
|
||||
val name = stubGenerator.kotlinFile.declare(classifier)
|
||||
|
||||
val externalObjCClassAnnotationName = "@ExternalObjCClass"
|
||||
val externalObjCClassAnnotation: String
|
||||
|
||||
if (container is ObjCProtocol) {
|
||||
protocolGetter = if (metaContainerStub != null) {
|
||||
metaContainerStub.protocolGetter!!
|
||||
} else {
|
||||
val nativeBacked = object : NativeBacked {}
|
||||
// TODO: handle the case when protocol getter stub can't be compiled.
|
||||
genProtocolGetter(stubGenerator, nativeBacked, container)
|
||||
val externalObjCClassAnnotation: String = when (container) {
|
||||
is ObjCProtocol -> {
|
||||
protocolGetter = if (metaContainerStub != null) {
|
||||
metaContainerStub.protocolGetter!!
|
||||
} else {
|
||||
val nativeBacked = object : NativeBacked {}
|
||||
// TODO: handle the case when protocol getter stub can't be compiled.
|
||||
genProtocolGetter(stubGenerator, nativeBacked, container)
|
||||
}
|
||||
|
||||
externalObjCClassAnnotationName.applyToStrings(protocolGetter)
|
||||
}
|
||||
is ObjCClass -> {
|
||||
protocolGetter = null
|
||||
val binaryName = container.binaryName
|
||||
if (binaryName != null) {
|
||||
externalObjCClassAnnotationName.applyToStrings("", binaryName)
|
||||
} else {
|
||||
externalObjCClassAnnotationName
|
||||
}
|
||||
}
|
||||
|
||||
externalObjCClassAnnotation = externalObjCClassAnnotationName.applyToStrings(protocolGetter)
|
||||
} else {
|
||||
protocolGetter = null
|
||||
externalObjCClassAnnotation = externalObjCClassAnnotationName
|
||||
}
|
||||
|
||||
this.classHeader = "$externalObjCClassAnnotation $keywords $name : $supersString"
|
||||
|
||||
+13
-3
@@ -5,9 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.findPackageView
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull
|
||||
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
|
||||
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getExternalObjCMethodInfo
|
||||
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.resolve.constants.BooleanValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -229,4 +228,15 @@ fun inferObjCSelector(descriptor: FunctionDescriptor): String = if (descriptor.v
|
||||
append(':')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ClassDescriptor.getExternalObjCClassBinaryName(): String =
|
||||
this.getExplicitExternalObjCClassBinaryName()
|
||||
?: this.name.asString()
|
||||
|
||||
fun ClassDescriptor.getExternalObjCMetaClassBinaryName(): String =
|
||||
this.getExplicitExternalObjCClassBinaryName()
|
||||
?: this.name.asString().removeSuffix("Meta")
|
||||
|
||||
private fun ClassDescriptor.getExplicitExternalObjCClassBinaryName() =
|
||||
this.annotations.findAnnotation(externalObjCClassFqName)!!.getStringValueOrNull("binaryName")
|
||||
+2
-2
@@ -754,7 +754,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
context.llvm.imports.add(irClass.llvmSymbolOrigin)
|
||||
|
||||
if (irClass.isObjCMetaClass()) {
|
||||
val name = irClass.name.asString().removeSuffix("Meta")
|
||||
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
|
||||
|
||||
val objCClass = load(codegen.objCDataGenerator!!.genClassRef(name).llvm)
|
||||
|
||||
@@ -766,7 +766,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
|
||||
call(getClass, listOf(objCClass), exceptionHandler = exceptionHandler)
|
||||
} else {
|
||||
load(codegen.objCDataGenerator!!.genClassRef(irClass.name.asString()).llvm)
|
||||
load(codegen.objCDataGenerator!!.genClassRef(irClass.descriptor.getExternalObjCClassBinaryName()).llvm)
|
||||
}
|
||||
} else {
|
||||
if (irClass.isObjCMetaClass()) {
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
|
||||
|
||||
val superclassName = irClass.getSuperClassNotAny()!!.let {
|
||||
context.llvm.imports.add(it.llvmSymbolOrigin)
|
||||
it.name.asString()
|
||||
it.descriptor.getExternalObjCClassBinaryName()
|
||||
}
|
||||
val protocolNames = irClass.getSuperInterfaces().map {
|
||||
context.llvm.imports.add(it.llvmSymbolOrigin)
|
||||
|
||||
Reference in New Issue
Block a user