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 private val topLevelNamePrefix: String = moduleDescriptor.namePrefix
) : ObjCExportNamer { ) : ObjCExportNamer {
private fun String.mangleClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName =
ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = "$topLevelNamePrefix${this}")
private fun String.toUnmangledClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName = private fun String.toUnmangledClassOrProtocolName(): ObjCExportNamer.ClassOrProtocolName =
ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = this) ObjCExportNamer.ClassOrProtocolName(swiftName = this, objCName = this)
@@ -95,13 +92,15 @@ internal class ObjCExportNamerImpl(
!mapper.canHaveSameName(first, second) !mapper.canHaveSameName(first, second)
} }
private val classNames = object : Mapping<Any, String>() { private inner open class GlobalNameMapping<in T : Any, N> : Mapping<T, N>() {
override fun conflict(first: Any, second: Any): Boolean = true final override fun conflict(first: T, second: T): Boolean = true
} }
private val protocolNames = object : Mapping<Any, String>() { private val objCClassNames = GlobalNameMapping<Any, String>()
override fun conflict(first: Any, second: Any): Boolean = true 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>() { private abstract inner class ClassPropertyNameMapping<T : Any> : Mapping<T, String>() {
@@ -127,12 +126,26 @@ internal class ObjCExportNamerImpl(
first.containingDeclaration == second.containingDeclaration first.containingDeclaration == second.containingDeclaration
} }
override fun getFileClassName(file: SourceFile): ObjCExportNamer.ClassOrProtocolName = classNames.getOrPut(file) { override fun getFileClassName(file: SourceFile): ObjCExportNamer.ClassOrProtocolName {
val psiSourceFile = file as? PsiSourceFile ?: error("SourceFile '$file' is not PsiSourceFile") val baseName by lazy {
val psiFile = psiSourceFile.psiFile val psiSourceFile = file as? PsiSourceFile ?: error("SourceFile '$file' is not PsiSourceFile")
val ktFile = psiFile as? KtFile ?: error("PsiFile '$psiFile' is not KtFile") val psiFile = psiSourceFile.psiFile
StringBuilder(PackagePartClassUtils.getFilePartShortName(ktFile.name)).mangledSequence { append("_") } val ktFile = psiFile as? KtFile ?: error("PsiFile '$psiFile' is not KtFile")
}.mangleClassOrProtocolName() 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( private val predefinedClassNames = mapOf(
builtIns.any to kotlinAnyName, builtIns.any to kotlinAnyName,
@@ -140,22 +153,48 @@ internal class ObjCExportNamerImpl(
builtIns.mutableMap to mutableMapName builtIns.mutableMap to mutableMapName
) )
override fun getClassOrProtocolName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName { override fun getClassOrProtocolName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName =
predefinedClassNames[descriptor]?.let { return it } 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 { StringBuilder().apply {
if (descriptor.module != moduleDescriptor) { val containingDeclaration = descriptor.containingDeclaration
append(descriptor.module.namePrefix) if (containingDeclaration is ClassDescriptor) {
} append(getClassOrProtocolObjCName(containingDeclaration))
.append(descriptor.name.asString().capitalize())
descriptor.parentsWithSelf.takeWhile { it is ClassDescriptor } } else {
.toList().reversed() append(topLevelNamePrefix).appendTopLevelClassBaseName(descriptor)
.joinTo(this, "") { it.name.asString().capitalize() } }
}.mangledSequence { append("_") } }.mangledBySuffixUnderscores()
}.mangleClassOrProtocolName() }
}
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) { override fun getSelector(method: FunctionDescriptor): String = methodSelectors.getOrPut(method) {
@@ -258,7 +297,7 @@ internal class ObjCExportNamerImpl(
return objectInstanceSelectors.getOrPut(descriptor) { return objectInstanceSelectors.getOrPut(descriptor) {
val name = descriptor.name.asString().decapitalize().mangleIfSpecialFamily("get") 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() if (index == 0) lower else lower.capitalize()
}.joinToString("").mangleIfSpecialFamily("the") }.joinToString("").mangleIfSpecialFamily("the")
StringBuilder(name).mangledSequence { append("_") } StringBuilder(name).mangledBySuffixUnderscores()
} }
} }
@@ -280,8 +319,8 @@ internal class ObjCExportNamerImpl(
val any = builtIns.any val any = builtIns.any
predefinedClassNames.forEach { descriptor, name -> predefinedClassNames.forEach { descriptor, name ->
// Note: it is a hack. objCClassNames.forceAssign(descriptor, name.objCName)
classNames.forceAssign(descriptor, name.swiftName) swiftClassAndProtocolNames.forceAssign(descriptor, name.swiftName)
} }
fun ClassDescriptor.method(name: String) = fun ClassDescriptor.method(name: String) =
@@ -336,7 +375,7 @@ internal class ObjCExportNamerImpl(
private fun String.startsWithWords(words: String) = this.startsWith(words) && private fun String.startsWithWords(words: String) = this.startsWith(words) &&
(this.length == words.length || !this[words.length].isLowerCase()) (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 elementToName = mutableMapOf<T, N>()
private val nameToElements = mutableMapOf<N, MutableList<T>>() private val nameToElements = mutableMapOf<N, MutableList<T>>()
@@ -390,6 +429,8 @@ private inline fun StringBuilder.mangledSequence(crossinline mangle: StringBuild
this@mangledSequence.toString() this@mangledSequence.toString()
} }
private fun StringBuilder.mangledBySuffixUnderscores() = this.mangledSequence { append("_") }
private fun ObjCExportMapper.canHaveCommonSubtype(first: ClassDescriptor, second: ClassDescriptor): Boolean { private fun ObjCExportMapper.canHaveCommonSubtype(first: ClassDescriptor, second: ClassDescriptor): Boolean {
if (first.isSubclassOf(second) || second.isSubclassOf(first)) { if (first.isSubclassOf(second) || second.isSubclassOf(first)) {
return true return true
@@ -377,7 +377,7 @@ func testDataClass() throws {
} }
func testCompanionObj() 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") try assertEquals(actual: ValuesKt.getCompanionObject().str, expected: "String")
let namedFromCompanion = ValuesKt.getCompanionObject().named let namedFromCompanion = ValuesKt.getCompanionObject().named