[KN] CInterop: __attribute__((objc_direct)) support
Merge-request: KT-MR-8828 Merged-by: Gleb Lukianets <Gleb.Lukianets@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
ae07d0e9ce
commit
fc96eb6d8d
+12
-2
@@ -132,7 +132,7 @@ private class ObjCMethodStubBuilder(
|
||||
kotlinMethodParameters = method.getKotlinParameters(context, forConstructorOrFactory = false)
|
||||
external = (container !is ObjCProtocol)
|
||||
modality = when (container) {
|
||||
is ObjCClass -> MemberStubModality.OPEN
|
||||
is ObjCClass -> if (method.isDirect) MemberStubModality.FINAL else MemberStubModality.OPEN
|
||||
is ObjCProtocol -> if (method.isOptional) MemberStubModality.OPEN else MemberStubModality.ABSTRACT
|
||||
is ObjCCategory -> MemberStubModality.FINAL
|
||||
}
|
||||
@@ -145,7 +145,17 @@ private class ObjCMethodStubBuilder(
|
||||
private fun buildObjCMethodAnnotations(main: AnnotationStub): List<AnnotationStub> = listOfNotNull(
|
||||
main,
|
||||
AnnotationStub.ObjC.ConsumesReceiver.takeIf { method.nsConsumesSelf },
|
||||
AnnotationStub.ObjC.ReturnsRetained.takeIf { method.nsReturnsRetained }
|
||||
AnnotationStub.ObjC.ReturnsRetained.takeIf { method.nsReturnsRetained },
|
||||
if (method.isDirect) {
|
||||
when (container) {
|
||||
is ObjCClass -> container.name
|
||||
is ObjCCategory -> container.clazz.name
|
||||
is ObjCProtocol -> null
|
||||
}?.let {
|
||||
val prefix = if (method.isClass) '+' else '-'
|
||||
AnnotationStub.ObjC.Direct("$prefix[$it ${method.selector}]")
|
||||
}
|
||||
} else { null },
|
||||
)
|
||||
|
||||
fun isDefaultConstructor(): Boolean =
|
||||
|
||||
+3
@@ -185,6 +185,9 @@ sealed class AnnotationStub(val classifier: Classifier) {
|
||||
class Method(val selector: String, val encoding: String, val isStret: Boolean = false) :
|
||||
ObjC(Classifier.topLevel(cinteropPackage, "ObjCMethod"))
|
||||
|
||||
class Direct(val symbol: String) :
|
||||
ObjC(Classifier.topLevel(cinteropPackage, "ObjCDirect"))
|
||||
|
||||
class Factory(val selector: String, val encoding: String, val isStret: Boolean = false) :
|
||||
ObjC(Classifier.topLevel(cinteropPackage, "ObjCFactory"))
|
||||
|
||||
|
||||
+3
@@ -394,6 +394,9 @@ private class MappingExtensions(
|
||||
("encoding" to encoding).asAnnotationArgument(),
|
||||
("isStret" to KmAnnotationArgument.BooleanValue(isStret))
|
||||
)
|
||||
is AnnotationStub.ObjC.Direct -> mapOfNotNull(
|
||||
("symbol" to symbol).asAnnotationArgument(),
|
||||
)
|
||||
is AnnotationStub.ObjC.Factory -> mapOfNotNull(
|
||||
("selector" to selector).asAnnotationArgument(),
|
||||
("encoding" to encoding).asAnnotationArgument(),
|
||||
|
||||
+1
@@ -458,6 +458,7 @@ class StubIrTextEmitter(
|
||||
val encoding = annotationStub.encoding.quoteAsKotlinLiteral()
|
||||
"@ObjCMethod($selector, $encoding$stret)"
|
||||
}
|
||||
is AnnotationStub.ObjC.Direct -> "@ObjCDirect(${annotationStub.symbol.quoteAsKotlinLiteral()})"
|
||||
is AnnotationStub.ObjC.Factory -> {
|
||||
val stret = if (annotationStub.isStret) ", true" else ""
|
||||
val selector = annotationStub.selector.quoteAsKotlinLiteral()
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.native.interop.gen
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.native.interop.indexer.buildNativeIndex
|
||||
import org.junit.Assume
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ObjCMethodSignaturesTest : InteropTestsBase() {
|
||||
companion object {
|
||||
@BeforeClass
|
||||
@JvmStatic
|
||||
fun assumeMacOS() {
|
||||
Assume.assumeTrue(HostManager.hostIsMac)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ObjC Direct`() {
|
||||
val files = TempFiles("ObjCDirect")
|
||||
files.file("header.h", """
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface Foo : NSObject
|
||||
+ (void)direct __attribute__((objc_direct));
|
||||
- (void)direct __attribute__((objc_direct));
|
||||
@end
|
||||
|
||||
@interface Foo(Ext)
|
||||
+ (void)directExt __attribute__((objc_direct));
|
||||
- (void)directExt __attribute__((objc_direct));
|
||||
@end
|
||||
""".trimIndent())
|
||||
val defFile = files.file("direct.def", """
|
||||
language = Objective-C
|
||||
headers = header.h
|
||||
""".trimIndent())
|
||||
val library = buildNativeLibraryFrom(defFile, files.directory)
|
||||
val index = buildNativeIndex(library, false).index
|
||||
|
||||
index.objCClasses.find { it.name == "Foo" }.let { cls ->
|
||||
assertNotNull(cls, "Class 'Foo' not found in native library $library")
|
||||
assertNotNull(cls.methods.find { it.selector == "direct" && it.isClass && it.isDirect })
|
||||
assertNotNull(cls.methods.find { it.selector == "direct" && !it.isClass && it.isDirect })
|
||||
}
|
||||
|
||||
index.objCCategories.find { it.name == "Ext" && it.clazz.name == "Foo" }.let { cat ->
|
||||
assertNotNull(cat, "Category 'Foo(Ext)' not found in native library $library")
|
||||
assertNotNull(cat.methods.find { it.selector == "directExt" && it.isClass && it.isDirect })
|
||||
assertNotNull(cat.methods.find { it.selector == "directExt" && !it.isClass && it.isDirect })
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user