diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/PrettyPrinter.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/PrettyPrinter.kt index 632ae485c88..1b484cbca3a 100644 --- a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/PrettyPrinter.kt +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/PrettyPrinter.kt @@ -16,11 +16,12 @@ package org.jetbrains.kotlin.cli.klib -import org.jetbrains.kotlin.serialization.KonanLinkData +import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializerProtocol import org.jetbrains.kotlin.backend.konan.serialization.parseModuleHeader import org.jetbrains.kotlin.backend.konan.serialization.parsePackageFragment -import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializerProtocol import org.jetbrains.kotlin.serialization.Flags +import org.jetbrains.kotlin.serialization.Flags.* +import org.jetbrains.kotlin.serialization.KonanLinkData import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.utils.Printer import java.lang.System.out @@ -37,484 +38,297 @@ open class ModuleDeserializer(val library: ByteArray) { } -class PrettyPrinter(library: ByteArray, val packageLoader: (String) -> ByteArray) +//-----------------------------------------------------------------------------// + +class PrettyPrinter(library: ByteArray, val packageLoader: (String) -> ByteArray) : ModuleDeserializer(library) { private fun packageFragment(fqname: String): KonanLinkData.PackageFragment = parsePackageFragment(packageLoader(fqname)) fun printPackageFragment(fqname: String) { - if (fqname.isNotEmpty()) println("\npackage $fqname") val fragment = packageFragment(fqname) PackageFragmentPrinter(fragment, out).print() } } +//-----------------------------------------------------------------------------// + class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment, out: Appendable) { private val printer = Printer(out, " ") private val stringTable = packageFragment.stringTable!! private val qualifiedNameTable = packageFragment.nameTable!! - private var typeTableStack = mutableListOf() + + //-------------------------------------------------------------------------// + + object Indent { + private var indent: String = "" + fun push() { indent += " " } + fun pop() { indent = indent.dropLast(4) } + override fun toString() = indent + } + + //-------------------------------------------------------------------------// + + object TypeTables { + val tables = mutableListOf() + fun push(table: ProtoBuf.TypeTable) { tables.add(table) } + fun pop() { tables.removeAt(tables.lastIndex) } + fun type(typeId: Int) = tables.last().getType(typeId)!! + } //-------------------------------------------------------------------------// fun print() { - typeTableStack.add(packageFragment.`package`.typeTable) + TypeTables.push(packageFragment.`package`.typeTable) + // if (packageFragment.hasFqName()) printer.print("package ${packageFragment.fqName}\n") + packageFragment.classes.classesList.forEach { printer.println(it.asString()) } + packageFragment.`package`.functionList.forEach { printer.println(it.asString()) } + packageFragment.`package`.propertyList.forEach { printer.println(it.asString()) } + TypeTables.pop() + } - val protoTypeAliases = packageFragment.`package`.typeAliasList - protoTypeAliases.forEach { protoTypeAlias -> - printTypeAlias(protoTypeAlias) - } + //-------------------------------------------------------------------------// - val protoClasses = packageFragment.classes.classesList // ProtoBuf classes - protoClasses.forEach { protoClass -> - val classKind = Flags.CLASS_KIND.get(protoClass.flags)!! - when (classKind) { - ProtoBuf.Class.Kind.CLASS -> printClass(protoClass) - ProtoBuf.Class.Kind.ENUM_CLASS -> printEnum(protoClass) - ProtoBuf.Class.Kind.INTERFACE -> printClass(protoClass) - ProtoBuf.Class.Kind.ENUM_ENTRY -> printEnum(protoClass) - ProtoBuf.Class.Kind.ANNOTATION_CLASS -> printClass(protoClass) - ProtoBuf.Class.Kind.OBJECT -> printClass(protoClass) - ProtoBuf.Class.Kind.COMPANION_OBJECT -> printClass(protoClass) + private fun StringBuilder.buildBody(body: StringBuilder.() -> Unit) { + Indent.push() + val result = StringBuilder().apply(body).toString() + append(if (result.isEmpty()) "\n" else " {\n$result}\n") + Indent.pop() + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Class.asString(): String { + if (hasTypeTable()) TypeTables.push(typeTable) + val result = buildString { + val className = getName(fqName) + val classKind = Flags.CLASS_KIND.get(flags).asString() + val modality = Flags.MODALITY .get(flags).asString() + val visibility = Flags.VISIBILITY.get(flags).asString() + val typeParameters = typeParameterList.joinToString("<", "> ") { it.asString() } + val primaryConstructor = primaryConstructor().asString(true) + val supertypes = supertypesToString(supertypeIdList) + val annotations = annotationsToString(getExtension(KonanSerializerProtocol.classAnnotation), "\n") + + append("$annotations$Indent$modality$visibility$classKind$className$typeParameters$primaryConstructor$supertypes") + buildBody { + secondaryConstructors().forEach { append(it.asString()) } + functionList.forEach { append(it.asString()) } + propertyList.forEach { append(it.asString()) } + nestedClassNameList.forEach { append(nestedClassAsString(it)) } } } - - val protoFunctions = packageFragment.`package`.functionList - protoFunctions.forEach { protoFunction -> - printFunction(protoFunction) - } - - val protoProperties = packageFragment.`package`.propertyList - protoProperties.forEach { protoProperty -> - printProperty(protoProperty) - } - } - - //-------------------------------------------------------------------------// - - private fun printTypeAlias(protoTypeAlias: ProtoBuf.TypeAlias) { - val aliasName = stringTable.getString(protoTypeAlias.name) - val typeName = typeToString(protoTypeAlias.expandedTypeId) - printer.println("typealias $aliasName = $typeName") - } - - //-------------------------------------------------------------------------// - - private fun printClass(protoClass: ProtoBuf.Class) { - val hasTypeTable = protoClass.hasTypeTable() - if (hasTypeTable) typeTableStack.add(protoClass.typeTable) - val className = getShortName(protoClass.fqName) - val annotations = protoClass.getExtension(KonanSerializerProtocol.classAnnotation) - val keyword = classOrInterface(protoClass) - val protoConstructors = protoClass.constructorList - val protoFunctions = protoClass.functionList - val protoProperties = protoClass.propertyList - val nestedClasses = protoClass.nestedClassNameList - - printAnnotations(annotations) - printer.print("$keyword $className") - printer.print(typeParametersToString(protoClass.typeParameterList)) - printer.print(primaryConstructorToString(protoConstructors)) - printer.print(supertypesToString(protoClass.supertypeIdList)) - - printer.println(" {") - printer.pushIndent() - printSecondaryConstructors(protoConstructors) - printCompanionObject(protoClass) - protoFunctions.forEach { printFunction(it) } - protoProperties.forEach { printProperty(it) } - nestedClasses.forEach { printNestedClass(it) } - printer.popIndent() - printer.println("}\n") - if (hasTypeTable) typeTableStack.removeAt(typeTableStack.lastIndex) - } - - //-------------------------------------------------------------------------// - - private fun printEnum(protoEnum: ProtoBuf.Class) { - val hasTypeTable = protoEnum.hasTypeTable() - if (hasTypeTable) typeTableStack.add(protoEnum.typeTable) - val flags = protoEnum.flags - val enumName = getShortName(protoEnum.fqName) - val modality = modalityToString(Flags.MODALITY.get(flags)) - val annotations = protoEnum.getExtension(KonanSerializerProtocol.classAnnotation) - val enumEntries = protoEnum.enumEntryList - if (Flags.CLASS_KIND.get(flags) == ProtoBuf.Class.Kind.ENUM_ENTRY) return - - printAnnotations(annotations) - printer.print("enum class $modality") - printer.print(enumName) - - printer.println(" {") - enumEntries.dropLast(1).forEach { printer.print(" ${enumEntryToString(it)},\n") } - enumEntries.lastOrNull()?.let { printer.print(" ${enumEntryToString(it)} \n") } - printer.println("}\n") - if (hasTypeTable) typeTableStack.removeAt(typeTableStack.lastIndex) - } - - //-------------------------------------------------------------------------// - - private fun printFunction(protoFunction: ProtoBuf.Function) { - val hasTypeTable = protoFunction.hasTypeTable() - if (hasTypeTable) typeTableStack.add(protoFunction.typeTable) - val flags = protoFunction.flags - val name = stringTable.getString(protoFunction.name) - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - val isInline = inlineToString(Flags.IS_INLINE.get(flags)) - val receiverType = receiverTypeToString(protoFunction) - val annotations = protoFunction.getExtension(KonanSerializerProtocol.functionAnnotation) - val typeParameters = typeParametersToString(protoFunction.typeParameterList) - val valueParameters = valueParametersToString(protoFunction.valueParameterList) - val returnType = returnTypeToString(protoFunction) - - printAnnotations(annotations) - printer.println("$visibility${isInline}fun $typeParameters$receiverType$name$valueParameters$returnType") - if (hasTypeTable) typeTableStack.removeAt(typeTableStack.lastIndex) - } - - //-------------------------------------------------------------------------// - - private fun printProperty(protoProperty: ProtoBuf.Property) { - val name = stringTable.getString(protoProperty.name) - val flags = protoProperty.flags - val isVar = if (Flags.IS_VAR.get(flags)) "var" else "val" - val modality = modalityToString(Flags.MODALITY.get(flags)) - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - val returnType = typeToString(protoProperty.returnTypeId) - val annotations = protoProperty.getExtension(KonanSerializerProtocol.propertyAnnotation) - - printAnnotations(annotations) - printer.println("$modality$visibility$isVar $name: $returnType") - } - - //-------------------------------------------------------------------------// - - fun printObject(protoObject: ProtoBuf.Class) { - val flags = protoObject.flags - val name = getShortName(protoObject.fqName) - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - val annotations = protoObject.getExtension(KonanSerializerProtocol.classAnnotation) - - printAnnotations(annotations) - printer.println("${visibility}object $name") - } - - //-------------------------------------------------------------------------// - - private fun printAnnotations(protoAnnotations: List) { - val annotations = annotationsToString(protoAnnotations) - if (annotations.isEmpty()) return - printer.println(annotations) - } - - //-------------------------------------------------------------------------// - - private fun annotationsToString(protoAnnotations: List): String { - val buff = StringBuilder() - protoAnnotations.forEach { buff.append(annotationToString(it)) } - return buff.toString() - } - - //-------------------------------------------------------------------------// - - private fun annotationToString(protoAnnotation: ProtoBuf.Annotation): String { - val buff = StringBuilder() - val annotationName = getShortName(protoAnnotation.id) - buff.append("@$annotationName") - val arguments = annotationArgumentsToString(protoAnnotation.argumentList) - buff.append(arguments) - return buff.append(" ").toString() - } - - //-------------------------------------------------------------------------// - - private fun annotationArgumentsToString(annotationArguments: List): String { - if (annotationArguments.isEmpty()) return "" - val buff = StringBuilder("(") - annotationArguments.dropLast(1).forEach { buff.append(annotationArgumentValueToString(it.value) + ", ") } - annotationArguments.lastOrNull()?.let { buff.append(annotationArgumentValueToString(it.value)) } - return buff.append(")").toString() - } - - //-------------------------------------------------------------------------// - - private fun annotationArgumentValueToString(value: ProtoBuf.Annotation.Argument.Value): String { - val buff = StringBuilder() - if (value.hasAnnotation()) buff.append(annotationToString(value.annotation)) - if (value.hasStringValue()) buff.append("\"${stringTable.getString(value.stringValue)}\"") - if (value.hasDoubleValue()) buff.append(value.doubleValue) - if (value.hasFloatValue()) buff.append(value.floatValue) - if (value.hasIntValue()) buff.append(value.intValue) - if (value.hasClassId()) buff.append(getShortName(value.classId) + ".") - if (value.hasEnumValueId()) buff.append(stringTable.getString(value.enumValueId)) - if (value.arrayElementCount > 0) { - val arrayElements = value.arrayElementList - arrayElements.dropLast(1).forEach { buff.append(annotationArgumentValueToString(it) + ", ") } - arrayElements.lastOrNull()?.let { buff.append(annotationArgumentValueToString(it)) } - } - return buff.toString() + if (hasTypeTable()) TypeTables.pop() + return result } //-------------------------------------------------------------------------// private fun supertypesToString(supertypesId: List): String { - val buff = StringBuilder() - supertypesId.dropLast(1).forEach { supertypeId -> - val supertype = typeToString(supertypeId) - if (supertype != "Any") buff.append("$supertype, ") + val result = supertypesId.joinToString { + val supertype = TypeTables.type(it).asString() + if (supertype == "Any") "" else supertype } - supertypesId.lastOrNull()?.let { supertypeId -> - val supertype = typeToString(supertypeId) - if (supertype != "Any") buff.append(supertype) - } - - if (buff.isEmpty()) return "" - return " : " + buff.toString() + return if (result.isEmpty()) "" else " : $result" } //-------------------------------------------------------------------------// - private fun primaryConstructorToString(protoConstructors: List): String { - val primaryConstructor = protoConstructors.firstOrNull { protoConstructor -> - !Flags.IS_SECONDARY.get(protoConstructor.flags) - } ?: return "" + private fun ProtoBuf.Constructor.asString(isPrimary: Boolean = false): String { + val visibility = Flags.VISIBILITY.get(flags).asString() + val annotations = annotationsToString(getExtension(KonanSerializerProtocol.constructorAnnotation), "\n") + val parameters = valueParameterList.joinToString(", ", prefix = "(", postfix = ")") { it.asString(true) } - val flags = primaryConstructor.flags - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - val annotations = annotationsToString(primaryConstructor.getExtension(KonanSerializerProtocol.constructorAnnotation)) - val valueParameters = constructorValueParametersToString(primaryConstructor.valueParameterList) - - val buff = "$visibility$annotations" - if (buff.isNotEmpty()) return " ${buff}constructor$valueParameters" - else return valueParameters - } - - //-------------------------------------------------------------------------// - - private fun printSecondaryConstructors(protoConstructors: List) { - val secondaryConstructors = protoConstructors.filter { protoConstructor -> - Flags.IS_SECONDARY.get(protoConstructor.flags) - } - - secondaryConstructors.forEach { protoConstructor -> - val flags = protoConstructor.flags - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - val valueParameters = valueParametersToString(protoConstructor.valueParameterList) - printer.println(" ${visibility}constructor$valueParameters") + val header = "$visibility$annotations" + if (isPrimary) { + if (header.isNotEmpty()) return "$header constructor$parameters" + if (parameters == "()") return "" + return parameters + } else { + if (header.isNotEmpty()) return "$Indent$header constructor$parameters\n" + return "${Indent}constructor$parameters\n" } } //-------------------------------------------------------------------------// - private fun typeParametersToString(typeParameters: List): String { - if (typeParameters.isEmpty()) return "" - - val buff = StringBuilder("<") - typeParameters.dropLast(1).forEach { buff.append(typeParameterToString(it) + ", ") } - typeParameters.lastOrNull()?.let { buff.append(typeParameterToString(it)) } - return buff.append("> ").toString() + private fun ProtoBuf.Function.asString(): String { + if (hasTypeTable()) TypeTables.push(typeTable) + val result = buildString { + val name = stringTable.getString(name) + val visibility = Flags.VISIBILITY.get(flags).asString() + val isInline = Flags.IS_INLINE.asString(flags) + val receiverType = receiverType() + val annotations = annotationsToString(getExtension(KonanSerializerProtocol.functionAnnotation), "\n") + val typeParameters = typeParameterList.joinToString("<", "> ") { it.asString() } + val valueParameters = valueParameterList.joinToString(", ", "(", ")") { it.asString() } + val returnType = returnType() + append("$annotations$Indent$visibility${isInline}fun $typeParameters$receiverType$name$valueParameters$returnType\n") + } + if (hasTypeTable()) TypeTables.pop() + return result } //-------------------------------------------------------------------------// - private fun typeParameterToString(protoTypeParameter: ProtoBuf.TypeParameter): String { - val parameterName = stringTable.getString(protoTypeParameter.name) - val upperBounds = upperBoundsToString(protoTypeParameter.upperBoundIdList) - val isReified = if (protoTypeParameter.reified) "reified " else "" - val variance = varianceToString(protoTypeParameter.variance) - val protoAnnotations = protoTypeParameter.getExtension(KonanSerializerProtocol.typeParameterAnnotation) - val annotations = annotationsToString(protoAnnotations) + private fun ProtoBuf.Property.asString() = buildString { + val name = stringTable.getString(name) + val isVar = Flags.IS_VAR.asString(flags) + val modality = Flags.MODALITY.get(flags).asString() + val visibility = Flags.VISIBILITY.get(flags).asString() + val returnType = TypeTables.type(returnTypeId).asString() + val annotations = annotationsToString(getExtension(KonanSerializerProtocol.propertyAnnotation), "\n") + append("$annotations$Indent$modality$visibility$isVar$name: $returnType\n") + } + //-------------------------------------------------------------------------// + + private fun nestedClassAsString(nestedClass: Int): String { + val nestedClassName = stringTable.getString(nestedClass) + return "${Indent}class $nestedClassName\n" + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Function.receiverType(): String { + if (!hasReceiverTypeId()) return "" + return TypeTables.type(receiverTypeId).asString() + "." + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Function.returnType(): String { + val returnType = TypeTables.type(returnTypeId).asString() + return if (returnType == "Unit") "" else ": " + returnType + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.TypeParameter.asString(): String { + val parameterName = stringTable.getString(name) + val upperBounds = upperBoundsToString(upperBoundIdList) + val isReified = if (reified) "reified " else "" + val variance = variance.asString() + val annotations = annotationsToString(getExtension(KonanSerializerProtocol.typeParameterAnnotation)) return "$annotations$isReified$variance$parameterName$upperBounds" } + private fun upperBoundsToString(upperBounds: List): String { + if (upperBounds.isEmpty()) return "" + return ": " + TypeTables.type(upperBounds.first()).asString() + } + //-------------------------------------------------------------------------// - private fun constructorValueParametersToString(valueParameters: List): String { - if (valueParameters.isEmpty()) return "" + private fun ProtoBuf.ValueParameter.asString(isConstructor: Boolean = false): String { + val parameterName = stringTable.getString(name) + val type = TypeTables.type(typeId).asString() - val buff = StringBuilder("(") - valueParameters.dropLast(1).forEach { valueParameter -> - val parameter = constructorValueParameterToString(valueParameter) - buff.append("$parameter, ") + val isVar = if (isConstructor) Flags.IS_VAR.asString(flags) else "" + val isCrossInline = Flags.IS_CROSSINLINE.asString(flags) + val visibility0 = Flags.VISIBILITY.get(flags).asString() + val visibility = if (visibility0 == "internal ") "" else visibility0 + val annotations = annotationsToString(getExtension(KonanSerializerProtocol.parameterAnnotation)) + + return "$annotations$isCrossInline$visibility$isVar$parameterName: $type" + } + + //-------------------------------------------------------------------------// + + private fun annotationsToString(annotations: List, separator: String = " "): String { + return buildString { annotations.forEach { append(it.asString() + separator) } } + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Annotation.asString(): String { + val builder = StringBuilder("$Indent@${getName(id)}") + argumentList.joinTo(builder, prefix = "(", postfix = ")") { it.value.asString() } + return builder.toString() + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Annotation.Argument.Value.asString(): String { + val builder = StringBuilder( + when { + hasAnnotation() -> annotation.asString() + hasStringValue() -> "\"${stringTable.getString(stringValue)}\"" + hasDoubleValue() -> doubleValue.toString() + hasFloatValue() -> floatValue.toString() + hasIntValue() -> intValue.toString() + hasClassId() -> getName(classId) + "." + hasEnumValueId() -> stringTable.getString(enumValueId) + else -> "" + }) + + arrayElementList.joinTo(builder) { it.asString() } + return builder.toString() + } + + + //--- Types ---------------------------------------------------------------// + + private fun ProtoBuf.Type.asValueString(): String { + val builder = StringBuilder(name()) + argumentList.joinTo(builder, "<", ">") { it.type.asString() } + if (nullable) builder.append("?") + return builder.toString() + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Type.asCallableString(): String { + val builder = StringBuilder() + argumentList.dropLast(1).joinTo(builder, ", ", "(", ") -> ") { TypeTables.type(it.typeId).asString() } + val returnType = argumentList.lastOrNull() + if (returnType != null) builder.append(TypeTables.type(returnType.typeId).asString()) + return builder.toString() + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Type.name() = when { + hasClassName() -> getName(className) + hasTypeParameterName() -> stringTable.getString(typeParameterName) + hasTypeAliasName() -> stringTable.getString(typeAliasName) + else -> "undefined" } - valueParameters.lastOrNull()?.let { valueParameter -> - val parameter = constructorValueParameterToString(valueParameter) - buff.append(parameter) - } - return buff.append(")").toString() - } //-------------------------------------------------------------------------// - private fun valueParametersToString(valueParameters: List): String { - val buff = StringBuilder("(") - valueParameters.dropLast(1).forEach { valueParameter -> - val parameter = valueParameterToString(valueParameter) - buff.append("$parameter, ") - } - valueParameters.lastOrNull()?.let { valueParameter -> - val parameter = valueParameterToString(valueParameter) - buff.append(parameter) - } - return buff.append(")").toString() - } + private fun ProtoBuf.Type.isCallable() = name().contains("Function") //-------------------------------------------------------------------------// - private fun valueParameterToString(protoValueParameter: ProtoBuf.ValueParameter): String { - val parameterName = stringTable.getString(protoValueParameter.name) - val typeId = protoValueParameter.typeId - val type = if (isCallableType(typeId)) callableTypeToString(typeId) - else typeToString(typeId) - - val flags = protoValueParameter.flags - val isCrossInline = crossInlineToString(Flags.IS_CROSSINLINE.get(flags)) - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - val protoAnnotations = protoValueParameter.getExtension(KonanSerializerProtocol.parameterAnnotation) - val annotations = annotationsToString(protoAnnotations) - - return "$annotations$isCrossInline$visibility$parameterName: $type" - } - - //-------------------------------------------------------------------------// - - private fun constructorValueParameterToString(protoValueParameter: ProtoBuf.ValueParameter): String { - val flags = protoValueParameter.flags - val isVar = if (Flags.IS_VAR.get(flags)) "var " else "val " - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - val parameterName = stringTable.getString(protoValueParameter.name) - val type = typeToString(protoValueParameter.typeId) - val protoAnnotations = protoValueParameter.getExtension(KonanSerializerProtocol.parameterAnnotation) - val annotations = annotationsToString(protoAnnotations) - - return "$annotations$visibility$isVar$parameterName: $type" - } - - //-------------------------------------------------------------------------// - - private fun enumEntryToString(protoEnumEntry: ProtoBuf.EnumEntry): String { - val buff = stringTable.getString(protoEnumEntry.name) - return buff - } - - //-------------------------------------------------------------------------// - - private fun printCompanionObject(protoClass: ProtoBuf.Class) { - if (!protoClass.hasCompanionObjectName()) return - val companionObjectName = stringTable.getString(protoClass.companionObjectName) - printer.println("companion object $companionObjectName") - } - - //-------------------------------------------------------------------------// - - private fun printNestedClass(nestedClass: Int) { - val nestedClassName = stringTable.getString(nestedClass) - printer.println("class $nestedClassName") - } + private fun ProtoBuf.Type.asString() = if (isCallable()) asCallableString() else asValueString() //--- Helpers -------------------------------------------------------------// - private fun getShortName(id: Int): String { + private fun getName(id: Int): String { val shortQualifiedName = qualifiedNameTable.getQualifiedName(id) - val shortStringId = shortQualifiedName.shortName - val shortName = stringTable.getString(shortStringId) - return shortName + val shortStringId = shortQualifiedName.shortName + return stringTable.getString(shortStringId) } //-------------------------------------------------------------------------// - fun getParentName(id: Int): String { - val childQualifiedName = qualifiedNameTable.getQualifiedName(id) - val parentQualifiedId = childQualifiedName.parentQualifiedName - val parentQualifiedName = qualifiedNameTable.getQualifiedName(parentQualifiedId) - val parentStringId = parentQualifiedName.shortName - val parentName = stringTable.getString(parentStringId) - return parentName + private fun getParentName(id: Int) = qualifiedNameTable.getQualifiedName(id).parentQualifiedName + 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.TypeParameter.Variance.asString(): String { + if (this == ProtoBuf.TypeParameter.Variance.INV) return "" + return toString().toLowerCase() + " " } //-------------------------------------------------------------------------// - private fun varianceToString(variance: ProtoBuf.TypeParameter.Variance): String { - if (variance == ProtoBuf.TypeParameter.Variance.INV) return "" - return variance.toString().toLowerCase() + " " - } - - //-------------------------------------------------------------------------// - - private fun upperBoundsToString(upperBounds: List): String { - val buff = StringBuilder() - upperBounds.forEach { buff.append(": " + typeToString(it)) } - return buff.toString() - } - - //-------------------------------------------------------------------------// - - private fun typeToString(typeId: Int): String { - val type = typeTableStack.last().getType(typeId) - val buff = StringBuilder(typeName(type)) - - val argumentList = type.argumentList - if (argumentList.isNotEmpty()) { - buff.append("<") - argumentList.dropLast(1).forEach { buff.append("${typeToString(it.typeId)}, ") } - argumentList.lastOrNull()?.let { - if (typeId != it.typeId) - buff.append(typeToString(it.typeId)) - } - buff.append(">") - } - if (type.nullable) buff.append("?") - return buff.toString() - } - - //-------------------------------------------------------------------------// - - private fun isCallableType(typeId: Int): Boolean { - val type = typeTableStack.last().getType(typeId) - return typeName(type).contains("Function") - } - - //-------------------------------------------------------------------------// - - private fun callableTypeToString(typeId: Int): String { - val callableType = typeTableStack.last().getType(typeId) - val buff = StringBuilder("(") - val argumentTypes = callableType.argumentList.dropLast(1) - val returnType = callableType.argumentList.lastOrNull() - - argumentTypes.dropLast(1).forEach { buff.append("${typeToString(it.typeId)}, ") } - argumentTypes.lastOrNull()?.let { buff.append(typeToString(it.typeId)) } - buff.append(") -> ") - if (returnType != null) buff.append(typeToString(returnType.typeId)) - return buff.toString() - } - - //-------------------------------------------------------------------------// - - private fun typeName(type: ProtoBuf.Type): String { - var typeName = "undefined" - if (type.hasClassName()) { - val qualifiedName = qualifiedNameTable.getQualifiedName(type.className) - val typeNameId = qualifiedName.shortName - typeName = stringTable.getString(typeNameId) - } - - if (type.hasTypeParameterName()) { - typeName = stringTable.getString(type.typeParameterName) - } - - if (type.hasTypeAliasName()) { - typeName = stringTable.getString(type.typeAliasName) - } - return typeName - } - - //-------------------------------------------------------------------------// - - private fun modalityToString(modality: ProtoBuf.Modality) = - when (modality) { + private fun ProtoBuf.Modality.asString() = + when (this) { ProtoBuf.Modality.FINAL -> "" ProtoBuf.Modality.OPEN -> "open " ProtoBuf.Modality.ABSTRACT -> "abstract " @@ -523,64 +337,57 @@ class PackageFragmentPrinter(val packageFragment: KonanLinkData.PackageFragment, //-------------------------------------------------------------------------// - private fun visibilityToString(visibility: ProtoBuf.Visibility) = - when (visibility) { + private fun ProtoBuf.Visibility.asString() = + when (this) { ProtoBuf.Visibility.INTERNAL -> "internal " ProtoBuf.Visibility.PRIVATE -> "private " ProtoBuf.Visibility.PROTECTED -> "protected " ProtoBuf.Visibility.PUBLIC -> "" ProtoBuf.Visibility.PRIVATE_TO_THIS -> "private " ProtoBuf.Visibility.LOCAL -> "local " + else -> "invalid visibility " } //-------------------------------------------------------------------------// - private fun inlineToString(isInline: Boolean): String { - if (isInline) return "inline " - return "" - } - - //-------------------------------------------------------------------------// - - private fun receiverTypeToString(protoFunction: ProtoBuf.Function): String { - if (!protoFunction.hasReceiverTypeId()) return "" - val receiverType = typeToString(protoFunction.receiverTypeId) - return receiverType + "." - } - - //-------------------------------------------------------------------------// - - private fun crossInlineToString(isCrossInline: Boolean): String { - if (isCrossInline) return "crossinline " - return "" - } - - //-------------------------------------------------------------------------// - - private fun returnTypeToString(protoFunction: ProtoBuf.Function): String { - val returnType = typeToString(protoFunction.returnTypeId) - if (returnType == "Unit") return "" - return ": " + returnType - } - - //-------------------------------------------------------------------------// - - private fun classOrInterface(protoClass: ProtoBuf.Class): String { - val flags = protoClass.flags - val classKind = Flags.CLASS_KIND.get(flags)!! - val modality = modalityToString(Flags.MODALITY.get(flags)) - val visibility = visibilityToString(Flags.VISIBILITY.get(flags)) - - val buff = StringBuilder("$modality$visibility") - when (classKind) { - ProtoBuf.Class.Kind.CLASS -> buff.append("class") - ProtoBuf.Class.Kind.INTERFACE -> buff.append("interface") - ProtoBuf.Class.Kind.ENUM_CLASS -> buff.append("enum class") - ProtoBuf.Class.Kind.ENUM_ENTRY -> buff.append("enum") - ProtoBuf.Class.Kind.ANNOTATION_CLASS -> buff.append("annotation class") - ProtoBuf.Class.Kind.OBJECT -> buff.append("object") - ProtoBuf.Class.Kind.COMPANION_OBJECT -> buff.append("companion object") + private fun ProtoBuf.Class.Kind.asString() = + when (this) { + ProtoBuf.Class.Kind.CLASS -> "class " + ProtoBuf.Class.Kind.INTERFACE -> "interface " + ProtoBuf.Class.Kind.ENUM_CLASS -> "enum class " + ProtoBuf.Class.Kind.ENUM_ENTRY -> "enum " + ProtoBuf.Class.Kind.ANNOTATION_CLASS -> "annotation class " + ProtoBuf.Class.Kind.OBJECT -> "object " + ProtoBuf.Class.Kind.COMPANION_OBJECT -> "companion object " + else -> "invalid member kind " } - return buff.toString() + + //-------------------------------------------------------------------------// + + private fun Flags.BooleanFlagField.asString(flags: Int) = + when(this) { + IS_INLINE -> if (Flags.IS_INLINE .get(flags)) "inline " else "" + IS_VAR -> if (Flags.IS_VAR .get(flags)) "var " else "val " + IS_CROSSINLINE -> if (Flags.IS_CROSSINLINE.get(flags)) "crossinline " else "" + IS_NOINLINE -> if (Flags.IS_NOINLINE .get(flags)) "noinline " else "" + else -> "unknown flag" + } + + //-------------------------------------------------------------------------// + + private fun ProtoBuf.Class.isRoot() = getParentName(fqName) == -1 + + //-------------------------------------------------------------------------// + + private fun Collection.joinTo(builder: StringBuilder, prefix: CharSequence = "", postfix: CharSequence = "", transform: ((T) -> CharSequence)? = null): String { + if (isEmpty()) return "" + return joinTo(builder, ", ", prefix, postfix, -1, "...", transform).toString() + } + + //-------------------------------------------------------------------------// + + private fun Collection.joinToString(prefix: CharSequence = "", postfix: CharSequence = "", transform: ((T) -> CharSequence)? = null): String { + if (isEmpty()) return "" + return joinTo(StringBuilder(), ", ", prefix, postfix, -1, "...", transform).toString() } }