Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ internal fun ObjCExportedInterface.createCodeSpec(symbolTable: SymbolTable): Obj

if (descriptor.kind == ClassKind.ENUM_CLASS) {
descriptor.enumEntries.mapTo(methods) {
ObjCGetterForKotlinEnumEntry(symbolTable.descriptorExtension.referenceEnumEntry(it), namer.getEnumEntrySelector(it))
ObjCGetterForKotlinEnumEntry(
symbolTable.descriptorExtension.referenceEnumEntry(it),
namer.getEnumEntryName(it).objCName)
}

descriptor.getEnumValuesFunctionDescriptor()?.let {
Expand Down Expand Up @@ -133,7 +135,7 @@ internal fun <S : IrFunctionSymbol> createObjCMethodSpecBaseMethod(
): ObjCMethodSpec.BaseMethod<S> {
require(mapper.isBaseMethod(descriptor))

val selector = namer.getSelector(descriptor)
val selector = namer.getFunctionName(descriptor).objCName
val bridge = mapper.bridgeMethod(descriptor)

return ObjCMethodSpec.BaseMethod(symbol, bridge, selector)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal val KtObjCExportSession.errorInterface
returnType = ObjCInstanceType,
selectors = listOf("init"),
parameters = emptyList(),
attributes = listOf("swift_name(\"init()\")", "objc_designated_initializer")
attributes = listOf("objc_designated_initializer")
),
ObjCMethod(
comment = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.jetbrains.kotlin.objcexport.getObjCKotlinStdlibClassOrProtocolName
* Some entities like top level functions are wrapped into classes with Base super class.
*
* @interface FooKt : Base
* + (NSString *)myTopLevelFunction __attribute__((swift_name("myTopLevelFunction()")));
* + (NSString *)myTopLevelFunction;
* @end
*/
internal fun KtObjCExportSession.getDefaultSuperClassOrProtocolName(): ObjCExportClassOrProtocolName {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ internal fun ObjCExportContext.buildCompanionProperty(classSymbol: KaClassSymbol
}),
propertyAttributes = listOf("class", "readonly"),
getterName = propertyName,
declarationAttributes = listOf(swiftNameAttribute(propertyName))
declarationAttributes = emptyList(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal fun buildThrowableAsErrorMethod(): ObjCMethod {
returnType = ObjCClassType("NSError"),
selectors = listOf("asError"),
parameters = emptyList(),
attributes = listOf(swiftNameAttribute("asError()")),
attributes = emptyList(),
origin = null
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,35 @@ import org.jetbrains.kotlin.backend.konan.objcexport.swiftNameAttribute
*/
internal class ObjCMethodMangler {

private val mangledMethods = mutableMapOf<String, ObjCMemberDetails>()
private val mangledMethods = mutableSetOf<String>()

fun mangle(member: ObjCExportStub, containingStub: ObjCExportStub): ObjCExportStub {
if (!member.isSwiftNameMethod()) return member
require(member is ObjCMethod)
if (!contains(member)) {
cacheMember(member)
return member
} else {
val key = getMemberKey(member)
val attribute = mangledMethods[key] ?: error("No cached item for $member")
val mangledAttribute = attribute.mangleAttribute()
val cloned = member.copy(
mangledSelectors = buildMangledSelectors(mangledAttribute),
mangledParameters = buildMangledParameters(mangledAttribute),
swiftNameAttribute = buildMangledSwiftNameMethodAttribute(mangledAttribute, containingStub),
containingStubName = containingStub.name
)
mangledMethods[key] = mangledAttribute
return cloned
if (member is ObjCMethod) {
var cloned: ObjCMethod = member
while (true) {
val key = getMemberKey(cloned)
if (!mangledMethods.contains(key)) {
mangledMethods.add(key)
return cloned
}
val newSelectors = cloned.selectors.toMutableList()
val lastIndex = newSelectors.lastIndex
var lastSelector = newSelectors[lastIndex]
if (lastSelector.endsWith(":")) {
// - (void)foo:; -> -(void)foo_:;
// - (void)foo:bar:; -> -(void)foo:bar_:;
lastSelector = lastSelector.dropLast(1) + "_:"
} else {
// - (void)foo; -> -(void)foo_;
lastSelector += "_"
}
newSelectors[lastIndex] = lastSelector
cloned = member.copy(
mangledSelectors = newSelectors,
containingStubName = containingStub.name
)
}
}
}

private fun contains(member: ObjCExportStub): Boolean {
if (!member.isSwiftNameMethod()) return false
return mangledMethods[getMemberKey(member as ObjCMethod)] != null
}

private fun cacheMember(member: ObjCMethod) {
val memberKey = getMemberKey(member)
val swiftNameAttr = getSwiftNameAttribute(member)
mangledMethods[memberKey] = parseSwiftMethodNameAttribute(swiftNameAttr, member.returnType == ObjCInstanceType, member.parameters)
return member
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,33 @@ class ObjCPropertyMangler {
private val mangledProperties = hashSetOf<String>()

fun mangle(member: ObjCExportStub, containingStub: ObjCExportStub): ObjCExportStub {
return if (member.isSwiftNameProperty()) {
val key = getSwiftNameAttribute(member as ObjCProperty)
if (mangledProperties.contains(key)) {
return if (member is ObjCProperty) {
val name = member.name
if (mangledProperties.contains(name)) {
val copy = if (containingStub.isExtensionFacade) {
val attr = parseSwiftPropertyNameAttribute(getSwiftNameAttribute(member))
member.copy(
name = member.name + "_",
name = name + "_",
propertyAttributes = null,
declarationAttributes = listOf(buildMangledSwiftNamePropertyAttribute(attr.mangleAttribute()))
declarationAttributes = null
)
} else {
member.copy(
name = member.name,
propertyAttributes = "getter=${member.name}_",
name = name,
propertyAttributes = "getter=${name}_",
declarationAttributes = null
)
}
mangledProperties.add(getSwiftNameAttribute(copy))
copy
} else {
mangledProperties.add(key)
mangledProperties.add(name)
member
}
} else if (member.isSwiftNameMethod()) {
mangledProperties.add(getSwiftNameAttribute(member as ObjCMethod).replace("()", ""))
} else if (member is ObjCMethod && member.selectors.size == 1 && member.parameters.isEmpty()) {
mangledProperties.add(member.selectors[0])
member
} else {
// Leave it as it is since it is neither property, nor method
member
}
}
}

private fun buildMangledSwiftNamePropertyAttribute(attribute: ObjCMemberDetails): String {
return "swift_name(\"${attribute.name + attribute.postfix}\")"
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,12 @@ internal fun ObjCProperty.copy(
*/
internal fun ObjCMethod.copy(
mangledSelectors: List<String>,
mangledParameters: List<String>,
swiftNameAttribute: String,
containingStubName: String,
): ObjCMethod {
val selectorsSize = mangledSelectors.size
val parametersSize = this.parameters.size
val methodName = this.name
require((selectorsSize == parametersSize) || (selectorsSize == 1 && mangledParameters.isEmpty())) {
require((selectorsSize == parametersSize) || (selectorsSize == 1 && parametersSize == 0)) {
"'$containingStubName.$methodName': selectors of doesn't match parameters count: " +
"selectors($mangledSelectors): $selectorsSize, " +
"parameters(${this.parameters.joinToString { it.name }}): $parametersSize"
Expand All @@ -47,9 +45,70 @@ internal fun ObjCMethod.copy(
selectors = mangledSelectors,
parameters = this.parameters,
attributes = this.attributes.map { attr ->
if (attr.startsWith("swift_name")) swiftNameAttribute else attr
if (attr.startsWith("swift_name")) remangledSwiftName(mangledSelectors, this.attributes) else attr
},
extras = this.extras
)
}

}
/**
* Create a swift name based on the selectors and attributes.
*/
internal fun ObjCMethod.remangledSwiftName(mangledSelectors: List<String>, attributes: List<String>): String {
fun isConstructor(attributes: List<String>) : Boolean {
return attributes.contains("objc_designated_initializer")
}

val swiftName = StringBuilder("swift_name(\"")
val count = if (mangledSelectors[0].endsWith(":")) mangledSelectors.size else mangledSelectors.size - 1
if (count == 0) {
// - (void)bar; -> bar()
swiftName.append(mangledSelectors[0] + "()")
} else {
val selector = mangledSelectors[0]
val lastUppercaseChar = selector.indexOfLast { it.isUpperCase() }
if (isConstructor(attributes)) {
// - (instancetype)initWithA:...; -> init(a:)
var prefix = selector.take(lastUppercaseChar)
if (prefix.endsWith("With")) {
prefix = prefix.dropLast(4)
}
swiftName.append(
prefix
+ "("
+ selector.substring(lastUppercaseChar).replaceFirstChar { it.lowercase() })
} else if (lastUppercaseChar == -1 && selector.endsWith("_:")) {
//- (Foo *)days_... -> days(__:...)
//- (Foo *)days__... -> days(___:...)
val index = selector.indexOf("_")
swiftName.append(selector.substring(0, index) + "(")
for (i in index until selector.length) {
swiftName.append("_")
}
swiftName.append(":")
} else {
if (lastUppercaseChar == -1) {
// - (void)bar:; -> bar:(_)
swiftName.append(selector.dropLast(1) + "(_")
if (count > 1) {
// - (void)bar:...; -> bar:(_:...
swiftName.append(":")
}
} else {
// - (void)doBar:...; -> do(bar:...)
swiftName.append(
selector.take(lastUppercaseChar)
+ "("
+ selector.substring(lastUppercaseChar).replaceFirstChar { it.lowercase() })
}
}
if (count > 1) {
for (i in 1 until count) {
swiftName.append(mangledSelectors[i])
}
}
swiftName.append(")")
}
swiftName.append("\")")
return swiftName.toString()
}
Loading