[ObjCExport] Extract generation of ObjC base declarations into shared code
KT-64226
This commit is contained in:
committed by
Space Team
parent
aab9a606ce
commit
72f135396c
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.objcexport.testUtils
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCTopLevel
|
||||
import org.jetbrains.kotlin.backend.konan.tests.ObjCExportBaseDeclarationsTest
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.api.extension.ParameterContext
|
||||
import org.junit.jupiter.api.extension.ParameterResolver
|
||||
|
||||
class AnalysisApiBaseDeclarationsGeneratorExtension : ParameterResolver {
|
||||
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
|
||||
return parameterContext.parameter.type == ObjCExportBaseDeclarationsTest.BaseDeclarationsGenerator::class.java
|
||||
}
|
||||
|
||||
override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
|
||||
return AnalysisApiBaseDeclarationsGenerator
|
||||
}
|
||||
}
|
||||
|
||||
object AnalysisApiBaseDeclarationsGenerator : ObjCExportBaseDeclarationsTest.BaseDeclarationsGenerator {
|
||||
override fun invoke(topLevelPrefix: String): List<ObjCTopLevel> {
|
||||
TODO("Analysis Api based 'base declaration generation' in not yet implemented")
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
#
|
||||
org.jetbrains.kotlin.objcexport.testUtils.AnalysisApiHeaderGeneratorExtension
|
||||
org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysisExtension
|
||||
org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysisExtension
|
||||
org.jetbrains.kotlin.objcexport.testUtils.AnalysisApiBaseDeclarationsGeneratorExtension
|
||||
-41
@@ -436,44 +436,3 @@ internal fun ObjCExportMapper.bridgePropertyType(descriptor: PropertyDescriptor)
|
||||
return bridgeType(descriptor.type)
|
||||
}
|
||||
|
||||
@InternalKotlinNativeApi
|
||||
enum class NSNumberKind(val mappedKotlinClassId: ClassId?, val objCType: ObjCType) {
|
||||
CHAR(PrimitiveType.BYTE, ObjCPrimitiveType.char),
|
||||
UNSIGNED_CHAR(UnsignedType.UBYTE, ObjCPrimitiveType.unsigned_char),
|
||||
SHORT(PrimitiveType.SHORT, ObjCPrimitiveType.short),
|
||||
UNSIGNED_SHORT(UnsignedType.USHORT, ObjCPrimitiveType.unsigned_short),
|
||||
INT(PrimitiveType.INT, ObjCPrimitiveType.int),
|
||||
UNSIGNED_INT(UnsignedType.UINT, ObjCPrimitiveType.unsigned_int),
|
||||
LONG(ObjCPrimitiveType.long),
|
||||
UNSIGNED_LONG(ObjCPrimitiveType.unsigned_long),
|
||||
LONG_LONG(PrimitiveType.LONG, ObjCPrimitiveType.long_long),
|
||||
UNSIGNED_LONG_LONG(UnsignedType.ULONG, ObjCPrimitiveType.unsigned_long_long),
|
||||
FLOAT(PrimitiveType.FLOAT, ObjCPrimitiveType.float),
|
||||
DOUBLE(PrimitiveType.DOUBLE, ObjCPrimitiveType.double),
|
||||
BOOL(PrimitiveType.BOOLEAN, ObjCPrimitiveType.BOOL),
|
||||
INTEGER(ObjCPrimitiveType.NSInteger),
|
||||
UNSIGNED_INTEGER(ObjCPrimitiveType.NSUInteger)
|
||||
|
||||
;
|
||||
|
||||
// UNSIGNED_SHORT -> unsignedShort
|
||||
private val kindName = this.name.split('_')
|
||||
.joinToString("") { it.lowercase().replaceFirstChar(Char::uppercaseChar) }.replaceFirstChar(Char::lowercaseChar)
|
||||
|
||||
|
||||
val valueSelector = kindName // unsignedShort
|
||||
val initSelector = "initWith${kindName.replaceFirstChar(Char::uppercaseChar)}:" // initWithUnsignedShort:
|
||||
val factorySelector = "numberWith${kindName.replaceFirstChar(Char::uppercaseChar)}:" // numberWithUnsignedShort:
|
||||
|
||||
constructor(
|
||||
primitiveType: PrimitiveType,
|
||||
objCPrimitiveType: ObjCPrimitiveType,
|
||||
) : this(ClassId.topLevel(primitiveType.typeFqName), objCPrimitiveType)
|
||||
|
||||
constructor(
|
||||
unsignedType: UnsignedType,
|
||||
objCPrimitiveType: ObjCPrimitiveType,
|
||||
) : this(unsignedType.classId, objCPrimitiveType)
|
||||
|
||||
constructor(objCPrimitiveType: ObjCPrimitiveType) : this(null, objCPrimitiveType)
|
||||
}
|
||||
|
||||
+8
-109
@@ -52,115 +52,14 @@ class ObjCExportTranslatorImpl(
|
||||
|
||||
private val kotlinAnyName = namer.kotlinAnyName
|
||||
|
||||
override fun generateBaseDeclarations(): List<ObjCTopLevel> = buildTopLevel {
|
||||
add {
|
||||
objCInterface(namer.kotlinAnyName, superClass = "NSObject", members = buildMembers {
|
||||
add { ObjCMethod(null, true, ObjCInstanceType, listOf("init"), emptyList(), listOf("unavailable")) }
|
||||
add { ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable")) }
|
||||
add { ObjCMethod(null, false, ObjCVoidType, listOf("initialize"), emptyList(), listOf("objc_requires_super")) }
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: add comment to the header.
|
||||
add {
|
||||
ObjCInterfaceImpl(
|
||||
namer.kotlinAnyName.objCName,
|
||||
superProtocols = listOf("NSCopying"),
|
||||
categoryName = "${namer.kotlinAnyName.objCName}Copying"
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: only if appears
|
||||
add {
|
||||
val generics = listOf("ObjectType")
|
||||
objCInterface(
|
||||
namer.mutableSetName,
|
||||
generics = generics,
|
||||
superClass = "NSMutableSet",
|
||||
superClassGenerics = generics
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: only if appears
|
||||
add {
|
||||
val generics = listOf("KeyType", "ObjectType")
|
||||
objCInterface(
|
||||
namer.mutableMapName,
|
||||
generics = generics,
|
||||
superClass = "NSMutableDictionary",
|
||||
superClassGenerics = generics
|
||||
)
|
||||
}
|
||||
|
||||
val nsErrorCategoryName = "NSError${namer.topLevelNamePrefix}KotlinException"
|
||||
add {
|
||||
ObjCInterfaceImpl("NSError", categoryName = nsErrorCategoryName, members = buildMembers {
|
||||
add { ObjCProperty("kotlinException", null, ObjCNullableReferenceType(ObjCIdType), listOf("readonly")) }
|
||||
})
|
||||
}
|
||||
|
||||
genKotlinNumbers()
|
||||
}
|
||||
|
||||
private fun StubBuilder<ObjCTopLevel>.genKotlinNumbers() {
|
||||
val members = buildMembers {
|
||||
NSNumberKind.entries.forEach {
|
||||
add { nsNumberFactory(it, listOf("unavailable")) }
|
||||
}
|
||||
NSNumberKind.entries.forEach {
|
||||
add { nsNumberInit(it, listOf("unavailable")) }
|
||||
}
|
||||
}
|
||||
add {
|
||||
objCInterface(
|
||||
namer.kotlinNumberName,
|
||||
superClass = "NSNumber",
|
||||
members = members
|
||||
)
|
||||
}
|
||||
|
||||
NSNumberKind.entries.forEach {
|
||||
if (it.mappedKotlinClassId != null) add {
|
||||
genKotlinNumber(it.mappedKotlinClassId, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun genKotlinNumber(kotlinClassId: ClassId, kind: NSNumberKind): ObjCInterface {
|
||||
val name = namer.numberBoxName(kotlinClassId)
|
||||
|
||||
val members = buildMembers {
|
||||
add { nsNumberFactory(kind) }
|
||||
add { nsNumberInit(kind) }
|
||||
}
|
||||
return objCInterface(
|
||||
name,
|
||||
superClass = namer.kotlinNumberName.objCName,
|
||||
members = members
|
||||
)
|
||||
}
|
||||
|
||||
private fun nsNumberInit(kind: NSNumberKind, attributes: List<String> = emptyList()): ObjCMethod {
|
||||
return ObjCMethod(
|
||||
null,
|
||||
false,
|
||||
ObjCInstanceType,
|
||||
listOf(kind.factorySelector),
|
||||
listOf(ObjCParameter("value", null, kind.objCType)),
|
||||
attributes
|
||||
)
|
||||
}
|
||||
|
||||
private fun nsNumberFactory(kind: NSNumberKind, attributes: List<String> = emptyList()): ObjCMethod {
|
||||
return ObjCMethod(
|
||||
null,
|
||||
true,
|
||||
ObjCInstanceType,
|
||||
listOf(kind.initSelector),
|
||||
listOf(ObjCParameter("value", null, kind.objCType)),
|
||||
attributes
|
||||
)
|
||||
}
|
||||
override fun generateBaseDeclarations(): List<ObjCTopLevel> = objCBaseDeclarations(
|
||||
topLevelNamePrefix = namer.topLevelNamePrefix,
|
||||
objCNameOfAny = namer.kotlinAnyName,
|
||||
objCNameOfNumber = namer.kotlinNumberName,
|
||||
objCNameOfMutableMap = namer.mutableMapName,
|
||||
objCNameOfMutableSet = namer.mutableSetName,
|
||||
objCNameForNumberBox = { classId -> namer.numberBoxName(classId) }
|
||||
)
|
||||
|
||||
override fun getClassIfExtension(receiverType: KotlinType): ClassDescriptor? =
|
||||
mapper.getClassIfCategory(receiverType)
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.backend.konan.testUtils
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportProblemCollector
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCTopLevel
|
||||
import org.jetbrains.kotlin.backend.konan.tests.ObjCExportBaseDeclarationsTest
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.api.extension.ParameterContext
|
||||
import org.junit.jupiter.api.extension.ParameterResolver
|
||||
|
||||
|
||||
class Fe10BaseDeclarationsGeneratorExtension : ParameterResolver {
|
||||
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
|
||||
return parameterContext.parameter.type == ObjCExportBaseDeclarationsTest.BaseDeclarationsGenerator::class.java
|
||||
}
|
||||
|
||||
override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
|
||||
return Fe10BaseDeclarationsGenerator
|
||||
}
|
||||
}
|
||||
|
||||
private object Fe10BaseDeclarationsGenerator : ObjCExportBaseDeclarationsTest.BaseDeclarationsGenerator {
|
||||
override fun invoke(topLevelPrefix: String): List<ObjCTopLevel> {
|
||||
val translator = ObjCExportTranslatorImpl(
|
||||
generator = null,
|
||||
mapper = createObjCExportMapper(),
|
||||
namer = createObjCExportNamer(configuration = createObjCExportNamerConfiguration(topLevelNamePrefix = topLevelPrefix)),
|
||||
problemCollector = ObjCExportProblemCollector.SILENT,
|
||||
objcGenerics = true
|
||||
)
|
||||
|
||||
return translator.generateBaseDeclarations()
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -2,4 +2,5 @@
|
||||
# Copyright 2010-2023 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.
|
||||
#
|
||||
org.jetbrains.kotlin.backend.konan.testUtils.Fe10HeaderGeneratorExtension
|
||||
org.jetbrains.kotlin.backend.konan.testUtils.Fe10HeaderGeneratorExtension
|
||||
org.jetbrains.kotlin.backend.konan.testUtils.Fe10BaseDeclarationsGeneratorExtension
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
/*
|
||||
Defining ClassIds for Unsigned types:
|
||||
Cannot reuse 'UnsignedType.kt' from core/descriptors
|
||||
*/
|
||||
private val uByteClassId = ClassId.fromString("kotlin/UByte")
|
||||
private val uShortClassId = ClassId.fromString("kotlin/UShort")
|
||||
private val uIntClassId = ClassId.fromString("kotlin/UInt")
|
||||
private val uLongClassId = ClassId.fromString("kotlin/ULong")
|
||||
|
||||
@InternalKotlinNativeApi
|
||||
enum class NSNumberKind(val mappedKotlinClassId: ClassId?, val objCType: ObjCType) {
|
||||
CHAR(PrimitiveType.BYTE, ObjCPrimitiveType.char),
|
||||
UNSIGNED_CHAR(uByteClassId, ObjCPrimitiveType.unsigned_char),
|
||||
SHORT(PrimitiveType.SHORT, ObjCPrimitiveType.short),
|
||||
UNSIGNED_SHORT(uShortClassId, ObjCPrimitiveType.unsigned_short),
|
||||
INT(PrimitiveType.INT, ObjCPrimitiveType.int),
|
||||
UNSIGNED_INT(uIntClassId, ObjCPrimitiveType.unsigned_int),
|
||||
LONG(ObjCPrimitiveType.long),
|
||||
UNSIGNED_LONG(ObjCPrimitiveType.unsigned_long),
|
||||
LONG_LONG(PrimitiveType.LONG, ObjCPrimitiveType.long_long),
|
||||
UNSIGNED_LONG_LONG(uLongClassId, ObjCPrimitiveType.unsigned_long_long),
|
||||
FLOAT(PrimitiveType.FLOAT, ObjCPrimitiveType.float),
|
||||
DOUBLE(PrimitiveType.DOUBLE, ObjCPrimitiveType.double),
|
||||
BOOL(PrimitiveType.BOOLEAN, ObjCPrimitiveType.BOOL),
|
||||
INTEGER(ObjCPrimitiveType.NSInteger),
|
||||
UNSIGNED_INTEGER(ObjCPrimitiveType.NSUInteger)
|
||||
|
||||
;
|
||||
|
||||
// UNSIGNED_SHORT -> unsignedShort
|
||||
private val kindName = this.name.split('_')
|
||||
.joinToString("") { it.lowercase().replaceFirstChar(Char::uppercaseChar) }.replaceFirstChar(Char::lowercaseChar)
|
||||
|
||||
val valueSelector = kindName // unsignedShort
|
||||
val initSelector = "initWith${kindName.replaceFirstChar(Char::uppercaseChar)}:" // initWithUnsignedShort:
|
||||
val factorySelector = "numberWith${kindName.replaceFirstChar(Char::uppercaseChar)}:" // numberWithUnsignedShort:
|
||||
|
||||
constructor(
|
||||
primitiveType: PrimitiveType,
|
||||
objCPrimitiveType: ObjCPrimitiveType,
|
||||
) : this(ClassId.topLevel(primitiveType.typeFqName), objCPrimitiveType)
|
||||
|
||||
constructor(objCPrimitiveType: ObjCPrimitiveType) : this(null, objCPrimitiveType)
|
||||
}
|
||||
|
||||
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
@InternalKotlinNativeApi
|
||||
fun objCBaseDeclarations(
|
||||
topLevelNamePrefix: String,
|
||||
objCNameOfAny: ObjCExportClassOrProtocolName,
|
||||
objCNameOfNumber: ObjCExportClassOrProtocolName,
|
||||
objCNameOfMutableMap: ObjCExportClassOrProtocolName,
|
||||
objCNameOfMutableSet: ObjCExportClassOrProtocolName,
|
||||
objCNameForNumberBox: (numberClassId: ClassId) -> ObjCExportClassOrProtocolName
|
||||
): List<ObjCTopLevel> = buildList {
|
||||
add {
|
||||
objCInterface(objCNameOfAny, superClass = "NSObject", members = buildList {
|
||||
add {
|
||||
ObjCMethod(
|
||||
origin = null,
|
||||
comment = null,
|
||||
isInstanceMethod = true,
|
||||
returnType = ObjCInstanceType,
|
||||
selectors = listOf("init"),
|
||||
parameters = emptyList(),
|
||||
attributes = listOf("unavailable")
|
||||
)
|
||||
}
|
||||
add {
|
||||
ObjCMethod(
|
||||
origin = null,
|
||||
comment = null,
|
||||
isInstanceMethod = false,
|
||||
returnType = ObjCInstanceType,
|
||||
selectors = listOf("new"),
|
||||
parameters = emptyList(), attributes = listOf("unavailable")
|
||||
)
|
||||
}
|
||||
add {
|
||||
ObjCMethod(
|
||||
origin = null,
|
||||
comment = null,
|
||||
isInstanceMethod = false,
|
||||
returnType = ObjCVoidType,
|
||||
selectors = listOf("initialize"),
|
||||
parameters = emptyList(),
|
||||
attributes = listOf("objc_requires_super")
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: add comment to the header.
|
||||
add {
|
||||
ObjCInterfaceImpl(
|
||||
objCNameOfAny.objCName,
|
||||
superProtocols = listOf("NSCopying"),
|
||||
categoryName = "${objCNameOfAny.objCName}Copying",
|
||||
origin = null,
|
||||
comment = null,
|
||||
generics = emptyList(),
|
||||
attributes = emptyList(),
|
||||
members = emptyList(),
|
||||
superClass = null,
|
||||
superClassGenerics = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: only if appears
|
||||
add {
|
||||
val generics = listOf("ObjectType")
|
||||
objCInterface(
|
||||
objCNameOfMutableSet,
|
||||
generics = generics,
|
||||
superClass = "NSMutableSet",
|
||||
superClassGenerics = generics
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: only if appears
|
||||
add {
|
||||
val generics = listOf("KeyType", "ObjectType")
|
||||
objCInterface(
|
||||
objCNameOfMutableMap,
|
||||
generics = generics,
|
||||
superClass = "NSMutableDictionary",
|
||||
superClassGenerics = generics
|
||||
)
|
||||
}
|
||||
|
||||
val nsErrorCategoryName = "NSError${topLevelNamePrefix}KotlinException"
|
||||
add {
|
||||
ObjCInterfaceImpl(
|
||||
name = "NSError",
|
||||
categoryName = nsErrorCategoryName,
|
||||
members = buildList {
|
||||
add {
|
||||
ObjCProperty(
|
||||
name = "kotlinException",
|
||||
origin = null,
|
||||
type = ObjCNullableReferenceType(ObjCIdType),
|
||||
propertyAttributes = listOf("readonly"),
|
||||
setterName = null,
|
||||
getterName = null,
|
||||
comment = null,
|
||||
declarationAttributes = emptyList()
|
||||
)
|
||||
}
|
||||
},
|
||||
attributes = emptyList(),
|
||||
comment = null,
|
||||
origin = null,
|
||||
superProtocols = emptyList(),
|
||||
generics = emptyList(),
|
||||
superClass = null,
|
||||
superClassGenerics = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
genKotlinNumbers(objCNameOfNumber = objCNameOfNumber, objCNameForNumberBox = objCNameForNumberBox)
|
||||
}
|
||||
|
||||
private fun MutableList<ObjCTopLevel>.genKotlinNumbers(
|
||||
objCNameOfNumber: ObjCExportClassOrProtocolName,
|
||||
objCNameForNumberBox: (numberClassId: ClassId) -> ObjCExportClassOrProtocolName
|
||||
) {
|
||||
val members = buildList {
|
||||
NSNumberKind.entries.forEach {
|
||||
add(nsNumberFactory(it, listOf("unavailable")))
|
||||
}
|
||||
NSNumberKind.entries.forEach {
|
||||
add(nsNumberInit(it, listOf("unavailable")))
|
||||
}
|
||||
}
|
||||
add {
|
||||
objCInterface(
|
||||
objCNameOfNumber,
|
||||
superClass = "NSNumber",
|
||||
members = members
|
||||
)
|
||||
}
|
||||
|
||||
NSNumberKind.entries.forEach {
|
||||
if (it.mappedKotlinClassId != null) add {
|
||||
genKotlinNumber(it.mappedKotlinClassId, it, objCNameOfNumber, objCNameForNumberBox)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun genKotlinNumber(
|
||||
kotlinClassId: ClassId,
|
||||
kind: NSNumberKind,
|
||||
objCNameOfNumber: ObjCExportClassOrProtocolName,
|
||||
objCNameForNumberBox: (numberClassId: ClassId) -> ObjCExportClassOrProtocolName
|
||||
): ObjCInterface {
|
||||
val name = objCNameForNumberBox(kotlinClassId)
|
||||
|
||||
val members = buildList<ObjCExportStub> {
|
||||
add { nsNumberFactory(kind) }
|
||||
add { nsNumberInit(kind) }
|
||||
}
|
||||
return objCInterface(
|
||||
name,
|
||||
superClass = objCNameOfNumber.objCName,
|
||||
members = members
|
||||
)
|
||||
}
|
||||
|
||||
private fun nsNumberInit(kind: NSNumberKind, attributes: List<String> = emptyList()): ObjCMethod {
|
||||
return ObjCMethod(
|
||||
origin = null,
|
||||
comment = null,
|
||||
isInstanceMethod = false,
|
||||
returnType = ObjCInstanceType,
|
||||
selectors = listOf(kind.factorySelector),
|
||||
parameters = listOf(
|
||||
ObjCParameter(name = "value", origin = null, type = kind.objCType, todo = null)
|
||||
),
|
||||
attributes = attributes
|
||||
)
|
||||
}
|
||||
|
||||
private fun nsNumberFactory(kind: NSNumberKind, attributes: List<String> = emptyList()): ObjCMethod {
|
||||
return ObjCMethod(
|
||||
origin = null,
|
||||
comment = null,
|
||||
isInstanceMethod = true,
|
||||
returnType = ObjCInstanceType,
|
||||
selectors = listOf(kind.initSelector),
|
||||
parameters = listOf(ObjCParameter("value", null, kind.objCType, todo = null)),
|
||||
attributes = attributes
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private inline fun <T> MutableList<T>.add(producer: () -> T) {
|
||||
add(producer())
|
||||
}
|
||||
|
||||
private fun objCInterface(
|
||||
name: ObjCExportClassOrProtocolName,
|
||||
generics: List<String>,
|
||||
superClass: String,
|
||||
superClassGenerics: List<String>,
|
||||
): ObjCInterface = objCInterface(
|
||||
name,
|
||||
generics = generics.map { ObjCGenericTypeRawDeclaration(it) },
|
||||
superClass = superClass,
|
||||
superClassGenerics = superClassGenerics.map { ObjCGenericTypeRawUsage(it) }
|
||||
)
|
||||
|
||||
private fun objCInterface(
|
||||
name: ObjCExportClassOrProtocolName,
|
||||
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
|
||||
superClass: String? = null,
|
||||
superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
|
||||
superProtocols: List<String> = emptyList(),
|
||||
members: List<ObjCExportStub> = emptyList(),
|
||||
attributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
): ObjCInterface = ObjCInterfaceImpl(
|
||||
name = name.objCName,
|
||||
generics = generics,
|
||||
origin = null,
|
||||
superClass = superClass,
|
||||
superClassGenerics = superClassGenerics,
|
||||
superProtocols = superProtocols,
|
||||
members = members,
|
||||
attributes = attributes.plus(name.toNameAttributes()),
|
||||
comment = comment,
|
||||
categoryName = null
|
||||
)
|
||||
|
||||
private fun objCProtocol(
|
||||
name: ObjCExportClassOrProtocolName,
|
||||
superProtocols: List<String>,
|
||||
members: List<ObjCExportStub>,
|
||||
attributes: List<String> = emptyList(),
|
||||
comment: ObjCComment? = null,
|
||||
): ObjCProtocol = ObjCProtocolImpl(
|
||||
name = name.objCName,
|
||||
origin = null,
|
||||
superProtocols = superProtocols,
|
||||
members = members,
|
||||
attributes = attributes + name.toNameAttributes(),
|
||||
comment = comment
|
||||
)
|
||||
|
||||
|
||||
private fun ObjCExportClassOrProtocolName.toNameAttributes(): List<String> = listOfNotNull(
|
||||
binaryName.takeIf { it != objCName }?.let { objcRuntimeNameAttribute(it) },
|
||||
swiftName.takeIf { it != objCName }?.let { swiftNameAttribute(it) }
|
||||
)
|
||||
|
||||
private fun swiftNameAttribute(swiftName: String) = "swift_name(\"$swiftName\")"
|
||||
private fun objcRuntimeNameAttribute(name: String) = "objc_runtime_name(\"$name\")"
|
||||
+2
-1
@@ -8,4 +8,5 @@ package org.jetbrains.kotlin.backend.konan.testUtils
|
||||
import java.io.File
|
||||
|
||||
val testDataDir = File("native/objcexport-header-generator/testData")
|
||||
val headersTestDataDir = testDataDir.resolve("headers")
|
||||
val headersTestDataDir = testDataDir.resolve("headers")
|
||||
val baseDeclarationsDir = testDataDir.resolve("baseDeclarations")
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.backend.konan.tests
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCTopLevel
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.StubRenderer
|
||||
import org.jetbrains.kotlin.backend.konan.testUtils.baseDeclarationsDir
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* ## Test Scope
|
||||
* This test will just invoke the generation of 'base declarations' (basically ObjC stubs that shall always be present)
|
||||
* The generated declarations will be compared to previously checked-in 'golden' headers.
|
||||
*/
|
||||
class ObjCExportBaseDeclarationsTest(
|
||||
/**
|
||||
* Injected implementation: Either K1 or based upon Analysis API.
|
||||
*/
|
||||
private val generator: BaseDeclarationsGenerator,
|
||||
) {
|
||||
|
||||
@Test
|
||||
fun `test - noTopLevelPrefix`() {
|
||||
doTest(baseDeclarationsDir.resolve("!noTopLevelPrefix.h"), "")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - topLevelPrefix`() {
|
||||
doTest(baseDeclarationsDir.resolve("!topLevelPrefix.h"), "MyTopLevelPrefix")
|
||||
}
|
||||
|
||||
private fun doTest(headerFile: File, topLevelPrefix: String) {
|
||||
val declarations = generator(topLevelPrefix)
|
||||
|
||||
val renderedDeclarations = declarations
|
||||
.flatMap { declaration -> StubRenderer.render(declaration) }
|
||||
.joinToString(System.lineSeparator())
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(headerFile, renderedDeclarations)
|
||||
}
|
||||
|
||||
fun interface BaseDeclarationsGenerator {
|
||||
operator fun invoke(topLevelPrefix: String): List<ObjCTopLevel>
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
__attribute__((swift_name("KotlinBase")))
|
||||
@interface Base : NSObject
|
||||
- (instancetype)init __attribute__((unavailable));
|
||||
+ (instancetype)new __attribute__((unavailable));
|
||||
+ (void)initialize __attribute__((objc_requires_super));
|
||||
@end
|
||||
@interface Base (BaseCopying) <NSCopying>
|
||||
@end
|
||||
__attribute__((swift_name("KotlinMutableSet")))
|
||||
@interface MutableSet<ObjectType> : NSMutableSet<ObjectType>
|
||||
@end
|
||||
__attribute__((swift_name("KotlinMutableDictionary")))
|
||||
@interface MutableDictionary<KeyType, ObjectType> : NSMutableDictionary<KeyType, ObjectType>
|
||||
@end
|
||||
@interface NSError (NSErrorKotlinException)
|
||||
@property (readonly) id _Nullable kotlinException;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinNumber")))
|
||||
@interface Number : NSNumber
|
||||
- (instancetype)initWithChar:(char)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedChar:(unsigned char)value __attribute__((unavailable));
|
||||
- (instancetype)initWithShort:(short)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedShort:(unsigned short)value __attribute__((unavailable));
|
||||
- (instancetype)initWithInt:(int)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedInt:(unsigned int)value __attribute__((unavailable));
|
||||
- (instancetype)initWithLong:(long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedLong:(unsigned long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithLongLong:(long long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedLongLong:(unsigned long long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithFloat:(float)value __attribute__((unavailable));
|
||||
- (instancetype)initWithDouble:(double)value __attribute__((unavailable));
|
||||
- (instancetype)initWithBool:(BOOL)value __attribute__((unavailable));
|
||||
- (instancetype)initWithInteger:(NSInteger)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedInteger:(NSUInteger)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithChar:(char)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedChar:(unsigned char)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithShort:(short)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedShort:(unsigned short)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithInt:(int)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedInt:(unsigned int)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithLong:(long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedLong:(unsigned long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithLongLong:(long long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedLongLong:(unsigned long long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithFloat:(float)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithDouble:(double)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithBool:(BOOL)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithInteger:(NSInteger)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedInteger:(NSUInteger)value __attribute__((unavailable));
|
||||
@end
|
||||
__attribute__((swift_name("KotlinByte")))
|
||||
@interface Byte : Number
|
||||
- (instancetype)initWithChar:(char)value;
|
||||
+ (instancetype)numberWithChar:(char)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinUByte")))
|
||||
@interface UByte : Number
|
||||
- (instancetype)initWithUnsignedChar:(unsigned char)value;
|
||||
+ (instancetype)numberWithUnsignedChar:(unsigned char)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinShort")))
|
||||
@interface Short : Number
|
||||
- (instancetype)initWithShort:(short)value;
|
||||
+ (instancetype)numberWithShort:(short)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinUShort")))
|
||||
@interface UShort : Number
|
||||
- (instancetype)initWithUnsignedShort:(unsigned short)value;
|
||||
+ (instancetype)numberWithUnsignedShort:(unsigned short)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinInt")))
|
||||
@interface Int : Number
|
||||
- (instancetype)initWithInt:(int)value;
|
||||
+ (instancetype)numberWithInt:(int)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinUInt")))
|
||||
@interface UInt : Number
|
||||
- (instancetype)initWithUnsignedInt:(unsigned int)value;
|
||||
+ (instancetype)numberWithUnsignedInt:(unsigned int)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinLong")))
|
||||
@interface Long : Number
|
||||
- (instancetype)initWithLongLong:(long long)value;
|
||||
+ (instancetype)numberWithLongLong:(long long)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinULong")))
|
||||
@interface ULong : Number
|
||||
- (instancetype)initWithUnsignedLongLong:(unsigned long long)value;
|
||||
+ (instancetype)numberWithUnsignedLongLong:(unsigned long long)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinFloat")))
|
||||
@interface Float : Number
|
||||
- (instancetype)initWithFloat:(float)value;
|
||||
+ (instancetype)numberWithFloat:(float)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinDouble")))
|
||||
@interface Double : Number
|
||||
- (instancetype)initWithDouble:(double)value;
|
||||
+ (instancetype)numberWithDouble:(double)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinBoolean")))
|
||||
@interface Boolean : Number
|
||||
- (instancetype)initWithBool:(BOOL)value;
|
||||
+ (instancetype)numberWithBool:(BOOL)value;
|
||||
@end
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
__attribute__((swift_name("KotlinBase")))
|
||||
@interface MyTopLevelPrefixBase : NSObject
|
||||
- (instancetype)init __attribute__((unavailable));
|
||||
+ (instancetype)new __attribute__((unavailable));
|
||||
+ (void)initialize __attribute__((objc_requires_super));
|
||||
@end
|
||||
@interface MyTopLevelPrefixBase (MyTopLevelPrefixBaseCopying) <NSCopying>
|
||||
@end
|
||||
__attribute__((swift_name("KotlinMutableSet")))
|
||||
@interface MyTopLevelPrefixMutableSet<ObjectType> : NSMutableSet<ObjectType>
|
||||
@end
|
||||
__attribute__((swift_name("KotlinMutableDictionary")))
|
||||
@interface MyTopLevelPrefixMutableDictionary<KeyType, ObjectType> : NSMutableDictionary<KeyType, ObjectType>
|
||||
@end
|
||||
@interface NSError (NSErrorMyTopLevelPrefixKotlinException)
|
||||
@property (readonly) id _Nullable kotlinException;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinNumber")))
|
||||
@interface MyTopLevelPrefixNumber : NSNumber
|
||||
- (instancetype)initWithChar:(char)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedChar:(unsigned char)value __attribute__((unavailable));
|
||||
- (instancetype)initWithShort:(short)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedShort:(unsigned short)value __attribute__((unavailable));
|
||||
- (instancetype)initWithInt:(int)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedInt:(unsigned int)value __attribute__((unavailable));
|
||||
- (instancetype)initWithLong:(long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedLong:(unsigned long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithLongLong:(long long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedLongLong:(unsigned long long)value __attribute__((unavailable));
|
||||
- (instancetype)initWithFloat:(float)value __attribute__((unavailable));
|
||||
- (instancetype)initWithDouble:(double)value __attribute__((unavailable));
|
||||
- (instancetype)initWithBool:(BOOL)value __attribute__((unavailable));
|
||||
- (instancetype)initWithInteger:(NSInteger)value __attribute__((unavailable));
|
||||
- (instancetype)initWithUnsignedInteger:(NSUInteger)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithChar:(char)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedChar:(unsigned char)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithShort:(short)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedShort:(unsigned short)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithInt:(int)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedInt:(unsigned int)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithLong:(long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedLong:(unsigned long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithLongLong:(long long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedLongLong:(unsigned long long)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithFloat:(float)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithDouble:(double)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithBool:(BOOL)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithInteger:(NSInteger)value __attribute__((unavailable));
|
||||
+ (instancetype)numberWithUnsignedInteger:(NSUInteger)value __attribute__((unavailable));
|
||||
@end
|
||||
__attribute__((swift_name("KotlinByte")))
|
||||
@interface MyTopLevelPrefixByte : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithChar:(char)value;
|
||||
+ (instancetype)numberWithChar:(char)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinUByte")))
|
||||
@interface MyTopLevelPrefixUByte : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithUnsignedChar:(unsigned char)value;
|
||||
+ (instancetype)numberWithUnsignedChar:(unsigned char)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinShort")))
|
||||
@interface MyTopLevelPrefixShort : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithShort:(short)value;
|
||||
+ (instancetype)numberWithShort:(short)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinUShort")))
|
||||
@interface MyTopLevelPrefixUShort : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithUnsignedShort:(unsigned short)value;
|
||||
+ (instancetype)numberWithUnsignedShort:(unsigned short)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinInt")))
|
||||
@interface MyTopLevelPrefixInt : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithInt:(int)value;
|
||||
+ (instancetype)numberWithInt:(int)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinUInt")))
|
||||
@interface MyTopLevelPrefixUInt : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithUnsignedInt:(unsigned int)value;
|
||||
+ (instancetype)numberWithUnsignedInt:(unsigned int)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinLong")))
|
||||
@interface MyTopLevelPrefixLong : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithLongLong:(long long)value;
|
||||
+ (instancetype)numberWithLongLong:(long long)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinULong")))
|
||||
@interface MyTopLevelPrefixULong : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithUnsignedLongLong:(unsigned long long)value;
|
||||
+ (instancetype)numberWithUnsignedLongLong:(unsigned long long)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinFloat")))
|
||||
@interface MyTopLevelPrefixFloat : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithFloat:(float)value;
|
||||
+ (instancetype)numberWithFloat:(float)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinDouble")))
|
||||
@interface MyTopLevelPrefixDouble : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithDouble:(double)value;
|
||||
+ (instancetype)numberWithDouble:(double)value;
|
||||
@end
|
||||
__attribute__((swift_name("KotlinBoolean")))
|
||||
@interface MyTopLevelPrefixBoolean : MyTopLevelPrefixNumber
|
||||
- (instancetype)initWithBool:(BOOL)value;
|
||||
+ (instancetype)numberWithBool:(BOOL)value;
|
||||
@end
|
||||
Reference in New Issue
Block a user