Add minor improvements to ObjCExport
This commit is contained in:
committed by
SvyatoslavScherbina
parent
faafeea719
commit
c0ef560b07
+167
-136
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isAny
|
||||
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
@@ -19,12 +22,15 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.isInterface
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
interface ObjCExportTranslator {
|
||||
fun generateBaseDeclarations(): List<ObjCTopLevel<*>>
|
||||
fun getClassIfExtension(receiverType: KotlinType): ClassDescriptor?
|
||||
fun translateFile(file: SourceFile, declarations: List<CallableMemberDescriptor>): ObjCInterface
|
||||
fun translateClass(descriptor: ClassDescriptor): ObjCInterface
|
||||
fun translateInterface(descriptor: ClassDescriptor): ObjCProtocol
|
||||
@@ -43,7 +49,6 @@ interface ObjCExportWarningCollector {
|
||||
|
||||
internal class ObjCExportTranslatorImpl(
|
||||
private val generator: ObjCExportHeaderGenerator?,
|
||||
val builtIns: KotlinBuiltIns,
|
||||
val mapper: ObjCExportMapper,
|
||||
val namer: ObjCExportNamer,
|
||||
val warningCollector: ObjCExportWarningCollector,
|
||||
@@ -52,13 +57,129 @@ internal class ObjCExportTranslatorImpl(
|
||||
|
||||
private val kotlinAnyName = namer.kotlinAnyName
|
||||
|
||||
internal fun translateKotlinObjCClassAsUnavailableStub(descriptor: ClassDescriptor): ObjCInterface = objCInterface(
|
||||
override fun generateBaseDeclarations(): List<ObjCTopLevel<*>> {
|
||||
val stubs = mutableListOf<ObjCTopLevel<*>>()
|
||||
|
||||
stubs.add(objCInterface(namer.kotlinAnyName, superClass = "NSObject", members = buildMembers {
|
||||
+ObjCMethod(null, true, ObjCInstanceType, listOf("init"), emptyList(), listOf("unavailable"))
|
||||
+ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable"))
|
||||
+ObjCMethod(null, false, ObjCVoidType, listOf("initialize"), emptyList(), listOf("objc_requires_super"))
|
||||
}))
|
||||
|
||||
// TODO: add comment to the header.
|
||||
stubs.add(ObjCInterfaceImpl(
|
||||
namer.kotlinAnyName.objCName,
|
||||
superProtocols = listOf("NSCopying"),
|
||||
categoryName = "${namer.kotlinAnyName.objCName}Copying"
|
||||
))
|
||||
|
||||
// TODO: only if appears
|
||||
stubs.add(objCInterface(
|
||||
namer.mutableSetName,
|
||||
generics = listOf("ObjectType"),
|
||||
superClass = "NSMutableSet<ObjectType>"
|
||||
))
|
||||
|
||||
// TODO: only if appears
|
||||
stubs.add(objCInterface(
|
||||
namer.mutableMapName,
|
||||
generics = listOf("KeyType", "ObjectType"),
|
||||
superClass = "NSMutableDictionary<KeyType, ObjectType>"
|
||||
))
|
||||
|
||||
stubs.add(ObjCInterfaceImpl("NSError", categoryName = "NSErrorKotlinException", members = buildMembers {
|
||||
+ObjCProperty("kotlinException", null, ObjCNullableReferenceType(ObjCIdType), listOf("readonly"))
|
||||
}))
|
||||
|
||||
genKotlinNumbers(stubs)
|
||||
|
||||
return stubs
|
||||
}
|
||||
|
||||
private fun genKotlinNumbers(stubs: MutableList<ObjCTopLevel<*>>) {
|
||||
val members = buildMembers {
|
||||
NSNumberKind.values().forEach {
|
||||
+nsNumberFactory(it, listOf("unavailable"))
|
||||
}
|
||||
NSNumberKind.values().forEach {
|
||||
+nsNumberInit(it, listOf("unavailable"))
|
||||
}
|
||||
}
|
||||
stubs.add(objCInterface(
|
||||
namer.kotlinNumberName,
|
||||
superClass = "NSNumber",
|
||||
members = members
|
||||
))
|
||||
|
||||
NSNumberKind.values().forEach {
|
||||
if (it.mappedKotlinClassId != null) {
|
||||
stubs += genKotlinNumber(it.mappedKotlinClassId, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun genKotlinNumber(kotlinClassId: ClassId, kind: NSNumberKind): ObjCInterface {
|
||||
val name = namer.numberBoxName(kotlinClassId)
|
||||
|
||||
val members = buildMembers {
|
||||
+nsNumberFactory(kind)
|
||||
+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 getClassIfExtension(receiverType: KotlinType): ClassDescriptor? =
|
||||
mapper.getClassIfCategory(receiverType)
|
||||
|
||||
internal fun translateUnexposedClassAsUnavailableStub(descriptor: ClassDescriptor): ObjCInterface = objCInterface(
|
||||
namer.getClassOrProtocolName(descriptor),
|
||||
descriptor = descriptor,
|
||||
superClass = "NSObject",
|
||||
attributes = listOf("unavailable(\"Kotlin subclass of Objective-C class can't be imported\")")
|
||||
attributes = attributesForUnexposed(descriptor)
|
||||
)
|
||||
|
||||
internal fun translateUnexposedInterfaceAsUnavailableStub(descriptor: ClassDescriptor): ObjCProtocol = objCProtocol(
|
||||
namer.getClassOrProtocolName(descriptor),
|
||||
descriptor = descriptor,
|
||||
superProtocols = emptyList(),
|
||||
members = emptyList(),
|
||||
attributes = attributesForUnexposed(descriptor)
|
||||
)
|
||||
|
||||
private fun attributesForUnexposed(descriptor: ClassDescriptor): List<String> {
|
||||
val message = when {
|
||||
descriptor.isKotlinObjCClass() -> "Kotlin subclass of Objective-C class "
|
||||
else -> ""
|
||||
} + "can't be imported"
|
||||
return listOf("unavailable(\"$message\")")
|
||||
}
|
||||
|
||||
private fun genericExportScope(classDescriptor: DeclarationDescriptor): ObjCExportScope {
|
||||
return if(objcGenerics && classDescriptor is ClassDescriptor && !classDescriptor.isInterface) {
|
||||
ObjCClassExportScope(classDescriptor, namer)
|
||||
@@ -105,6 +226,9 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
|
||||
override fun translateInterface(descriptor: ClassDescriptor): ObjCProtocol {
|
||||
require(mapper.shouldBeExposed(descriptor))
|
||||
require(descriptor.isInterface)
|
||||
|
||||
val name = translateClassOrInterfaceName(descriptor)
|
||||
val members: List<Stub<*>> = buildMembers { translateInterfaceMembers(descriptor) }
|
||||
val superProtocols: List<String> = descriptor.superProtocols
|
||||
@@ -133,7 +257,7 @@ internal class ObjCExportTranslatorImpl(
|
||||
val members = buildMembers {
|
||||
translatePlainMembers(declarations, ObjCNoneExportScope)
|
||||
}
|
||||
return ObjCInterface(name, categoryName = "Extensions", members = members)
|
||||
return ObjCInterfaceImpl(name, categoryName = "Extensions", members = members)
|
||||
}
|
||||
|
||||
override fun translateFile(file: SourceFile, declarations: List<CallableMemberDescriptor>): ObjCInterface {
|
||||
@@ -147,11 +271,13 @@ internal class ObjCExportTranslatorImpl(
|
||||
name,
|
||||
superClass = namer.kotlinAnyName.objCName,
|
||||
members = members,
|
||||
attributes = listOf("objc_subclassing_restricted")
|
||||
attributes = listOf(OBJC_SUBCLASSING_RESTRICTED)
|
||||
)
|
||||
}
|
||||
|
||||
override fun translateClass(descriptor: ClassDescriptor): ObjCInterface {
|
||||
require(mapper.shouldBeExposed(descriptor))
|
||||
require(!descriptor.isInterface)
|
||||
|
||||
val genericExportScope = genericExportScope(descriptor)
|
||||
|
||||
@@ -187,6 +313,7 @@ internal class ObjCExportTranslatorImpl(
|
||||
if (!descriptor.isArray) presentConstructors += selector
|
||||
|
||||
+buildMethod(it, it, genericExportScope)
|
||||
exportThrown(it)
|
||||
if (selector == "init") {
|
||||
+ObjCMethod(it, false, ObjCInstanceType, listOf("new"), emptyList(),
|
||||
listOf("availability(swift, unavailable, message=\"use object initializers instead\")"))
|
||||
@@ -244,7 +371,7 @@ internal class ObjCExportTranslatorImpl(
|
||||
translateClassMembers(descriptor)
|
||||
}
|
||||
|
||||
val attributes = if (descriptor.isFinalOrEnum) listOf("objc_subclassing_restricted") else emptyList()
|
||||
val attributes = if (descriptor.isFinalOrEnum) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
|
||||
|
||||
val name = translateClassOrInterfaceName(descriptor)
|
||||
|
||||
@@ -334,6 +461,8 @@ internal class ObjCExportTranslatorImpl(
|
||||
|
||||
members.toObjCMembers(methods, properties)
|
||||
|
||||
methods.forEach { exportThrown(it) }
|
||||
|
||||
collectMethodsOrProperties(methods) { it -> buildAsDeclaredOrInheritedMethods(it.original) }
|
||||
collectMethodsOrProperties(properties) { it -> buildAsDeclaredOrInheritedProperties(it.original) }
|
||||
}
|
||||
@@ -346,6 +475,8 @@ internal class ObjCExportTranslatorImpl(
|
||||
|
||||
members.toObjCMembers(methods, properties)
|
||||
|
||||
methods.forEach { exportThrown(it) }
|
||||
|
||||
methods.retainAll { mapper.isBaseMethod(it) }
|
||||
|
||||
properties.retainAll {
|
||||
@@ -366,6 +497,8 @@ internal class ObjCExportTranslatorImpl(
|
||||
|
||||
members.toObjCMembers(methods, properties)
|
||||
|
||||
methods.forEach { exportThrown(it) }
|
||||
|
||||
translatePlainMembers(methods, properties, objCExportScope)
|
||||
}
|
||||
|
||||
@@ -398,32 +531,29 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private val methodToSignatures = mutableMapOf<FunctionDescriptor, Set<RenderedStub<ObjCMethod>>>()
|
||||
private val propertyToSignatures = mutableMapOf<PropertyDescriptor, Set<RenderedStub<ObjCProperty>>>()
|
||||
|
||||
private fun buildAsDeclaredOrInheritedMethods(
|
||||
method: FunctionDescriptor
|
||||
): Set<RenderedStub<ObjCMethod>> = methodToSignatures.getOrPut(method) {
|
||||
): Set<RenderedStub<ObjCMethod>> {
|
||||
val isInterface = (method.containingDeclaration as ClassDescriptor).isInterface
|
||||
|
||||
mapper.getBaseMethods(method)
|
||||
return mapper.getBaseMethods(method)
|
||||
.asSequence()
|
||||
.distinctBy { namer.getSelector(it) }
|
||||
.map { base -> buildMethod((if (isInterface) base else method), base, genericExportScope(method.containingDeclaration)) }
|
||||
.map { method -> RenderedStub(method) }
|
||||
.map { RenderedStub(it) }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
private fun buildAsDeclaredOrInheritedProperties(
|
||||
property: PropertyDescriptor
|
||||
): Set<RenderedStub<ObjCProperty>> = propertyToSignatures.getOrPut(property) {
|
||||
): Set<RenderedStub<ObjCProperty>> {
|
||||
val isInterface = (property.containingDeclaration as ClassDescriptor).isInterface
|
||||
|
||||
mapper.getBaseProperties(property)
|
||||
return mapper.getBaseProperties(property)
|
||||
.asSequence()
|
||||
.distinctBy { namer.getPropertyName(it) }
|
||||
.map { base -> buildProperty((if (isInterface) base else property), base, genericExportScope(property.containingDeclaration)) }
|
||||
.map { property -> RenderedStub(property) }
|
||||
.map { RenderedStub(it) }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
@@ -514,8 +644,6 @@ internal class ObjCExportTranslatorImpl(
|
||||
|
||||
val baseMethodBridge = mapper.bridgeMethod(baseMethod)
|
||||
|
||||
exportThrownFromThisAndOverridden(method)
|
||||
|
||||
val isInstanceMethod: Boolean = baseMethodBridge.isInstance
|
||||
val returnType: ObjCType = mapReturnType(baseMethodBridge.returnBridge, method, objCExportScope)
|
||||
val parameters = collectParameters(baseMethodBridge, method)
|
||||
@@ -541,12 +669,8 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private val methodsWithThrowAnnotationConsidered = mutableSetOf<FunctionDescriptor>()
|
||||
|
||||
private val uncheckedExceptionClasses = listOf("Error", "RuntimeException").map {
|
||||
builtIns.builtInsPackageScope
|
||||
.getContributedClassifier(Name.identifier(it), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
}
|
||||
private val uncheckedExceptionClasses =
|
||||
listOf("kotlin.Error", "kotlin.RuntimeException").map { ClassId.topLevel(FqName(it)) }
|
||||
|
||||
private fun exportThrown(method: FunctionDescriptor) {
|
||||
if (!method.kind.isReal) return
|
||||
@@ -557,14 +681,11 @@ internal class ObjCExportTranslatorImpl(
|
||||
"@${KonanFqNames.throws.shortName()} annotation should also be added to a base method")
|
||||
}
|
||||
|
||||
if (method in methodsWithThrowAnnotationConsidered) return
|
||||
methodsWithThrowAnnotationConsidered += method
|
||||
|
||||
val arguments = (throwsAnnotation.allValueArguments.values.single() as ArrayValue).value
|
||||
for (argument in arguments) {
|
||||
val classDescriptor = TypeUtils.getClassDescriptor((argument as KClassValue).getArgumentType(method.module)) ?: continue
|
||||
|
||||
uncheckedExceptionClasses.firstOrNull { classDescriptor.isSubclassOf(it) }?.let {
|
||||
classDescriptor.getAllSuperClassifiers().firstOrNull { it.classId in uncheckedExceptionClasses }?.let {
|
||||
warningCollector.reportWarning(method,
|
||||
"Method is declared to throw ${classDescriptor.fqNameSafe}, " +
|
||||
"but instances of ${it.fqNameSafe} and its subclasses aren't propagated " +
|
||||
@@ -575,10 +696,6 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun exportThrownFromThisAndOverridden(method: FunctionDescriptor) {
|
||||
method.allOverriddenDescriptors.forEach { exportThrown(it) }
|
||||
}
|
||||
|
||||
private fun mapReturnType(returnBridge: MethodBridge.ReturnValue, method: FunctionDescriptor, objCExportScope: ObjCExportScope): ObjCType = when (returnBridge) {
|
||||
MethodBridge.ReturnValue.Void -> ObjCVoidType
|
||||
MethodBridge.ReturnValue.HashCode -> ObjCPrimitiveType("NSUInteger")
|
||||
@@ -650,7 +767,7 @@ internal class ObjCExportTranslatorImpl(
|
||||
// TODO: translate `where T : BaseClass, T : SomeInterface` to `BaseClass* <SomeInterface>`
|
||||
|
||||
// TODO: expose custom inline class boxes properly.
|
||||
if (classDescriptor == builtIns.any || classDescriptor.classId in mapper.hiddenTypes || classDescriptor.isInlined()) {
|
||||
if (isAny(classDescriptor) || classDescriptor.classId in mapper.hiddenTypes || classDescriptor.isInlined()) {
|
||||
return ObjCIdType
|
||||
}
|
||||
|
||||
@@ -719,7 +836,7 @@ internal class ObjCExportTranslatorImpl(
|
||||
objCExportScope: ObjCExportScope,
|
||||
typeBridge: BlockPointerBridge
|
||||
): ObjCReferenceType {
|
||||
val expectedDescriptor = builtIns.getFunction(typeBridge.numberOfParameters)
|
||||
val expectedDescriptor = kotlinType.builtIns.getFunction(typeBridge.numberOfParameters)
|
||||
|
||||
// Somewhat similar to mapType:
|
||||
val functionType = if (TypeUtils.getClassDescriptor(kotlinType) == expectedDescriptor) {
|
||||
@@ -759,7 +876,6 @@ internal class ObjCExportTranslatorImpl(
|
||||
|
||||
abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
val moduleDescriptors: List<ModuleDescriptor>,
|
||||
val builtIns: KotlinBuiltIns,
|
||||
internal val mapper: ObjCExportMapper,
|
||||
val namer: ObjCExportNamer,
|
||||
val objcGenerics:Boolean = false
|
||||
@@ -778,7 +894,6 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
mapper: ObjCExportMapper
|
||||
) : this(
|
||||
moduleDescriptors,
|
||||
builtIns,
|
||||
mapper,
|
||||
ObjCExportNamerImpl(moduleDescriptors.toSet(), builtIns, mapper, topLevelNamePrefix, local = false)
|
||||
)
|
||||
@@ -802,7 +917,7 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
private val protocolForwardDeclarations = linkedSetOf<String>()
|
||||
private val extraClassesToTranslate = mutableSetOf<ClassDescriptor>()
|
||||
|
||||
private val translator = ObjCExportTranslatorImpl(this, builtIns, mapper, namer,
|
||||
private val translator = ObjCExportTranslatorImpl(this, mapper, namer,
|
||||
object : ObjCExportWarningCollector {
|
||||
override fun reportWarning(text: String) =
|
||||
this@ObjCExportHeaderGenerator.reportWarning(text)
|
||||
@@ -866,38 +981,7 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
// TODO: make the translation order stable
|
||||
// to stabilize name mangling.
|
||||
|
||||
stubs.add(objCInterface(namer.kotlinAnyName, superClass = "NSObject", members = buildMembers {
|
||||
+ObjCMethod(null, true, ObjCInstanceType, listOf("init"), emptyList(), listOf("unavailable"))
|
||||
+ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable"))
|
||||
+ObjCMethod(null, false, ObjCVoidType, listOf("initialize"), emptyList(), listOf("objc_requires_super"))
|
||||
}))
|
||||
|
||||
// TODO: add comment to the header.
|
||||
stubs.add(ObjCInterface(
|
||||
namer.kotlinAnyName.objCName,
|
||||
superProtocols = listOf("NSCopying"),
|
||||
categoryName = "${namer.kotlinAnyName.objCName}Copying"
|
||||
))
|
||||
|
||||
// TODO: only if appears
|
||||
stubs.add(objCInterface(
|
||||
namer.mutableSetName,
|
||||
generics = listOf("ObjectType"),
|
||||
superClass = "NSMutableSet<ObjectType>"
|
||||
))
|
||||
|
||||
// TODO: only if appears
|
||||
stubs.add(objCInterface(
|
||||
namer.mutableMapName,
|
||||
generics = listOf("KeyType", "ObjectType"),
|
||||
superClass = "NSMutableDictionary<KeyType, ObjectType>"
|
||||
))
|
||||
|
||||
stubs.add(ObjCInterface("NSError", categoryName = "NSErrorKotlinException", members = buildMembers {
|
||||
+ObjCProperty("kotlinException", null, ObjCNullableReferenceType(ObjCIdType), listOf("readonly"))
|
||||
}))
|
||||
|
||||
genKotlinNumbers()
|
||||
stubs += translator.generateBaseDeclarations()
|
||||
|
||||
val packageFragments = moduleDescriptors.flatMap { it.getPackageFragments() }
|
||||
|
||||
@@ -930,9 +1014,12 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
}
|
||||
|
||||
it.unsubstitutedMemberScope.translateClasses()
|
||||
} else if (it.isKotlinObjCClass() && mapper.shouldBeVisible(it)) {
|
||||
assert(!it.isInterface)
|
||||
stubs += translator.translateKotlinObjCClassAsUnavailableStub(it)
|
||||
} else if (mapper.shouldBeVisible(it)) {
|
||||
stubs += if (it.isInterface) {
|
||||
translator.translateUnexposedInterfaceAsUnavailableStub(it)
|
||||
} else {
|
||||
translator.translateUnexposedClassAsUnavailableStub(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -962,64 +1049,6 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
return stubs
|
||||
}
|
||||
|
||||
private fun genKotlinNumbers() {
|
||||
val members = buildMembers {
|
||||
NSNumberKind.values().forEach {
|
||||
+nsNumberFactory(it, listOf("unavailable"))
|
||||
}
|
||||
NSNumberKind.values().forEach {
|
||||
+nsNumberInit(it, listOf("unavailable"))
|
||||
}
|
||||
}
|
||||
stubs.add(objCInterface(
|
||||
namer.kotlinNumberName,
|
||||
superClass = "NSNumber",
|
||||
members = members
|
||||
))
|
||||
|
||||
NSNumberKind.values().forEach {
|
||||
if (it.mappedKotlinClassId != null) {
|
||||
stubs += genKotlinNumber(it.mappedKotlinClassId, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun genKotlinNumber(kotlinClassId: ClassId, kind: NSNumberKind): ObjCInterface {
|
||||
val name = namer.numberBoxName(kotlinClassId)
|
||||
|
||||
val members = buildMembers {
|
||||
+nsNumberFactory(kind)
|
||||
+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
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateFile(sourceFile: SourceFile, declarations: List<CallableMemberDescriptor>) {
|
||||
stubs.add(translator.translateFile(sourceFile, declarations))
|
||||
}
|
||||
@@ -1062,7 +1091,7 @@ private fun objCInterface(
|
||||
superProtocols: List<String> = emptyList(),
|
||||
members: List<Stub<*>> = emptyList(),
|
||||
attributes: List<String> = emptyList()
|
||||
): ObjCInterface = ObjCInterface(
|
||||
): ObjCInterface = ObjCInterfaceImpl(
|
||||
name.objCName,
|
||||
generics,
|
||||
descriptor,
|
||||
@@ -1080,7 +1109,7 @@ private fun objCProtocol(
|
||||
superProtocols: List<String>,
|
||||
members: List<Stub<*>>,
|
||||
attributes: List<String> = emptyList()
|
||||
): ObjCProtocol = ObjCProtocol(
|
||||
): ObjCProtocol = ObjCProtocolImpl(
|
||||
name.objCName,
|
||||
descriptor,
|
||||
superProtocols,
|
||||
@@ -1088,7 +1117,7 @@ private fun objCProtocol(
|
||||
attributes + name.toNameAttributes()
|
||||
)
|
||||
|
||||
private fun ObjCExportNamer.ClassOrProtocolName.toNameAttributes(): List<String> = listOfNotNull(
|
||||
internal fun ObjCExportNamer.ClassOrProtocolName.toNameAttributes(): List<String> = listOfNotNull(
|
||||
binaryName.takeIf { it != objCName }?.let { objcRuntimeNameAttribute(it) },
|
||||
swiftName.takeIf { it != objCName }?.let { swiftNameAttribute(it) }
|
||||
)
|
||||
@@ -1131,4 +1160,6 @@ internal fun Variance.objcDeclaration():String = when(this){
|
||||
else -> ""
|
||||
}
|
||||
|
||||
private fun computeSuperClassType(descriptor: ClassDescriptor): KotlinType? = descriptor.typeConstructor.supertypes.filter { !it.isInterface() }.firstOrNull()
|
||||
private fun computeSuperClassType(descriptor: ClassDescriptor): KotlinType? = descriptor.typeConstructor.supertypes.filter { !it.isInterface() }.firstOrNull()
|
||||
|
||||
internal const val OBJC_SUBCLASSING_RESTRICTED = "objc_subclassing_restricted"
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ internal class ObjCExportHeaderGeneratorImpl(
|
||||
mapper: ObjCExportMapper,
|
||||
namer: ObjCExportNamer,
|
||||
objcGenerics: Boolean
|
||||
) : ObjCExportHeaderGenerator(moduleDescriptors, context.builtIns, mapper, namer, objcGenerics) {
|
||||
) : ObjCExportHeaderGenerator(moduleDescriptors, mapper, namer, objcGenerics) {
|
||||
|
||||
override fun reportWarning(text: String) {
|
||||
context.reportCompilationWarning(text)
|
||||
|
||||
+6
-2
@@ -46,6 +46,10 @@ internal fun ObjCExportMapper.getClassIfCategory(descriptor: CallableMemberDescr
|
||||
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return null
|
||||
|
||||
return getClassIfCategory(extensionReceiverType)
|
||||
}
|
||||
|
||||
internal fun ObjCExportMapper.getClassIfCategory(extensionReceiverType: KotlinType): ClassDescriptor? {
|
||||
// FIXME: this code must rely on type mapping instead of copying its logic.
|
||||
|
||||
if (extensionReceiverType.isObjCObjectType()) return null
|
||||
@@ -63,13 +67,13 @@ internal fun ObjCExportMapper.shouldBeExposed(descriptor: CallableMemberDescript
|
||||
descriptor.isEffectivelyPublicApi && !descriptor.isSuspend && !descriptor.isExpect
|
||||
|
||||
internal fun ObjCExportMapper.shouldBeExposed(descriptor: ClassDescriptor): Boolean =
|
||||
shouldBeVisible(descriptor) && !descriptor.defaultType.isObjCObjectType()
|
||||
shouldBeVisible(descriptor) && !isSpecialMapped(descriptor) && !descriptor.defaultType.isObjCObjectType()
|
||||
|
||||
internal fun ObjCExportMapper.shouldBeVisible(descriptor: ClassDescriptor): Boolean =
|
||||
descriptor.isEffectivelyPublicApi && when (descriptor.kind) {
|
||||
ClassKind.CLASS, ClassKind.INTERFACE, ClassKind.ENUM_CLASS, ClassKind.OBJECT -> true
|
||||
ClassKind.ENUM_ENTRY, ClassKind.ANNOTATION_CLASS -> false
|
||||
} && !descriptor.isExpect && !isSpecialMapped(descriptor) && !descriptor.isInlined()
|
||||
} && !descriptor.isExpect && !descriptor.isInlined()
|
||||
|
||||
private fun ObjCExportMapper.isBase(descriptor: CallableMemberDescriptor): Boolean =
|
||||
descriptor.overriddenDescriptors.all { !shouldBeExposed(it) }
|
||||
|
||||
+87
-29
@@ -23,6 +23,12 @@ import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
||||
interface ObjCExportNamer {
|
||||
data class ClassOrProtocolName(val swiftName: String, val objCName: String, val binaryName: String = objCName)
|
||||
|
||||
interface Configuration {
|
||||
val topLevelNamePrefix: String
|
||||
fun getAdditionalPrefix(module: ModuleDescriptor): String?
|
||||
val objcGenerics: Boolean
|
||||
}
|
||||
|
||||
fun getFileClassName(file: SourceFile): ClassOrProtocolName
|
||||
fun getClassOrProtocolName(descriptor: ClassDescriptor): ClassOrProtocolName
|
||||
fun getSelector(method: FunctionDescriptor): String
|
||||
@@ -57,16 +63,42 @@ fun createNamer(
|
||||
)
|
||||
|
||||
internal class ObjCExportNamerImpl(
|
||||
private val moduleDescriptors: Set<ModuleDescriptor>,
|
||||
private val configuration: ObjCExportNamer.Configuration,
|
||||
builtIns: KotlinBuiltIns,
|
||||
private val mapper: ObjCExportMapper,
|
||||
private val topLevelNamePrefix: String,
|
||||
private val local: Boolean,
|
||||
private val objcGenerics: Boolean = false
|
||||
private val local: Boolean
|
||||
) : ObjCExportNamer {
|
||||
|
||||
constructor(
|
||||
moduleDescriptors: Set<ModuleDescriptor>,
|
||||
builtIns: KotlinBuiltIns,
|
||||
mapper: ObjCExportMapper,
|
||||
topLevelNamePrefix: String,
|
||||
local: Boolean,
|
||||
objcGenerics: Boolean = false
|
||||
) : this(
|
||||
object : ObjCExportNamer.Configuration {
|
||||
override val topLevelNamePrefix: String
|
||||
get() = topLevelNamePrefix
|
||||
|
||||
override fun getAdditionalPrefix(module: ModuleDescriptor): String? =
|
||||
if (module in moduleDescriptors) null else module.namePrefix
|
||||
|
||||
override val objcGenerics: Boolean
|
||||
get() = objcGenerics
|
||||
|
||||
},
|
||||
builtIns,
|
||||
mapper,
|
||||
local
|
||||
)
|
||||
|
||||
private fun String.toUnmangledClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName =
|
||||
ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = this)
|
||||
|
||||
private val objcGenerics get() = configuration.objcGenerics
|
||||
private val topLevelNamePrefix get() = configuration.topLevelNamePrefix
|
||||
|
||||
private fun String.toSpecialStandardClassOrProtocolName() = ObjCExportNamer.ClassOrProtocolName(
|
||||
swiftName = "Kotlin$this",
|
||||
objCName = "${topLevelNamePrefix}$this",
|
||||
@@ -174,18 +206,11 @@ internal class ObjCExportNamerImpl(
|
||||
return ObjCExportNamer.ClassOrProtocolName(swiftName = swiftName, objCName = objCName)
|
||||
}
|
||||
|
||||
private val predefinedClassNames = mapOf(
|
||||
builtIns.any to kotlinAnyName,
|
||||
builtIns.mutableSet to mutableSetName,
|
||||
builtIns.mutableMap to mutableMapName
|
||||
)
|
||||
|
||||
override fun getClassOrProtocolName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName =
|
||||
predefinedClassNames[descriptor]
|
||||
?: ObjCExportNamer.ClassOrProtocolName(
|
||||
swiftName = getClassOrProtocolSwiftName(descriptor),
|
||||
objCName = getClassOrProtocolObjCName(descriptor)
|
||||
)
|
||||
ObjCExportNamer.ClassOrProtocolName(
|
||||
swiftName = getClassOrProtocolSwiftName(descriptor),
|
||||
objCName = getClassOrProtocolObjCName(descriptor)
|
||||
)
|
||||
|
||||
private fun getClassOrProtocolSwiftName(
|
||||
descriptor: ClassDescriptor
|
||||
@@ -260,8 +285,8 @@ internal class ObjCExportNamerImpl(
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendTopLevelClassBaseName(descriptor: ClassDescriptor) = apply {
|
||||
if (descriptor.module !in moduleDescriptors) {
|
||||
append(descriptor.module.namePrefix)
|
||||
configuration.getAdditionalPrefix(descriptor.module)?.let {
|
||||
append(it)
|
||||
}
|
||||
append(descriptor.name.asString())
|
||||
}
|
||||
@@ -269,6 +294,8 @@ internal class ObjCExportNamerImpl(
|
||||
override fun getSelector(method: FunctionDescriptor): String = methodSelectors.getOrPut(method) {
|
||||
assert(mapper.isBaseMethod(method))
|
||||
|
||||
getPredefined(method, Predefined.anyMethodSelectors)?.let { return it }
|
||||
|
||||
val parameters = mapper.bridgeMethod(method).valueParametersAssociated(method)
|
||||
|
||||
StringBuilder().apply {
|
||||
@@ -317,6 +344,8 @@ internal class ObjCExportNamerImpl(
|
||||
override fun getSwiftName(method: FunctionDescriptor): String = methodSwiftNames.getOrPut(method) {
|
||||
assert(mapper.isBaseMethod(method))
|
||||
|
||||
getPredefined(method, Predefined.anyMethodSwiftNames)?.let { return it }
|
||||
|
||||
val parameters = mapper.bridgeMethod(method).valueParametersAssociated(method)
|
||||
|
||||
StringBuilder().apply {
|
||||
@@ -349,6 +378,14 @@ internal class ObjCExportNamerImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Any> getPredefined(method: FunctionDescriptor, predefinedForAny: Map<Name, T>): T? {
|
||||
return if (method.containingDeclaration.let { it is ClassDescriptor && KotlinBuiltIns.isAny(it) }) {
|
||||
predefinedForAny.getValue(method.name)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPropertyName(property: PropertyDescriptor): String = propertyNames.getOrPut(property) {
|
||||
assert(mapper.isBaseProperty(property))
|
||||
assert(mapper.isObjCProperty(property))
|
||||
@@ -395,31 +432,52 @@ internal class ObjCExportNamerImpl(
|
||||
}
|
||||
|
||||
init {
|
||||
if (!local) {
|
||||
forceAssignPredefined(builtIns)
|
||||
}
|
||||
}
|
||||
|
||||
private fun forceAssignPredefined(builtIns: KotlinBuiltIns) {
|
||||
val any = builtIns.any
|
||||
|
||||
val predefinedClassNames = mapOf(
|
||||
builtIns.any to kotlinAnyName,
|
||||
builtIns.mutableSet to mutableSetName,
|
||||
builtIns.mutableMap to mutableMapName
|
||||
)
|
||||
|
||||
predefinedClassNames.forEach { descriptor, name ->
|
||||
objCClassNames.forceAssign(descriptor, name.objCName)
|
||||
swiftClassAndProtocolNames.forceAssign(descriptor, name.swiftName)
|
||||
}
|
||||
|
||||
fun ClassDescriptor.method(name: String) =
|
||||
fun ClassDescriptor.method(name: Name) =
|
||||
this.unsubstitutedMemberScope.getContributedFunctions(
|
||||
Name.identifier(name),
|
||||
name,
|
||||
NoLookupLocation.FROM_BACKEND
|
||||
).single()
|
||||
|
||||
val hashCode = any.method("hashCode")
|
||||
val toString = any.method("toString")
|
||||
val equals = any.method("equals")
|
||||
Predefined.anyMethodSelectors.forEach { name, selector ->
|
||||
methodSelectors.forceAssign(any.method(name), selector)
|
||||
}
|
||||
|
||||
methodSelectors.forceAssign(hashCode, "hash")
|
||||
methodSwiftNames.forceAssign(hashCode, "hash()")
|
||||
Predefined.anyMethodSwiftNames.forEach { name, swiftName ->
|
||||
methodSwiftNames.forceAssign(any.method(name), swiftName)
|
||||
}
|
||||
}
|
||||
|
||||
methodSelectors.forceAssign(toString, "description")
|
||||
methodSwiftNames.forceAssign(toString, "description()")
|
||||
private object Predefined {
|
||||
val anyMethodSelectors = mapOf(
|
||||
"hashCode" to "hash",
|
||||
"toString" to "description",
|
||||
"equals" to "isEqual:"
|
||||
).mapKeys { Name.identifier(it.key) }
|
||||
|
||||
methodSelectors.forceAssign(equals, "isEqual:")
|
||||
methodSwiftNames.forceAssign(equals, "isEqual(_:)")
|
||||
val anyMethodSwiftNames = mapOf(
|
||||
"hashCode" to "hash()",
|
||||
"toString" to "description()",
|
||||
"equals" to "isEqual(_:)"
|
||||
).mapKeys { Name.identifier(it.key) }
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getMangledName(forSwift: Boolean): String {
|
||||
@@ -519,7 +577,7 @@ internal class ObjCExportNamerImpl(
|
||||
|
||||
abstract fun conflict(first: T, second: T): Boolean
|
||||
open fun reserved(name: N) = false
|
||||
fun getOrPut(element: T, nameCandidates: () -> Sequence<N>): N {
|
||||
inline fun getOrPut(element: T, nameCandidates: () -> Sequence<N>): N {
|
||||
getIfAssigned(element)?.let { return it }
|
||||
|
||||
nameCandidates().forEach {
|
||||
|
||||
+43
-25
@@ -10,48 +10,66 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
|
||||
open class Stub<out D : DeclarationDescriptor>(val name: String, val descriptor: D?)
|
||||
abstract class Stub<out D : DeclarationDescriptor>(val name: String) {
|
||||
abstract val descriptor: D?
|
||||
}
|
||||
|
||||
abstract class ObjCTopLevel<out D : DeclarationDescriptor>(name: String) : Stub<D>(name)
|
||||
|
||||
abstract class ObjCClass<out D : DeclarationDescriptor>(name: String,
|
||||
descriptor: D?,
|
||||
val superProtocols: List<String>,
|
||||
val members: List<Stub<*>>,
|
||||
val attributes: List<String>) : Stub<D>(name, descriptor)
|
||||
val attributes: List<String>) : ObjCTopLevel<D>(name) {
|
||||
abstract val superProtocols: List<String>
|
||||
abstract val members: List<Stub<*>>
|
||||
}
|
||||
|
||||
class ObjCProtocol(name: String,
|
||||
descriptor: ClassDescriptor,
|
||||
superProtocols: List<String>,
|
||||
members: List<Stub<*>>,
|
||||
attributes: List<String> = emptyList()) : ObjCClass<ClassDescriptor>(name, descriptor, superProtocols, members, attributes)
|
||||
abstract class ObjCProtocol(name: String,
|
||||
attributes: List<String>) : ObjCClass<ClassDescriptor>(name, attributes)
|
||||
|
||||
class ObjCInterface(name: String,
|
||||
val generics: List<String> = emptyList(),
|
||||
descriptor: ClassDescriptor? = null,
|
||||
val superClass: String? = null,
|
||||
val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
|
||||
superProtocols: List<String> = emptyList(),
|
||||
val categoryName: String? = null,
|
||||
members: List<Stub<*>> = emptyList(),
|
||||
attributes: List<String> = emptyList()) : ObjCClass<ClassDescriptor>(name, descriptor, superProtocols, members, attributes)
|
||||
class ObjCProtocolImpl(
|
||||
name: String,
|
||||
override val descriptor: ClassDescriptor,
|
||||
override val superProtocols: List<String>,
|
||||
override val members: List<Stub<*>>,
|
||||
attributes: List<String> = emptyList()) : ObjCProtocol(name, attributes)
|
||||
|
||||
class ObjCMethod(descriptor: DeclarationDescriptor?,
|
||||
abstract class ObjCInterface(name: String,
|
||||
val generics: List<String>,
|
||||
val categoryName: String?,
|
||||
attributes: List<String>) : ObjCClass<ClassDescriptor>(name, attributes) {
|
||||
abstract val superClass: String?
|
||||
abstract val superClassGenerics: List<ObjCNonNullReferenceType>
|
||||
}
|
||||
|
||||
class ObjCInterfaceImpl(
|
||||
name: String,
|
||||
generics: List<String> = emptyList(),
|
||||
override val descriptor: ClassDescriptor? = null,
|
||||
override val superClass: String? = null,
|
||||
override val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
|
||||
override val superProtocols: List<String> = emptyList(),
|
||||
categoryName: String? = null,
|
||||
override val members: List<Stub<*>> = emptyList(),
|
||||
attributes: List<String> = emptyList()
|
||||
) : ObjCInterface(name, generics, categoryName, attributes)
|
||||
|
||||
class ObjCMethod(override val descriptor: DeclarationDescriptor?,
|
||||
val isInstanceMethod: Boolean,
|
||||
val returnType: ObjCType,
|
||||
val selectors: List<String>,
|
||||
val parameters: List<ObjCParameter>,
|
||||
val attributes: List<String>) : Stub<DeclarationDescriptor>(buildMethodName(selectors, parameters), descriptor)
|
||||
val attributes: List<String>) : Stub<DeclarationDescriptor>(buildMethodName(selectors, parameters))
|
||||
|
||||
class ObjCParameter(name: String,
|
||||
descriptor: ParameterDescriptor?,
|
||||
val type: ObjCType) : Stub<ParameterDescriptor>(name, descriptor)
|
||||
override val descriptor: ParameterDescriptor?,
|
||||
val type: ObjCType) : Stub<ParameterDescriptor>(name)
|
||||
|
||||
class ObjCProperty(name: String,
|
||||
descriptor: PropertyDescriptor?,
|
||||
override val descriptor: PropertyDescriptor?,
|
||||
val type: ObjCType,
|
||||
val propertyAttributes: List<String>,
|
||||
val setterName: String? = null,
|
||||
val getterName: String? = null,
|
||||
val declarationAttributes: List<String> = emptyList()) : Stub<PropertyDescriptor>(name, descriptor) {
|
||||
val declarationAttributes: List<String> = emptyList()) : Stub<PropertyDescriptor>(name) {
|
||||
|
||||
@Deprecated("", ReplaceWith("this.propertyAttributes"), DeprecationLevel.WARNING)
|
||||
val attributes: List<String> get() = propertyAttributes
|
||||
|
||||
@@ -421,3 +421,5 @@ object UnitBlockCoercionImpl : UnitBlockCoercion<() -> Unit> {
|
||||
override fun coerce(block: () -> Unit): () -> Unit = block
|
||||
override fun uncoerce(block: () -> Unit): () -> Unit = block
|
||||
}
|
||||
|
||||
abstract class MyAbstractList : List<Any?>
|
||||
|
||||
Reference in New Issue
Block a user