[klib] Fix enum printing
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.klib
|
|||||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializerProtocol
|
import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializerProtocol
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.parseModuleHeader
|
import org.jetbrains.kotlin.backend.konan.serialization.parseModuleHeader
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.parsePackageFragment
|
import org.jetbrains.kotlin.backend.konan.serialization.parsePackageFragment
|
||||||
|
import org.jetbrains.kotlin.renderer.renderFqName
|
||||||
import org.jetbrains.kotlin.serialization.Flags
|
import org.jetbrains.kotlin.serialization.Flags
|
||||||
import org.jetbrains.kotlin.serialization.Flags.*
|
import org.jetbrains.kotlin.serialization.Flags.*
|
||||||
import org.jetbrains.kotlin.serialization.KonanLinkData
|
import org.jetbrains.kotlin.serialization.KonanLinkData
|
||||||
@@ -73,7 +74,7 @@ class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment,
|
|||||||
object TypeTables {
|
object TypeTables {
|
||||||
val tables = mutableListOf<ProtoBuf.TypeTable>()
|
val tables = mutableListOf<ProtoBuf.TypeTable>()
|
||||||
fun push(table: ProtoBuf.TypeTable) { tables.add(table) }
|
fun push(table: ProtoBuf.TypeTable) { tables.add(table) }
|
||||||
fun pop() { tables.removeAt(tables.lastIndex) }
|
fun pop() = tables.removeAt(tables.lastIndex)
|
||||||
fun type(typeId: Int) = tables.last().getType(typeId)!!
|
fun type(typeId: Int) = tables.last().getType(typeId)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment,
|
|||||||
fun print() {
|
fun print() {
|
||||||
TypeTables.push(packageFragment.`package`.typeTable)
|
TypeTables.push(packageFragment.`package`.typeTable)
|
||||||
// if (packageFragment.hasFqName()) printer.print("package ${packageFragment.fqName}\n")
|
// if (packageFragment.hasFqName()) printer.print("package ${packageFragment.fqName}\n")
|
||||||
packageFragment.classes.classesList.forEach { printer.println(it.asString()) }
|
packageFragment.classes.classesList.forEach { printer.println(it.asString(packageFragment.classes)) }
|
||||||
packageFragment.`package`.functionList.forEach { printer.println(it.asString()) }
|
packageFragment.`package`.functionList.forEach { printer.println(it.asString()) }
|
||||||
packageFragment.`package`.propertyList.forEach { printer.println(it.asString()) }
|
packageFragment.`package`.propertyList.forEach { printer.println(it.asString()) }
|
||||||
TypeTables.pop()
|
TypeTables.pop()
|
||||||
@@ -93,30 +94,62 @@ class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment,
|
|||||||
private fun StringBuilder.buildBody(body: StringBuilder.() -> Unit) {
|
private fun StringBuilder.buildBody(body: StringBuilder.() -> Unit) {
|
||||||
Indent.push()
|
Indent.push()
|
||||||
val result = StringBuilder().apply(body).toString()
|
val result = StringBuilder().apply(body).toString()
|
||||||
append(if (result.isEmpty()) "\n" else " {\n$result}\n")
|
|
||||||
Indent.pop()
|
Indent.pop()
|
||||||
|
append(if (result.isEmpty()) "\n" else " {\n$result$Indent}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun ProtoBuf.Class.asString(): String {
|
private fun ProtoBuf.EnumEntry.asString(): String = "$Indent${stringTable.getString(name)}"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun StringBuilder.appendClassBody(clazz: ProtoBuf.Class) = with(clazz) {
|
||||||
|
secondaryConstructors().forEach { append(it.asString(clazz.isEnumClass)) }
|
||||||
|
functionList.forEach { append(it.asString()) }
|
||||||
|
propertyList.forEach { append(it.asString()) }
|
||||||
|
nestedClassNameList.forEach { append(nestedClassAsString(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: val/var parameters are printed twice
|
||||||
|
// TODO: Support nested/inner and sealed classes
|
||||||
|
private fun ProtoBuf.Class.asString(classes: KonanLinkData.Classes): String {
|
||||||
|
if (isEnumEntry) return "" // TODO: Make better
|
||||||
if (hasTypeTable()) TypeTables.push(typeTable)
|
if (hasTypeTable()) TypeTables.push(typeTable)
|
||||||
val result = buildString {
|
val result = buildString {
|
||||||
val className = getName(fqName)
|
val className = getName(fqName)
|
||||||
val classKind = Flags.CLASS_KIND.get(flags).asString()
|
val classKind = Flags.CLASS_KIND.get(flags).asString()
|
||||||
val modality = Flags.MODALITY .get(flags).asString()
|
val modality = Flags.MODALITY .get(flags).asString()
|
||||||
val visibility = Flags.VISIBILITY.get(flags).asString()
|
val visibility = Flags.VISIBILITY.get(flags).asString()
|
||||||
val typeParameters = typeParameterList.joinToString("<", "> ") { it.asString() }
|
val typeParameters = typeParameterList
|
||||||
val primaryConstructor = primaryConstructor().asString(true)
|
.joinToString("<", "> ") { it.asString() }
|
||||||
|
.let { if (it.isEmpty()) " " else it }
|
||||||
|
val primaryConstructor = primaryConstructor().asString(isEnumClass, true)
|
||||||
val supertypes = supertypesToString(supertypeIdList)
|
val supertypes = supertypesToString(supertypeIdList)
|
||||||
val annotations = annotationsToString(getExtension(KonanSerializerProtocol.classAnnotation), "\n")
|
val annotations = annotationsToString(getExtension(KonanSerializerProtocol.classAnnotation), "\n")
|
||||||
|
|
||||||
append("$annotations$Indent$modality$visibility$classKind$className$typeParameters$primaryConstructor$supertypes")
|
append("$annotations$Indent$modality$visibility$classKind$className$typeParameters$primaryConstructor$supertypes")
|
||||||
|
|
||||||
buildBody {
|
buildBody {
|
||||||
secondaryConstructors().forEach { append(it.asString()) }
|
appendClassBody(this@asString)
|
||||||
functionList.forEach { append(it.asString()) }
|
|
||||||
propertyList.forEach { append(it.asString()) }
|
if (isEnumClass) {
|
||||||
nestedClassNameList.forEach { append(nestedClassAsString(it)) }
|
val enumClasses = classes.classesList.filter { clazz ->
|
||||||
|
clazz.isEnumEntry &&
|
||||||
|
clazz.hasTypeTable() &&
|
||||||
|
clazz.supertypeIdList.map { clazz.typeTable.getType(it).className }.contains(fqName)
|
||||||
|
}
|
||||||
|
|
||||||
|
enumClasses.forEach { entry ->
|
||||||
|
append(Indent)
|
||||||
|
append(getName(entry.fqName))
|
||||||
|
TypeTables.push(entry.typeTable)
|
||||||
|
buildBody {
|
||||||
|
appendClassBody(entry)
|
||||||
|
}
|
||||||
|
TypeTables.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasTypeTable()) TypeTables.pop()
|
if (hasTypeTable()) TypeTables.pop()
|
||||||
@@ -128,26 +161,34 @@ class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment,
|
|||||||
private fun supertypesToString(supertypesId: List<Int>): String {
|
private fun supertypesToString(supertypesId: List<Int>): String {
|
||||||
val result = supertypesId.joinToString {
|
val result = supertypesId.joinToString {
|
||||||
val supertype = TypeTables.type(it).asString()
|
val supertype = TypeTables.type(it).asString()
|
||||||
if (supertype == "Any") "" else supertype
|
// TODO: Use fq names here.
|
||||||
|
if (supertype == "Any" || supertype.startsWith("Enum<")) "" else supertype
|
||||||
}
|
}
|
||||||
return if (result.isEmpty()) "" else " : $result"
|
return if (result.isEmpty()) "" else " : $result"
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun ProtoBuf.Constructor.asString(isPrimary: Boolean = false): String {
|
private fun ProtoBuf.Constructor.asString(isEnumClass: Boolean = false, isPrimary: Boolean = false): String {
|
||||||
val visibility = Flags.VISIBILITY.get(flags).asString()
|
// Enum class constructors are always private.
|
||||||
val annotations = annotationsToString(getExtension(KonanSerializerProtocol.constructorAnnotation), "\n")
|
val visibility = if (!isEnumClass) Flags.VISIBILITY.get(flags).asString() else ""
|
||||||
|
// TODO: '\n' was used here as a separator (see annotationsToString code). Return it?
|
||||||
|
val annotations = annotationsToString(getExtension(KonanSerializerProtocol.constructorAnnotation))
|
||||||
val parameters = valueParameterList.joinToString(", ", prefix = "(", postfix = ")") { it.asString(true) }
|
val parameters = valueParameterList.joinToString(", ", prefix = "(", postfix = ")") { it.asString(true) }
|
||||||
|
|
||||||
val header = "$visibility$annotations"
|
val header = "$visibility$annotations"
|
||||||
if (isPrimary) {
|
if (isPrimary) {
|
||||||
if (header.isNotEmpty()) return "$header constructor$parameters"
|
return when {
|
||||||
if (parameters == "()") return ""
|
header.isNotEmpty() -> "${header}constructor$parameters"
|
||||||
return parameters
|
parameters == "()" -> ""
|
||||||
|
else -> parameters
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (header.isNotEmpty()) return "$Indent$header constructor$parameters\n"
|
return if (header.isNotEmpty()) {
|
||||||
return "${Indent}constructor$parameters\n"
|
"$Indent$header constructor$parameters\n"
|
||||||
|
} else {
|
||||||
|
"${Indent}constructor$parameters\n"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,6 +359,12 @@ class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment,
|
|||||||
private fun ProtoBuf.Class.primaryConstructor() = constructorList.first { !Flags.IS_SECONDARY.get(it.flags) }
|
private fun ProtoBuf.Class.primaryConstructor() = constructorList.first { !Flags.IS_SECONDARY.get(it.flags) }
|
||||||
private fun ProtoBuf.Class.secondaryConstructors() = constructorList.filter { Flags.IS_SECONDARY.get(it.flags) }
|
private fun ProtoBuf.Class.secondaryConstructors() = constructorList.filter { Flags.IS_SECONDARY.get(it.flags) }
|
||||||
|
|
||||||
|
private val ProtoBuf.Class.isEnumClass: Boolean
|
||||||
|
get() = Flags.CLASS_KIND.get(flags) == ProtoBuf.Class.Kind.ENUM_CLASS
|
||||||
|
|
||||||
|
private val ProtoBuf.Class.isEnumEntry: Boolean
|
||||||
|
get() = Flags.CLASS_KIND.get(flags) == ProtoBuf.Class.Kind.ENUM_ENTRY
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun ProtoBuf.TypeParameter.Variance.asString(): String {
|
private fun ProtoBuf.TypeParameter.Variance.asString(): String {
|
||||||
@@ -355,7 +402,7 @@ class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment,
|
|||||||
ProtoBuf.Class.Kind.CLASS -> "class "
|
ProtoBuf.Class.Kind.CLASS -> "class "
|
||||||
ProtoBuf.Class.Kind.INTERFACE -> "interface "
|
ProtoBuf.Class.Kind.INTERFACE -> "interface "
|
||||||
ProtoBuf.Class.Kind.ENUM_CLASS -> "enum class "
|
ProtoBuf.Class.Kind.ENUM_CLASS -> "enum class "
|
||||||
ProtoBuf.Class.Kind.ENUM_ENTRY -> "enum "
|
ProtoBuf.Class.Kind.ENUM_ENTRY -> "enum " // TODO: remove/never happen
|
||||||
ProtoBuf.Class.Kind.ANNOTATION_CLASS -> "annotation class "
|
ProtoBuf.Class.Kind.ANNOTATION_CLASS -> "annotation class "
|
||||||
ProtoBuf.Class.Kind.OBJECT -> "object "
|
ProtoBuf.Class.Kind.OBJECT -> "object "
|
||||||
ProtoBuf.Class.Kind.COMPANION_OBJECT -> "companion object "
|
ProtoBuf.Class.Kind.COMPANION_OBJECT -> "companion object "
|
||||||
|
|||||||
Reference in New Issue
Block a user