Improve inner/nested class names in framework

Use 'Outer.Inner' instead of 'OuterInner' for Swift

Also do some refactoring and add other minor improvements.
This commit is contained in:
Svyatoslav Scherbina
2018-09-12 17:45:17 +03:00
committed by SvyatoslavScherbina
parent e4ca831f06
commit 1791ed5643
2 changed files with 73 additions and 32 deletions
@@ -46,9 +46,6 @@ internal class ObjCExportNamerImpl(
private val topLevelNamePrefix: String = moduleDescriptor.namePrefix
) : ObjCExportNamer {
private fun String.mangleClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName =
ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = "$topLevelNamePrefix${this}")
private fun String.toUnmangledClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName =
ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = this)
@@ -95,13 +92,15 @@ internal class ObjCExportNamerImpl(
!mapper.canHaveSameName(first, second)
}
private val classNames = object : Mapping<Any, String>() {
override fun conflict(first: Any, second: Any): Boolean = true
private inner open class GlobalNameMapping<in T : Any, N> : Mapping<T, N>() {
final override fun conflict(first: T, second: T): Boolean = true
}
private val protocolNames = object : Mapping<Any, String>() {
override fun conflict(first: Any, second: Any): Boolean = true
}
private val objCClassNames = GlobalNameMapping<Any, String>()
private val objCProtocolNames = GlobalNameMapping<ClassDescriptor, String>()
// Classes and protocols share the same namespace in Swift.
private val swiftClassAndProtocolNames = GlobalNameMapping<Any, String>()
private abstract inner class ClassPropertyNameMapping<T : Any> : Mapping<T, String>() {
@@ -127,12 +126,26 @@ internal class ObjCExportNamerImpl(
first.containingDeclaration == second.containingDeclaration
}
override fun getFileClassName(file: SourceFile): ObjCExportNamer.ClassOrProtocolName = classNames.getOrPut(file) {
val psiSourceFile = file as? PsiSourceFile ?: error("SourceFile '$file' is not PsiSourceFile")
val psiFile = psiSourceFile.psiFile
val ktFile = psiFile as? KtFile ?: error("PsiFile '$psiFile' is not KtFile")
StringBuilder(PackagePartClassUtils.getFilePartShortName(ktFile.name)).mangledSequence { append("_") }
}.mangleClassOrProtocolName()
override fun getFileClassName(file: SourceFile): ObjCExportNamer.ClassOrProtocolName {
val baseName by lazy {
val psiSourceFile = file as? PsiSourceFile ?: error("SourceFile '$file' is not PsiSourceFile")
val psiFile = psiSourceFile.psiFile
val ktFile = psiFile as? KtFile ?: error("PsiFile '$psiFile' is not KtFile")
PackagePartClassUtils.getFilePartShortName(ktFile.name)
}
val objCName = objCClassNames.getOrPut(file) {
StringBuilder(topLevelNamePrefix).append(baseName)
.mangledBySuffixUnderscores()
}
val swiftName = swiftClassAndProtocolNames.getOrPut(file) {
StringBuilder(baseName)
.mangledBySuffixUnderscores()
}
return ObjCExportNamer.ClassOrProtocolName(swiftName = swiftName, objCName = objCName)
}
private val predefinedClassNames = mapOf(
builtIns.any to kotlinAnyName,
@@ -140,22 +153,48 @@ internal class ObjCExportNamerImpl(
builtIns.mutableMap to mutableMapName
)
override fun getClassOrProtocolName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName {
predefinedClassNames[descriptor]?.let { return it }
override fun getClassOrProtocolName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName =
predefinedClassNames[descriptor]
?: ObjCExportNamer.ClassOrProtocolName(
swiftName = getClassOrProtocolSwiftName(descriptor),
objCName = getClassOrProtocolObjCName(descriptor)
)
val mapping = if (descriptor.isInterface) protocolNames else classNames
private fun getClassOrProtocolSwiftName(
descriptor: ClassDescriptor
): String = swiftClassAndProtocolNames.getOrPut(descriptor) {
StringBuilder().apply {
val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration is ClassDescriptor) {
append(getClassOrProtocolSwiftName(containingDeclaration))
.append(".").append(descriptor.name.asString())
} else {
appendTopLevelClassBaseName(descriptor)
}
}.mangledBySuffixUnderscores()
}
return mapping.getOrPut(descriptor) {
private fun getClassOrProtocolObjCName(descriptor: ClassDescriptor): String {
val objCMapping = if (descriptor.isInterface) objCProtocolNames else objCClassNames
return objCMapping.getOrPut(descriptor) {
StringBuilder().apply {
if (descriptor.module != moduleDescriptor) {
append(descriptor.module.namePrefix)
}
val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration is ClassDescriptor) {
append(getClassOrProtocolObjCName(containingDeclaration))
.append(descriptor.name.asString().capitalize())
descriptor.parentsWithSelf.takeWhile { it is ClassDescriptor }
.toList().reversed()
.joinTo(this, "") { it.name.asString().capitalize() }
}.mangledSequence { append("_") }
}.mangleClassOrProtocolName()
} else {
append(topLevelNamePrefix).appendTopLevelClassBaseName(descriptor)
}
}.mangledBySuffixUnderscores()
}
}
private fun StringBuilder.appendTopLevelClassBaseName(descriptor: ClassDescriptor) = apply {
if (descriptor.module != moduleDescriptor) {
append(descriptor.module.namePrefix)
}
append(descriptor.name.asString())
}
override fun getSelector(method: FunctionDescriptor): String = methodSelectors.getOrPut(method) {
@@ -258,7 +297,7 @@ internal class ObjCExportNamerImpl(
return objectInstanceSelectors.getOrPut(descriptor) {
val name = descriptor.name.asString().decapitalize().mangleIfSpecialFamily("get")
StringBuilder(name).mangledSequence { append("_") }
StringBuilder(name).mangledBySuffixUnderscores()
}
}
@@ -272,7 +311,7 @@ internal class ObjCExportNamerImpl(
if (index == 0) lower else lower.capitalize()
}.joinToString("").mangleIfSpecialFamily("the")
StringBuilder(name).mangledSequence { append("_") }
StringBuilder(name).mangledBySuffixUnderscores()
}
}
@@ -280,8 +319,8 @@ internal class ObjCExportNamerImpl(
val any = builtIns.any
predefinedClassNames.forEach { descriptor, name ->
// Note: it is a hack.
classNames.forceAssign(descriptor, name.swiftName)
objCClassNames.forceAssign(descriptor, name.objCName)
swiftClassAndProtocolNames.forceAssign(descriptor, name.swiftName)
}
fun ClassDescriptor.method(name: String) =
@@ -336,7 +375,7 @@ internal class ObjCExportNamerImpl(
private fun String.startsWithWords(words: String) = this.startsWith(words) &&
(this.length == words.length || !this[words.length].isLowerCase())
private abstract inner class Mapping<T : Any, N>() {
private abstract inner class Mapping<in T : Any, N>() {
private val elementToName = mutableMapOf<T, N>()
private val nameToElements = mutableMapOf<N, MutableList<T>>()
@@ -390,6 +429,8 @@ private inline fun StringBuilder.mangledSequence(crossinline mangle: StringBuild
this@mangledSequence.toString()
}
private fun StringBuilder.mangledBySuffixUnderscores() = this.mangledSequence { append("_") }
private fun ObjCExportMapper.canHaveCommonSubtype(first: ClassDescriptor, second: ClassDescriptor): Boolean {
if (first.isSubclassOf(second) || second.isSubclassOf(first)) {
return true
@@ -377,7 +377,7 @@ func testDataClass() throws {
}
func testCompanionObj() throws {
try assertEquals(actual: WithCompanionAndObjectCompanion().str, expected: "String")
try assertEquals(actual: WithCompanionAndObject.Companion().str, expected: "String")
try assertEquals(actual: ValuesKt.getCompanionObject().str, expected: "String")
let namedFromCompanion = ValuesKt.getCompanionObject().named