From 13cf470e33b8263ffda04a69dc63f205b3acc957 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Tue, 6 Oct 2020 14:52:53 +0300 Subject: [PATCH] [KLIB tool] Print ID signatures --- .../cli/klib/DeclarationHeaderRenderer.kt | 7 + .../kotlin/cli/klib/DeclarationPrinter.kt | 100 +++++++++++ .../klib/DefaultDeclarationHeaderRenderer.kt | 79 +++++++++ .../cli/klib/DefaultIdSignatureRenderer.kt | 24 +++ .../kotlin/cli/klib/IdSignatureRenderer.kt | 13 ++ .../jetbrains/kotlin/cli/klib/KlibPrinter.kt | 163 ------------------ .../kotlin/cli/klib/SignaturePrinter.kt | 55 ++++++ .../org/jetbrains/kotlin/cli/klib/main.kt | 50 ++++-- .../kotlin/cli/klib/test/ContentsTest.kt | 4 +- 9 files changed, 314 insertions(+), 181 deletions(-) create mode 100644 klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationHeaderRenderer.kt create mode 100644 klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationPrinter.kt create mode 100644 klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultDeclarationHeaderRenderer.kt create mode 100644 klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultIdSignatureRenderer.kt create mode 100644 klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/IdSignatureRenderer.kt delete mode 100644 klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt create mode 100644 klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/SignaturePrinter.kt diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationHeaderRenderer.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationHeaderRenderer.kt new file mode 100644 index 00000000000..4523ed42b25 --- /dev/null +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationHeaderRenderer.kt @@ -0,0 +1,7 @@ +package org.jetbrains.kotlin.cli.klib + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor + +interface DeclarationHeaderRenderer { + fun render(descriptor: DeclarationDescriptor): String +} diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationPrinter.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationPrinter.kt new file mode 100644 index 00000000000..2298c34926f --- /dev/null +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DeclarationPrinter.kt @@ -0,0 +1,100 @@ +package org.jetbrains.kotlin.cli.klib + +import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.utils.Printer + +class DeclarationPrinter( + out: Appendable, + private val headerRenderer: DeclarationHeaderRenderer, + private val signatureRenderer: IdSignatureRenderer +) { + private val printer = Printer(out, 1, " ") + + private val DeclarationDescriptorWithVisibility.isPublicOrProtected: Boolean + get() = visibility == DescriptorVisibilities.PUBLIC || visibility == DescriptorVisibilities.PROTECTED + + private val CallableMemberDescriptor.isFakeOverride: Boolean + get() = kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE + + private val DeclarationDescriptor.shouldBePrinted: Boolean + get() = this is ClassifierDescriptorWithTypeParameters && isPublicOrProtected + || this is CallableMemberDescriptor && isPublicOrProtected && !isFakeOverride + + fun print(module: ModuleDescriptor) { + module.accept(PrinterVisitor(), Unit) + } + + private fun Printer.printWithBody(header: String, signature: String? = null, body: () -> Unit) { + println() + printPlain(header, signature, suffix = " {") + pushIndent() + body() + popIndent() + println("}") + println() + } + + private fun Printer.printPlain(header: String, signature: String? = null, suffix: String? = null) { + if (signature != null) println(signature) + println(if (suffix != null ) header + suffix else header) + } + + private inner class PrinterVisitor : DeclarationDescriptorVisitorEmptyBodies() { + override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: Unit) { + descriptor.getPackageFragments().forEach { it.accept(this, data) } + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: Unit) { + val children = descriptor.getMemberScope().getContributedDescriptors().filter { it.shouldBePrinted } + if (children.isNotEmpty()) { + printer.printWithBody(header = headerRenderer.render(descriptor)) { + children.forEach { it.accept(this, data) } + } + } + } + + override fun visitClassDescriptor(descriptor: ClassDescriptor, data: Unit) { + val header = headerRenderer.render(descriptor) + val signature = signatureRenderer.render(descriptor) + + val children = descriptor.unsubstitutedMemberScope.getContributedDescriptors().filter { it.shouldBePrinted } + val constructors = descriptor.constructors.filter { !it.isPrimary && it.shouldBePrinted } + if (children.isNotEmpty() || constructors.isNotEmpty()) { + printer.printWithBody(header, signature) { + constructors.forEach { it.accept(this, data) } + children.forEach { it.accept(this, data) } + } + } else { + printer.printPlain(header, signature) + } + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit) { + printer.printPlain(header = headerRenderer.render(descriptor), signature = signatureRenderer.render(descriptor)) + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit) { + printer.printPlain(header = headerRenderer.render(descriptor), signature = signatureRenderer.render(descriptor)) + descriptor.getter?.takeIf { !it.annotations.isEmpty() }?.let { getter -> + printer.pushIndent() + printer.printPlain(header = headerRenderer.render(getter), signature = signatureRenderer.render(getter)) + printer.popIndent() + } + descriptor.setter?.takeIf { !it.annotations.isEmpty() || it.visibility != descriptor.visibility }?.let { setter -> + printer.pushIndent() + printer.printPlain(header = headerRenderer.render(setter), signature = signatureRenderer.render(setter)) + printer.popIndent() + } + } + + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit) { + printer.printPlain(header = headerRenderer.render(descriptor), signature = signatureRenderer.render(descriptor)) + } + + override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: Unit) { + printer.printPlain(header = headerRenderer.render(descriptor), signature = signatureRenderer.render(descriptor)) + } + } +} diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultDeclarationHeaderRenderer.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultDeclarationHeaderRenderer.kt new file mode 100644 index 00000000000..efd252eec42 --- /dev/null +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultDeclarationHeaderRenderer.kt @@ -0,0 +1,79 @@ +package org.jetbrains.kotlin.cli.klib + +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.renderer.DescriptorRendererModifier +import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy + +object DefaultDeclarationHeaderRenderer : DeclarationHeaderRenderer { + override fun render(descriptor: DeclarationDescriptor): String = when (descriptor) { + is PackageFragmentDescriptor -> render(descriptor) + is ClassifierDescriptorWithTypeParameters -> render(descriptor) + is PropertyAccessorDescriptor -> render(descriptor) + is CallableMemberDescriptor -> render(descriptor) + else -> throw AssertionError("Unknown declaration descriptor type: $descriptor") + } + + private fun render(descriptor: PackageFragmentDescriptor): String { + val packageName = descriptor.fqName.let { if (it.isRoot) "" else it.asString() } + return "package $packageName" + } + + private fun render(descriptor: ClassifierDescriptorWithTypeParameters): String { + val renderer = when (descriptor.modality) { + // Don't render 'final' modality + Modality.FINAL -> Renderers.WITHOUT_MODALITY + else -> Renderers.DEFAULT + } + return renderer.render(descriptor) + } + + private fun render(descriptor: CallableMemberDescriptor): String { + val containingDeclaration = descriptor.containingDeclaration + val renderer = when { + // Don't render modality for non-override final methods and interface methods. + containingDeclaration is ClassDescriptor && containingDeclaration.kind == ClassKind.INTERFACE || + descriptor.modality == Modality.FINAL && descriptor.overriddenDescriptors.isEmpty() -> Renderers.WITHOUT_MODALITY + else -> Renderers.DEFAULT + } + return renderer.render(descriptor) + } + + private fun render(descriptor: PropertyAccessorDescriptor) = buildString { + descriptor.annotations.forEach { + append(Renderers.DEFAULT.renderAnnotation(it)).append(" ") + } + if (descriptor.visibility != DescriptorVisibilities.DEFAULT_VISIBILITY) { + append(descriptor.visibility.internalDisplayName).append(" ") + } + when (descriptor) { + is PropertyGetterDescriptor -> append("get") + is PropertySetterDescriptor -> append("set") + else -> throw AssertionError("Unknown accessor descriptor type: $descriptor") + } + } + + private object Renderers { + val DEFAULT = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions { + modifiers = DescriptorRendererModifier.ALL + overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE + annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY + excludedAnnotationClasses += StandardNames.FqNames.suppress + + classWithPrimaryConstructor = true + renderConstructorKeyword = true + includePropertyConstant = true + + unitReturnType = false + withDefinedIn = false + renderDefaultVisibility = false + secondaryConstructorsAsPrimary = false + } + + val WITHOUT_MODALITY = DEFAULT.withOptions { + modifiers -= DescriptorRendererModifier.MODALITY + } + } +} diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultIdSignatureRenderer.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultIdSignatureRenderer.kt new file mode 100644 index 00000000000..33e38813c1c --- /dev/null +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/DefaultIdSignatureRenderer.kt @@ -0,0 +1,24 @@ +package org.jetbrains.kotlin.cli.klib + +import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer +import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerDesc +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor + +class DefaultIdSignatureRenderer(private val prefix: String? = null) : IdSignatureRenderer { + private val idSignaturer = KonanIdSignaturer(KonanManglerDesc) + + override fun render(descriptor: DeclarationDescriptor): String? { + val idSignature = if (descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY) { + idSignaturer.composeEnumEntrySignature(descriptor) + } else { + idSignaturer.composeSignature(descriptor) + } ?: return null + + return if (prefix != null) + prefix + idSignature.render() + else + idSignature.render() + } +} diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/IdSignatureRenderer.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/IdSignatureRenderer.kt new file mode 100644 index 00000000000..cbbae6b8617 --- /dev/null +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/IdSignatureRenderer.kt @@ -0,0 +1,13 @@ +package org.jetbrains.kotlin.cli.klib + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor + +interface IdSignatureRenderer { + fun render(descriptor: DeclarationDescriptor): String? + + companion object { + val NO_SIGNATURE = object : IdSignatureRenderer { + override fun render(descriptor: DeclarationDescriptor): String? = null + } + } +} diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt deleted file mode 100644 index 1becd5c8f7e..00000000000 --- a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.cli.klib - -import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.builtins.StandardNames -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies -import org.jetbrains.kotlin.renderer.* -import org.jetbrains.kotlin.utils.Printer - -class KlibPrinter(out: Appendable) { - - val printer = Printer(out, 1, " ") - - val DeclarationDescriptorWithVisibility.isPublicOrProtected: Boolean - get() = visibility == DescriptorVisibilities.PUBLIC || visibility == DescriptorVisibilities.PROTECTED - - val CallableMemberDescriptor.isFakeOverride: Boolean - get() = kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE - - val DeclarationDescriptor.shouldBePrinted: Boolean - get() = this is ClassifierDescriptorWithTypeParameters && isPublicOrProtected - || this is CallableMemberDescriptor && isPublicOrProtected && !isFakeOverride - - private fun Printer.printBody(header: CharSequence, block: () -> Unit) { - println() - println("$header {") - pushIndent() - block() - popIndent() - println("}") - println() - } - - private fun ClassifierDescriptorWithTypeParameters.render(): String { - val renderer = when (modality) { - // Don't render 'final' modality - Modality.FINAL -> Renderers.WITHOUT_MODALITY - else -> Renderers.DEFAULT - } - return renderer.render(this) - } - - private fun CallableMemberDescriptor.render(): String { - val containingDeclaration = containingDeclaration - val renderer = when { - // Don't render modality for non-override final methods and interface methods. - containingDeclaration is ClassDescriptor && containingDeclaration.kind == ClassKind.INTERFACE || - modality == Modality.FINAL && overriddenDescriptors.isEmpty() -> - Renderers.WITHOUT_MODALITY - else -> Renderers.DEFAULT - } - return renderer.render(this) - } - - private fun PropertyAccessorDescriptor.render() = buildString { - annotations.forEach { - append(Renderers.DEFAULT.renderAnnotation(it)).append(" ") - } - if (visibility != DescriptorVisibilities.DEFAULT_VISIBILITY) { - append(visibility.internalDisplayName).append(" ") - } - when (this@render) { - is PropertyGetterDescriptor -> append("get") - is PropertySetterDescriptor -> append("set") - else -> throw AssertionError("Unknown accessor descriptor type: ${this@render}") - } - } - - fun print(module: ModuleDescriptor) { - module.accept(PrinterVisitor(), Unit) - } - - private inner class PrinterVisitor : DeclarationDescriptorVisitorEmptyBodies() { - override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: Unit) { - descriptor.getPackageFragments().forEach { - it.accept(this, data) - } - } - - override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: Unit) { - val children = descriptor.getMemberScope().getContributedDescriptors().filter { it.shouldBePrinted } - if (children.isNotEmpty()) { - val packageName = descriptor.fqName.let { if (it.isRoot) "" else it.asString() } - val header = "package $packageName" - printer.printBody(header) { - children.forEach { it.accept(this, data) } - } - } - } - - override fun visitClassDescriptor(descriptor: ClassDescriptor, data: Unit) { - val children = descriptor.unsubstitutedMemberScope.getContributedDescriptors().filter { it.shouldBePrinted } - val constructors = descriptor.constructors.filter { !it.isPrimary && it.shouldBePrinted } - val header = descriptor.render() - if (children.isNotEmpty() || constructors.isNotEmpty()) { - printer.printBody(header) { - constructors.forEach { it.accept(this, data) } - children.forEach { it.accept(this, data) } - } - } else { - printer.println(header) - } - } - - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit) { - printer.println(descriptor.render()) - } - - override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit) { - printer.println(descriptor.render()) - descriptor.getter?.let { getter -> - if (!getter.annotations.isEmpty()) { - printer.pushIndent() - printer.println(getter.render()) - printer.popIndent() - } - } - descriptor.setter?.let { setter -> - if (!setter.annotations.isEmpty() || setter.visibility != descriptor.visibility) { - printer.pushIndent() - printer.println(setter.render()) - printer.popIndent() - } - } - } - - override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit) { - printer.println(descriptor.render()) - } - - override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: Unit) { - printer.println(descriptor.render()) - } - } - - object Renderers { - val DEFAULT = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions { - modifiers = DescriptorRendererModifier.ALL - overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE - annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY - excludedAnnotationClasses += setOf(StandardNames.FqNames.suppress) - - classWithPrimaryConstructor = true - renderConstructorKeyword = true - includePropertyConstant = true - - unitReturnType = false - withDefinedIn = false - renderDefaultVisibility = false - secondaryConstructorsAsPrimary = false - } - val WITHOUT_MODALITY = DEFAULT.withOptions { - modifiers -= DescriptorRendererModifier.MODALITY - } - } - -} diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/SignaturePrinter.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/SignaturePrinter.kt new file mode 100644 index 00000000000..50dd51edc47 --- /dev/null +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/SignaturePrinter.kt @@ -0,0 +1,55 @@ +package org.jetbrains.kotlin.cli.klib + +import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.utils.Printer + +class SignaturePrinter( + out: Appendable, + private val signatureRenderer: IdSignatureRenderer +) { + private val printer = Printer(out) + + fun print(module: ModuleDescriptor) { + module.accept(PrinterVisitor(), Unit) + } + + private fun Printer.printlnIfNotNull(line: String?) { + if (line != null) println(line) + } + + private inner class PrinterVisitor : DeclarationDescriptorVisitorEmptyBodies() { + override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: Unit) { + descriptor.getPackageFragments().forEach { it.accept(this, data) } + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: Unit) { + descriptor.getMemberScope().getContributedDescriptors().forEach { it.accept(this, data) } + } + + override fun visitClassDescriptor(descriptor: ClassDescriptor, data: Unit) { + printer.printlnIfNotNull(signatureRenderer.render(descriptor)) + descriptor.constructors.forEach { it.accept(this, data) } + descriptor.unsubstitutedMemberScope.getContributedDescriptors().forEach { it.accept(this, data) } + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit) { + printer.printlnIfNotNull(signatureRenderer.render(descriptor)) + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit) { + printer.printlnIfNotNull(signatureRenderer.render(descriptor)) + descriptor.getter?.let { printer.printlnIfNotNull(signatureRenderer.render(it)) } + descriptor.setter?.let { printer.printlnIfNotNull(signatureRenderer.render(it)) } + } + + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit) { + printer.printlnIfNotNull(signatureRenderer.render(descriptor)) + } + + override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: Unit) { + printer.printlnIfNotNull(signatureRenderer.render(descriptor)) + } + } +} diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt index 422dfe4e0f7..591799bc1a8 100644 --- a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.konan.util.KlibMetadataFactories import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentTypeTransformer import org.jetbrains.kotlin.util.Logger import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf @@ -28,7 +29,6 @@ import org.jetbrains.kotlin.konan.library.resolverByName import org.jetbrains.kotlin.konan.util.KonanHomeProvider import org.jetbrains.kotlin.library.metadata.parseModuleHeader import org.jetbrains.kotlin.storage.LockBasedStorageManager -import java.lang.System.out import kotlin.system.exitProcess internal val KlibFactories = KlibMetadataFactories(::KonanBuiltIns, DynamicTypeDeserializer, PlatformDependentTypeTransformer.None) @@ -39,15 +39,17 @@ fun printUsage() { println("\tinfo\tgeneral information about the library") println("\tinstall\tinstall the library to the local repository") println("\tcontents\tlist contents of the library") + println("\tsignatures\tlist of ID signatures in the library") println("\tremove\tremove the library from the local repository") println("and the options are:") println("\t-repository \twork with the specified repository") println("\t-target \tinspect specifics of the given target") + println("\t-print-signatures [true|false]\tprint ID signature for every declaration (only for \"contents\" command)") } private fun parseArgs(args: Array): Map> { val commandLine = mutableMapOf>() - for (index in 0..args.size - 1 step 2) { + for (index in args.indices step 2) { val key = args[index] if (key[0] != '-') { throw IllegalArgumentException("Expected a flag with initial dash: $key") @@ -62,13 +64,14 @@ private fun parseArgs(args: Array): Map> { } -class Command(args: Array){ +class Command(args: Array) { init { if (args.size < 2) { printUsage() exitProcess(0) } } + val verb = args[0] val library = args[1] val options = parseArgs(args.drop(2).toTypedArray()) @@ -160,8 +163,22 @@ class Library(val name: String, val requestedRepository: String?, val target: St library?.libraryFile?.deleteRecursively() } - fun contents(output: Appendable = out) { + fun contents(output: Appendable, printSignatures: Boolean) { + val module = loadModule() + val signatureRenderer = if (printSignatures) DefaultIdSignatureRenderer("// ID signature: ") else IdSignatureRenderer.NO_SIGNATURE + val printer = DeclarationPrinter(output, DefaultDeclarationHeaderRenderer, signatureRenderer) + printer.print(module) + } + + fun signatures(output: Appendable) { + val module = loadModule() + val printer = SignaturePrinter(output, DefaultIdSignatureRenderer()) + + printer.print(module) + } + + private fun loadModule(): ModuleDescriptor { val storageManager = LockBasedStorageManager("klib") val library = libraryInRepoOrCurrentDir(repository, name) val versionSpec = LanguageVersionSettingsImpl(currentLanguageVersion, currentApiVersion) @@ -173,19 +190,18 @@ class Library(val name: String, val requestedRepository: String?, val target: St emptyList(), distributionKlib = Distribution(KonanHomeProvider.determineKonanHome()).klib, skipCurrentDir = true, - logger = KlibToolLogger) - resolver.defaultLinks(false, true, true) - .mapTo(defaultModules) { - KlibFactories.DefaultDeserializedDescriptorFactory.createDescriptor( - it, versionSpec, storageManager, module.builtIns, null) - } + logger = KlibToolLogger + ) + resolver.defaultLinks(false, true, true).mapTo(defaultModules) { + KlibFactories.DefaultDeserializedDescriptorFactory.createDescriptor(it, versionSpec, storageManager, module.builtIns, null) + } } (defaultModules + module).let { allModules -> allModules.forEach { it.setDependencies(allModules) } } - KlibPrinter(output).print(module) + return module } } @@ -208,15 +224,17 @@ fun main(args: Array) { val target = targetManager.targetName val repository = command.options["-repository"]?.last() + val printSignatures = command.options["-print-signatures"]?.last()?.toBoolean() == true val library = Library(command.library, repository, target) when (command.verb) { - "contents" -> library.contents() - "info" -> library.info() - "install" -> library.install() - "remove" -> library.remove() - else -> error("Unknown command ${command.verb}.") + "contents" -> library.contents(System.out, printSignatures) + "signatures" -> library.signatures(System.out) + "info" -> library.info() + "install" -> library.install() + "remove" -> library.remove() + else -> error("Unknown command ${command.verb}.") } } diff --git a/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt b/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt index ba526e7eb1d..ab55d672b03 100644 --- a/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt +++ b/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt @@ -19,7 +19,7 @@ class ContentsTest { private fun klibContents(library: String, printOutput: Boolean = false, expected: () -> String) { val output = StringBuilder() val lib = Library(library, null, "host") - lib.contents(output) + lib.contents(output, false) if (printOutput) { println(output.trim().toString()) } @@ -34,7 +34,7 @@ class ContentsTest { fun `Stdlib content should be printed without exceptions`() { val output = StringBuilder() val distributionPath = System.getProperty("konan.home") - Library(Distribution(distributionPath).stdlib, null, "host").contents(output) + Library(Distribution(distributionPath).stdlib, null, "host").contents(output, false) } @Test