Use compiler-generated C stubs when overriding some Objective-C methods (#2697)
* Add tests to interop_objc_smoke * Use compiler-generated C stubs when overriding some Objective-C methods
This commit is contained in:
committed by
Nikolay Igotti
parent
0c90464ac4
commit
4d6614e674
@@ -106,7 +106,7 @@ annotation class ObjCMethod(val selector: String, val bridge: String)
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ObjCBridge(val selector: String, val encoding: String, val imp: String)
|
||||
annotation class ObjCBridge(val selector: String, val encoding: String, val imp: String = "")
|
||||
|
||||
@Target(AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
|
||||
@@ -14,4 +14,16 @@ public annotation class CCall(val id: String) {
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class WCString
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ReturnsRetained
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ConsumesReceiver
|
||||
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Consumed
|
||||
}
|
||||
|
||||
+27
-5
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.native.interop.gen
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.native.interop.gen.jvm.StubGenerator
|
||||
import org.jetbrains.kotlin.native.interop.indexer.*
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
private fun ObjCMethod.getKotlinParameterNames(forConstructorOrFactory: Boolean = false): List<String> {
|
||||
val selectorParts = this.selector.split(":")
|
||||
@@ -74,6 +75,8 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
if (context.nativeBridges.isSupported(this)) {
|
||||
val result = mutableListOf<String>()
|
||||
result.add("@ObjCMethod".applyToStrings(method.selector, bridgeName))
|
||||
if (method.nsConsumesSelf) result.add("@CCall.ConsumesReceiver")
|
||||
if (method.nsReturnsRetained) result.add("@CCall.ReturnsRetained")
|
||||
result.add(header)
|
||||
|
||||
if (method.isInit) {
|
||||
@@ -136,9 +139,16 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
}
|
||||
}
|
||||
|
||||
val objCBridge = "@ObjCBridge".applyToStrings(
|
||||
*mutableListOf<String>().apply {
|
||||
add(method.selector)
|
||||
add(method.encoding)
|
||||
addIfNotNull(implementationTemplate)
|
||||
}.toTypedArray()
|
||||
)
|
||||
|
||||
context.addTopLevelDeclaration(
|
||||
listOf("@kotlin.native.internal.ExportForCompiler",
|
||||
"@ObjCBridge".applyToStrings(method.selector, method.encoding, implementationTemplate))
|
||||
listOf("@kotlin.native.internal.ExportForCompiler", objCBridge)
|
||||
+ block(bridgeHeader, bodyLines)
|
||||
)
|
||||
|
||||
@@ -154,7 +164,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
private val kotlinParameters: List<KotlinParameter>
|
||||
private val kotlinReturnType: String
|
||||
private val header: String
|
||||
private val implementationTemplate: String
|
||||
private val implementationTemplate: String?
|
||||
internal val bridgeName: String
|
||||
private val bridgeHeader: String
|
||||
|
||||
@@ -194,7 +204,8 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
val name = kotlinParameterNames[index]
|
||||
|
||||
val kotlinType = stubGenerator.mirror(it.type).argType
|
||||
kotlinParameters.add(KotlinParameter(name, kotlinType))
|
||||
val annotatedName = if (it.nsConsumed) "@CCall.Consumed $name" else name
|
||||
kotlinParameters.add(KotlinParameter(annotatedName, kotlinType))
|
||||
|
||||
kotlinObjCBridgeParameters.add(KotlinParameter(name, kotlinType))
|
||||
nativeBridgeArguments.add(TypedKotlinValue(it.type, name.asSimpleName()))
|
||||
@@ -233,7 +244,12 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
}
|
||||
bodyGenerator.returnResult(result)
|
||||
|
||||
this.implementationTemplate = genImplementationTemplate(stubGenerator)
|
||||
this.implementationTemplate = if (needsImplementationTemplate()) {
|
||||
genImplementationTemplate(stubGenerator)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
this.bodyLines = bodyGenerator.build()
|
||||
|
||||
bridgeName = "objcKniBridge${stubGenerator.nextUniqueId()}"
|
||||
@@ -277,6 +293,10 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
}
|
||||
}
|
||||
|
||||
private fun needsImplementationTemplate(): Boolean =
|
||||
method.getReturnType(container.classOrProtocol).isBlockPointer() ||
|
||||
method.parameters.any { it.type.isBlockPointer() }
|
||||
|
||||
private fun genImplementationTemplate(stubGenerator: StubGenerator): String = when (container) {
|
||||
is ObjCClassOrProtocol -> {
|
||||
val codeBuilder = NativeCodeBuilder(stubGenerator.simpleBridgeGenerator.topLevelNativeScope)
|
||||
@@ -289,6 +309,8 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
}
|
||||
}
|
||||
|
||||
private fun Type.isBlockPointer() = this.unwrapTypedefs() is ObjCBlockPointer
|
||||
|
||||
private fun deprecatedInit(className: String, initParameterNames: List<String>, factory: Boolean): String {
|
||||
val replacement = if (factory) "$className.create" else className
|
||||
val replacementKind = if (factory) "factory method" else "constructor"
|
||||
|
||||
Reference in New Issue
Block a user