[ObjCExport] Support naming of nested classes
^KT-65204 Fixed
This commit is contained in:
committed by
Space Team
parent
f1fd84f539
commit
4b6624c920
+95
-2
@@ -6,16 +6,109 @@
|
||||
package org.jetbrains.kotlin.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportClassOrProtocolName
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
fun KtClassLikeSymbol.getObjCClassOrProtocolName(): ObjCExportClassOrProtocolName {
|
||||
val resolvedObjCNameAnnotation = resolveObjCNameAnnotation()
|
||||
|
||||
return ObjCExportClassOrProtocolName(
|
||||
objCName = resolvedObjCNameAnnotation?.objCName ?: nameOrAnonymous.asString(),
|
||||
swiftName = resolvedObjCNameAnnotation?.swiftName ?: nameOrAnonymous.asString()
|
||||
objCName = getObjCName(resolvedObjCNameAnnotation),
|
||||
swiftName = getSwiftName(resolvedObjCNameAnnotation)
|
||||
)
|
||||
}
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassLikeSymbol.getObjCName(
|
||||
resolvedObjCNameAnnotation: KtResolvedObjCNameAnnotation? = resolveObjCNameAnnotation(),
|
||||
): String {
|
||||
val objCName = (resolvedObjCNameAnnotation?.objCName ?: nameOrAnonymous.asString()).toValidObjCSwiftIdentifier()
|
||||
|
||||
if (resolvedObjCNameAnnotation != null && resolvedObjCNameAnnotation.isExact) {
|
||||
return objCName
|
||||
}
|
||||
|
||||
getContainingSymbol()?.let { it as? KtClassLikeSymbol }?.let { containingClass ->
|
||||
return containingClass.getObjCName() + objCName.capitalizeAsciiOnly()
|
||||
}
|
||||
|
||||
// KT-65670: Append module specific prefixes?
|
||||
return configuration.frameworkName.orEmpty() + objCName
|
||||
}
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassLikeSymbol.getSwiftName(
|
||||
resolvedObjCNameAnnotation: KtResolvedObjCNameAnnotation? = resolveObjCNameAnnotation(),
|
||||
): String {
|
||||
val swiftName = (resolvedObjCNameAnnotation?.swiftName ?: nameOrAnonymous.asString()).toValidObjCSwiftIdentifier()
|
||||
if (resolvedObjCNameAnnotation != null && resolvedObjCNameAnnotation.isExact) {
|
||||
return swiftName
|
||||
}
|
||||
|
||||
getContainingSymbol()?.let { it as? KtClassLikeSymbol }?.let { containingClass ->
|
||||
val containingClassSwiftName = containingClass.getSwiftName()
|
||||
return buildString {
|
||||
if (canBeInnerSwift()) {
|
||||
append(containingClassSwiftName)
|
||||
if ("." !in this && containingClass.canBeOuterSwift()) {
|
||||
// AB -> AB.C
|
||||
append(".")
|
||||
append(mangleSwiftNestedClassName(swiftName))
|
||||
} else {
|
||||
// AB -> ABC
|
||||
// A.B -> A.BC
|
||||
append(swiftName.capitalizeAsciiOnly())
|
||||
}
|
||||
} else {
|
||||
append(containingClassSwiftName.replaceFirst(".", ""))
|
||||
append(swiftName.capitalizeAsciiOnly())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KT-65670: Append module specific prefixes?
|
||||
return swiftName
|
||||
|
||||
}
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassLikeSymbol.canBeInnerSwift(): Boolean {
|
||||
if (configuration.objcGenerics && this.typeParameters.isNotEmpty()) {
|
||||
// Swift compiler doesn't seem to handle this case properly.
|
||||
// See https://bugs.swift.org/browse/SR-14607.
|
||||
// This behaviour of Kotlin is reported as https://youtrack.jetbrains.com/issue/KT-46518.
|
||||
return false
|
||||
}
|
||||
|
||||
if (this is KtClassOrObjectSymbol && this.classKind == KtClassKind.INTERFACE) {
|
||||
// Swift doesn't support nested protocols.
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
context(KtAnalysisSession, KtObjCExportSession)
|
||||
private fun KtClassLikeSymbol.canBeOuterSwift(): Boolean {
|
||||
if (configuration.objcGenerics && this.typeParameters.isNotEmpty()) {
|
||||
// Swift nested classes are static but capture outer's generics.
|
||||
return false
|
||||
}
|
||||
|
||||
if (this is KtClassOrObjectSymbol && this.classKind == KtClassKind.INTERFACE) {
|
||||
// Swift doesn't support outer protocols.
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun mangleSwiftNestedClassName(name: String): String = when (name) {
|
||||
"Type" -> "${name}_" // See https://github.com/JetBrains/kotlin-native/issues/3167
|
||||
else -> name
|
||||
}
|
||||
+2
-1
@@ -17,9 +17,10 @@ fun KtClassOrObjectSymbol.translateToObjCClass(): ObjCClass? {
|
||||
|
||||
val enumKind = this.classKind == KtClassKind.ENUM_CLASS
|
||||
val final = if (this is KtSymbolWithModality) this.modality == Modality.FINAL else false
|
||||
val attributes = if (enumKind || final) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
|
||||
|
||||
val name = getObjCClassOrProtocolName()
|
||||
val attributes = (if (enumKind || final) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()) + name.toNameAttributes()
|
||||
|
||||
val comment: ObjCComment? = annotationsList.translateToObjCComment()
|
||||
val origin: ObjCExportStubOrigin = getObjCExportStubOrigin()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user