From f9f97f2050488ef2d5f54e52bf57f26fbc2b3e8d Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Fri, 9 Feb 2024 15:30:01 +0100 Subject: [PATCH] [KLIB tool] Support metadata format by kotlinp Use the unified metadata printing format in KLIB tool. The same format is already used in `kotlinp` CLI tool. ^KT-62340 --- kotlin-native/klib/build.gradle.kts | 3 + .../cli/klib/KotlinpBasedMetadataDumper.kt | 239 ++++++++++++++++++ .../kotlin/cli/klib/ModuleDescriptorLoader.kt | 51 ++++ .../org/jetbrains/kotlin/cli/klib/main.kt | 105 ++------ 4 files changed, 321 insertions(+), 77 deletions(-) create mode 100644 kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KotlinpBasedMetadataDumper.kt create mode 100644 kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/ModuleDescriptorLoader.kt diff --git a/kotlin-native/klib/build.gradle.kts b/kotlin-native/klib/build.gradle.kts index 5a0ca01e411..3a5f1042331 100644 --- a/kotlin-native/klib/build.gradle.kts +++ b/kotlin-native/klib/build.gradle.kts @@ -18,6 +18,9 @@ dependencies { implementation(project(":compiler:ir.psi2ir")) implementation(project(":compiler:ir.serialization.native")) implementation(project(":kotlin-util-klib-abi")) + implementation(project(":tools:kotlinp-klib")) + implementation(project(":kotlinx-metadata-klib")) { isTransitive = false } + implementation(project(":kotlinx-metadata")) { isTransitive = false } } tasks.withType> { diff --git a/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KotlinpBasedMetadataDumper.kt b/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KotlinpBasedMetadataDumper.kt new file mode 100644 index 00000000000..e554f7c8dd9 --- /dev/null +++ b/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KotlinpBasedMetadataDumper.kt @@ -0,0 +1,239 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli.klib + +import kotlinx.metadata.KmConstructor +import kotlinx.metadata.KmFunction +import kotlinx.metadata.KmPackage +import kotlinx.metadata.KmProperty +import kotlinx.metadata.internal.common.KmModuleFragment +import kotlinx.metadata.klib.KlibModuleMetadata +import kotlinx.metadata.klib.className +import kotlinx.metadata.klib.fqName +import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer +import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerDesc +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.ir.util.IdSignatureRenderer +import org.jetbrains.kotlin.kotlinp.Printer +import org.jetbrains.kotlin.kotlinp.Settings +import org.jetbrains.kotlin.kotlinp.klib.* +import org.jetbrains.kotlin.kotlinp.klib.TypeArgumentId.VarianceId +import org.jetbrains.kotlin.library.KotlinIrSignatureVersion +import org.jetbrains.kotlin.library.KotlinLibrary +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.resolve.calls.components.isVararg +import org.jetbrains.kotlin.resolve.descriptorUtil.classId +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.utils.addToStdlib.runIf + +internal class KotlinpBasedMetadataDumper( + output: Appendable, + printSignatures: Boolean, + signatureVersion: KotlinIrSignatureVersion? +) { + // `null` means no signatures should be rendered. + private val signatureRenderer = runIf(printSignatures) { signatureVersion.getMostSuitableSignatureRenderer() } + + private val printer = Printer(output) + + fun dumpLibrary(library: KotlinLibrary, testMode: Boolean) { + val moduleMetadata = loadModuleMetadata(library) + .let { originalModuleMetadata -> if (testMode) preprocessMetadataForTests(originalModuleMetadata) else originalModuleMetadata } + + val signatureComputer = prepareSignatureComputer(library, moduleMetadata) + + KlibKotlinp(DEFAULT_SETTINGS, signatureComputer).renderModule(moduleMetadata, printer) + } + + private fun preprocessMetadataForTests(originalModuleMetadata: KlibModuleMetadata) = KlibModuleMetadata( + name = originalModuleMetadata.name, + fragments = originalModuleMetadata.fragments.groupBy { it.fqName }.mapNotNull { (packageFqName, fragments) -> + val classNames = fragments.flatMap { it.className }.sorted() + val classes = fragments.flatMap { it.classes }.sortedBy { it.name } + val functions = fragments.flatMap { it.pkg?.functions.orEmpty() }.sortedBy { it.sortingKey() } + val properties = fragments.flatMap { it.pkg?.properties.orEmpty() }.sortedBy { it.sortingKey() } + val typeAliases = fragments.flatMap { it.pkg?.typeAliases.orEmpty() }.sortedBy { it.name } + + if (classNames.isEmpty() && classes.isEmpty() && functions.isEmpty() && properties.isEmpty() && typeAliases.isEmpty()) + return@mapNotNull null + + classes.forEach { clazz -> + clazz.constructors.sortBy { it.sortingKey() } + clazz.functions.sortBy { it.sortingKey() } + clazz.properties.sortBy { it.sortingKey() } + clazz.typeAliases.sortBy { it.name } + } + + KmModuleFragment().apply { + this.fqName = packageFqName + this.className += classNames + this.classes += classes + + if (functions.isNotEmpty() || properties.isNotEmpty() || typeAliases.isNotEmpty()) { + this.pkg = KmPackage().apply { + this.functions += functions + this.properties += properties + this.typeAliases += typeAliases + } + } + } + }.sortedBy { it.fqName.orEmpty() }, + annotations = originalModuleMetadata.annotations + ) + + private fun loadModuleMetadata(library: KotlinLibrary) = KlibModuleMetadata.read( + object : KlibModuleMetadata.MetadataLibraryProvider { + override val moduleHeaderData get() = library.moduleHeaderData + override fun packageMetadata(fqName: String, partName: String) = library.packageMetadata(fqName, partName) + override fun packageMetadataParts(fqName: String) = library.packageMetadataParts(fqName) + } + ) + + private fun prepareSignatureComputer(library: KotlinLibrary, moduleMetadata: KlibModuleMetadata): ExternalSignatureComputer? { + val signatureCollector = SignaturesCollector(signatureRenderer ?: return null) + + val moduleDescriptor = ModuleDescriptorLoader.load(library) + moduleDescriptor.accept(signatureCollector, Unit) + + return ExternalSignatureComputer(moduleMetadata, signatureCollector.signatures::get) + } + + private fun KmConstructor.sortingKey() = constructorId("") + private fun KmFunction.sortingKey() = functionId("") + private fun KmProperty.sortingKey() = propertyId("") + + companion object { + private val DEFAULT_SETTINGS = Settings(isVerbose = true, sortDeclarations = true) + } +} + +private class SignaturesCollector(private val renderer: IdSignatureRenderer) : DeclarationDescriptorVisitorEmptyBodies() { + private val signaturer = KonanIdSignaturer(KonanManglerDesc) + + val signatures = hashMapOf() + + override fun visitModuleDeclaration(module: ModuleDescriptor, data: Unit) { + module.getPackageFragments().forEach { it.accept(this, data) } + } + + override fun visitPackageFragmentDescriptor(fragment: PackageFragmentDescriptor, data: Unit) { + fragment.getMemberScope().getContributedDescriptors().forEach { it.accept(this, data) } + } + + override fun visitClassDescriptor(clazz: ClassDescriptor, data: Unit) { + if (clazz.kind == ClassKind.ENUM_ENTRY) { + collectEnumEntrySignature(clazz) + } else { + collectSignature(clazz) { clazz.id() } + } + + clazz.constructors.forEach { it.accept(this, data) } + clazz.unsubstitutedMemberScope.getContributedDescriptors().forEach { it.accept(this, data) } + } + + override fun visitConstructorDescriptor(constructor: ConstructorDescriptor, data: Unit) { + collectSignature(constructor) { constructor.id() } + } + + override fun visitFunctionDescriptor(function: FunctionDescriptor, data: Unit) { + collectSignature(function) { function.id() } + } + + override fun visitPropertyDescriptor(property: PropertyDescriptor, data: Unit) { + collectSignature(property) { property.id() } + property.getter?.accept(this, data) + property.setter?.accept(this, data) + } + + override fun visitPropertyGetterDescriptor(getter: PropertyGetterDescriptor, data: Unit) { + collectSignature(getter) { getter.id() } + } + + override fun visitPropertySetterDescriptor(setter: PropertySetterDescriptor, data: Unit) { + collectSignature(setter) { setter.id(ignoreParameterNames = true) } + } + + override fun visitTypeAliasDescriptor(typeAlias: TypeAliasDescriptor, data: Unit) { + collectSignature(typeAlias) { typeAlias.id() } + } + + private inline fun collectSignature(descriptor: T, id: T.() -> DeclarationId?) { + val rawSignature = signaturer.composeSignature(descriptor) ?: return + val renderedSignature = renderer.render(rawSignature) + val declarationId = descriptor.id() ?: return + signatures[declarationId] = renderedSignature + } + + private fun collectEnumEntrySignature(clazz: ClassDescriptor) { + val rawSignature = signaturer.composeEnumEntrySignature(clazz) ?: return + val renderedSignature = renderer.render(rawSignature) + val declarationId = clazz.id() ?: return + signatures[declarationId] = renderedSignature + } + + private fun ClassifierDescriptorWithTypeParameters.id() = classId?.asString()?.let(::ClassOrTypeAliasId) + + private fun DeclarationDescriptor.qualifiedName(): String { + fun ClassifierDescriptorWithTypeParameters.classIdOrFail() = classId + ?: error("Failed to compute class ID for ${this::class.java}, $this") + + return when (this) { + is ClassifierDescriptorWithTypeParameters -> classIdOrFail() + is CallableDescriptor -> when (val containingDeclaration = containingDeclaration) { + is ClassifierDescriptorWithTypeParameters -> containingDeclaration.classIdOrFail().createNestedClassId(name) + is PackageFragmentDescriptor -> ClassId(containingDeclaration.fqName, name) + else -> containingDeclaration.unexpectedDeclarationType() + } + else -> unexpectedDeclarationType() + }.asString() + } + + private fun ConstructorDescriptor.id() = ConstructorId( + qualifiedName = qualifiedName(), + parameters = valueParameters.map { it.id(ignoreName = false) } + ) + + private fun PropertyDescriptor.id() = PropertyId( + qualifiedName = qualifiedName(), + contextReceivers = contextReceiverParameters.map { it.type.id() }, + extensionReceiver = extensionReceiverParameter?.type?.id(), + returnType = type.id() + ) + + private fun FunctionDescriptor.id(ignoreParameterNames: Boolean = false) = FunctionId( + qualifiedName = qualifiedName(), + contextReceivers = contextReceiverParameters.map { it.type.id() }, + extensionReceiver = extensionReceiverParameter?.type?.id(), + parameters = valueParameters.map { it.id(ignoreParameterNames) }, + returnType = returnType?.id() ?: error("Function without return type: ${this::class.java}, $this") + ) + + private fun Variance.id() = when (this) { + Variance.INVARIANT -> VarianceId.INVARIANT + Variance.IN_VARIANCE -> VarianceId.IN + Variance.OUT_VARIANCE -> VarianceId.OUT + } + + private fun SimpleType.classifierId(): ClassifierId = when (val typeConstructorDescriptor = constructor.declarationDescriptor) { + is TypeParameterDescriptor -> TypeParameterId(typeConstructorDescriptor.index) + is ClassifierDescriptorWithTypeParameters -> ClassOrTypeAliasId(typeConstructorDescriptor.qualifiedName()) + else -> typeConstructorDescriptor.unexpectedDeclarationType() + } + + private fun TypeProjection.id() = if (isStarProjection) TypeArgumentId.Star else TypeArgumentId.Regular(type.id(), projectionKind.id()) + + private fun KotlinType.id(): TypeId { + val simpleType = asSimpleType() + return TypeId(simpleType.classifierId(), simpleType.arguments.map { it.id() }) + } + + private fun ValueParameterDescriptor.id(ignoreName: Boolean) = + if (ignoreName) ParameterId(type.id(), isVararg) else ParameterId(name.asString(), type.id(), isVararg) + + private fun DeclarationDescriptor?.unexpectedDeclarationType(): Nothing = + error(if (this == null) "Declaration descriptor is null" else "Unexpected declaration type: ${this::class.java}, $this") +} diff --git a/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/ModuleDescriptorLoader.kt b/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/ModuleDescriptorLoader.kt new file mode 100644 index 00000000000..44356ccd4ea --- /dev/null +++ b/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/ModuleDescriptorLoader.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli.klib + +import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer +import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns +import org.jetbrains.kotlin.config.ApiVersion +import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib +import org.jetbrains.kotlin.konan.library.resolverByName +import org.jetbrains.kotlin.konan.target.Distribution +import org.jetbrains.kotlin.library.KotlinLibrary +import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories +import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.utils.KotlinNativePaths + +internal object ModuleDescriptorLoader { + fun load(library: KotlinLibrary): ModuleDescriptorImpl { + val storageManager = LockBasedStorageManager("klib") + + val module = KlibFactories.DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(library, languageVersionSettings, storageManager, null) + + val defaultModules = mutableListOf() + if (!module.isNativeStdlib()) { + val resolver = resolverByName( + emptyList(), + distributionKlib = Distribution(KotlinNativePaths.homePath.absolutePath).klib, + skipCurrentDir = true, + logger = KlibToolLogger + ) + resolver.defaultLinks(noStdLib = false, noDefaultLibs = true, noEndorsedLibs = true).mapTo(defaultModules) { + KlibFactories.DefaultDeserializedDescriptorFactory.createDescriptor(it, languageVersionSettings, storageManager, module.builtIns, null) + } + } + + (defaultModules + module).let { allModules -> + allModules.forEach { it.setDependencies(allModules) } + } + + return module + } + + val languageVersionSettings = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE) + + private val KlibFactories = KlibMetadataFactories(::KonanBuiltIns, DynamicTypeDeserializer) +} diff --git a/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt b/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt index 979e69164b2..70ab60109e0 100644 --- a/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt +++ b/kotlin-native/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt @@ -12,17 +12,10 @@ import org.jetbrains.kotlin.backend.common.serialization.BasicIrModuleDeserializ import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy import org.jetbrains.kotlin.backend.common.serialization.IrModuleDeserializer import org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker -import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerDesc import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr -import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns -import org.jetbrains.kotlin.config.ApiVersion -import org.jetbrains.kotlin.config.LanguageVersion -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl -import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.builders.TranslationPluginContext @@ -34,26 +27,19 @@ import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.resolverByName -import org.jetbrains.kotlin.konan.target.Distribution import org.jetbrains.kotlin.konan.util.DependencyDirectories -import org.jetbrains.kotlin.utils.KotlinNativePaths import org.jetbrains.kotlin.library.* import org.jetbrains.kotlin.library.abi.* -import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories -import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf import org.jetbrains.kotlin.library.metadata.kotlinLibrary import org.jetbrains.kotlin.library.metadata.parseModuleHeader import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl -import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.util.Logger import org.jetbrains.kotlin.util.removeSuffixIfPresent import java.io.File import kotlin.system.exitProcess import org.jetbrains.kotlin.konan.file.File as KFile -private val KlibFactories = KlibMetadataFactories(::KonanBuiltIns, DynamicTypeDeserializer) - fun printUsage() { println( """ @@ -79,9 +65,9 @@ fun printUsage() { (such as Compose) were used during compilation of the library, there would be different signatures for patched declarations. signatures [DEPRECATED] Renamed to "dump-metadata-signatures". Please, use new command name. - dump-metadata Dump the metadata of all non-private declarations in the library in the form of Kotlin-alike code. - The output of this command is intended to be used for debugging purposes only. - contents [DEPRECATED] Renamed to "dump-metadata". Please, use new command name. + dump-metadata Dump the metadata of all declarations in the library. The output of this command is intended + to be used for debugging purposes only. + contents [DEPRECATED] Reworked and renamed to "dump-metadata". Please, use new command name. and the options are: -repository [DEPRECATED] Local KLIB repositories to be dropped soon. See https://youtrack.jetbrains.com/issue/KT-61098 @@ -178,18 +164,6 @@ object KlibToolLogger : Logger, IrMessageLogger { val defaultRepository = KFile(DependencyDirectories.localKonanDir.resolve("klib").absolutePath) -open class ModuleDeserializer(val library: ByteArray) { - protected val moduleHeader: KlibMetadataProtoBuf.Header - get() = parseModuleHeader(library) - - val moduleName: String - get() = moduleHeader.moduleName - - val packageFragmentNameList: List - get() = moduleHeader.packageFragmentNameList - -} - private class KlibRepoDeprecationWarning { private var alreadyLogged = false @@ -216,7 +190,7 @@ class Library(val libraryNameOrPath: String, val requestedRepository: String?) { val headerCompilerVersion = library.versions.compilerVersion val headerLibraryVersion = library.versions.libraryVersion val headerMetadataVersion = library.versions.metadataVersion - val moduleName = ModuleDeserializer(library.moduleHeaderData).moduleName + val moduleName = parseModuleHeader(library.moduleHeaderData).moduleName println("") println("Resolved to: ${KFile(library.libraryName).absolutePath}") @@ -269,15 +243,15 @@ class Library(val libraryNameOrPath: String, val requestedRepository: String?) { } class KlibToolLinker( - module: ModuleDescriptor, irBuiltIns: IrBuiltIns, symbolTable: SymbolTable + module: ModuleDescriptor, irBuiltIns: IrBuiltIns, symbolTable: SymbolTable ) : KotlinIrLinker(module, KlibToolLogger, irBuiltIns, symbolTable, emptyList()) { override val fakeOverrideBuilder = IrLinkerFakeOverrideProvider( - linker = this, - symbolTable = symbolTable, - mangler = KonanManglerIr, - typeSystem = IrTypeSystemContextImpl(builtIns), - friendModules = emptyMap(), - partialLinkageSupport = PartialLinkageSupportForLinker.DISABLED, + linker = this, + symbolTable = symbolTable, + mangler = KonanManglerIr, + typeSystem = IrTypeSystemContextImpl(builtIns), + friendModules = emptyMap(), + partialLinkageSupport = PartialLinkageSupportForLinker.DISABLED, ) override val returnUnboundSymbolsIfSignatureNotFound: Boolean @@ -313,8 +287,7 @@ class Library(val libraryNameOrPath: String, val requestedRepository: String?) { @OptIn(ObsoleteDescriptorBasedAPI::class) fun dumpIr(output: Appendable, printSignatures: Boolean, signatureVersion: KotlinIrSignatureVersion?) { - val module = loadModule() - val library = module.kotlinLibrary + val library = libraryInRepoOrCurrentDir(repository, libraryNameOrPath) checkLibraryHasIr(library) if (signatureVersion != null && signatureVersion != KotlinIrSignatureVersion.V2) { @@ -322,10 +295,11 @@ class Library(val libraryNameOrPath: String, val requestedRepository: String?) { logWarning("using a non-default signature version in \"dump-ir\" is not supported yet") } - val versionSpec = LanguageVersionSettingsImpl(currentLanguageVersion, currentApiVersion) + val module = ModuleDescriptorLoader.load(library) + val idSignaturer = KonanIdSignaturer(KonanManglerDesc) val symbolTable = SymbolTable(idSignaturer, IrFactoryImpl) - val typeTranslator = TypeTranslatorImpl(symbolTable, versionSpec, module) + val typeTranslator = TypeTranslatorImpl(symbolTable, ModuleDescriptorLoader.languageVersionSettings, module) val irBuiltIns = IrBuiltInsOverDescriptors(module.builtIns, typeTranslator, symbolTable) val linker = KlibToolLinker(module, irBuiltIns, symbolTable) @@ -391,11 +365,7 @@ class Library(val libraryNameOrPath: String, val requestedRepository: String?) { fun contents(output: Appendable, printSignatures: Boolean, signatureVersion: KotlinIrSignatureVersion?) { logWarning("\"contents\" has been renamed to \"dump-metadata\". Please, use new command name.") - dumpMetadata(output, printSignatures, signatureVersion) - } - - fun dumpMetadata(output: Appendable, printSignatures: Boolean, signatureVersion: KotlinIrSignatureVersion?) { - val module = loadModule() + val module = ModuleDescriptorLoader.load(libraryInRepoOrCurrentDir(repository, libraryNameOrPath)) val signatureRenderer = if (printSignatures) DefaultKlibSignatureRenderer(signatureVersion, "// Signature: ") else @@ -405,13 +375,23 @@ class Library(val libraryNameOrPath: String, val requestedRepository: String?) { printer.print(module) } + /** + * @param testMode if `true` then a special pre-processing is performed towards the metadata before rendering: + * - empty package fragments are removed + * - package fragments with the same package FQN are merged + * - classes are sorted in alphabetical order + */ + fun dumpMetadata(output: Appendable, printSignatures: Boolean, signatureVersion: KotlinIrSignatureVersion?, testMode: Boolean) { + KotlinpBasedMetadataDumper(output, printSignatures, signatureVersion).dumpLibrary(libraryInCurrentDir(libraryNameOrPath), testMode) + } + fun signatures(output: Appendable, signatureVersion: KotlinIrSignatureVersion?) { logWarning("\"signatures\" has been renamed to \"dump-metadata-signatures\". Please, use new command name.") dumpMetadataSignatures(output, signatureVersion) } fun dumpMetadataSignatures(output: Appendable, signatureVersion: KotlinIrSignatureVersion?) { - val module = loadModule() + val module = ModuleDescriptorLoader.load(libraryInRepoOrCurrentDir(repository, libraryNameOrPath)) // Don't call `checkSupportedInLibrary()` - the signatures are anyway generated on the fly. val printer = SignaturePrinter(output, DefaultKlibSignatureRenderer(signatureVersion)) @@ -437,37 +417,8 @@ class Library(val libraryNameOrPath: String, val requestedRepository: String?) { logError("Signature version ${this.number} is not supported in library ${library.libraryFile}." + " Supported versions: ${supportedSignatureVersions.joinToString { it.number.toString() }}") } - - private fun loadModule(): ModuleDescriptor { - val storageManager = LockBasedStorageManager("klib") - val library = libraryInRepoOrCurrentDir(repository, libraryNameOrPath) - val versionSpec = LanguageVersionSettingsImpl(currentLanguageVersion, currentApiVersion) - val module = KlibFactories.DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(library, versionSpec, storageManager, null) - - val defaultModules = mutableListOf() - if (!module.isNativeStdlib()) { - val resolver = resolverByName( - emptyList(), - distributionKlib = Distribution(KotlinNativePaths.homePath.absolutePath).klib, - skipCurrentDir = true, - 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) } - } - - return module - } } -val currentLanguageVersion = LanguageVersion.LATEST_STABLE -val currentApiVersion = ApiVersion.LATEST_STABLE - fun libraryInRepo(repository: KFile, name: String) = resolverByName(listOf(repository.absolutePath), skipCurrentDir = true, logger = KlibToolLogger).resolve(name) @@ -500,7 +451,7 @@ fun main(args: Array) { "dump-abi" -> library.dumpAbi(System.out, signatureVersion) "dump-ir" -> library.dumpIr(System.out, printSignatures, signatureVersion) "dump-ir-signatures" -> library.dumpIrSignatures(System.out, signatureVersion) - "dump-metadata" -> library.dumpMetadata(System.out, printSignatures, signatureVersion) + "dump-metadata" -> library.dumpMetadata(System.out, printSignatures, signatureVersion, testMode = false) "dump-metadata-signatures" -> library.dumpMetadataSignatures(System.out, signatureVersion) "contents" -> library.contents(System.out, printSignatures, signatureVersion) "signatures" -> library.signatures(System.out, signatureVersion)