diff --git a/libraries/kotlinx-metadata/jvm/ReadMe.md b/libraries/kotlinx-metadata/jvm/ReadMe.md index 1f6d9bb11b7..2f927d31e98 100644 --- a/libraries/kotlinx-metadata/jvm/ReadMe.md +++ b/libraries/kotlinx-metadata/jvm/ReadMe.md @@ -62,10 +62,10 @@ when (metadata) { ``` Let's assume we've obtained an instance of `KotlinClassMetadata.Class`; other kinds of classes are handled similarly, except some of them have metadata in a slightly different form. -The main way to make sense of the underlying metadata is to invoke `toKmClass()`, which returns an instance of `KmClass` (`Km` is a shorthand for “Kotlin metadata”): +The main way to make sense of the underlying metadata is to access the `kmClass` property, which returns an instance of `KmClass` (`Km` is a shorthand for “Kotlin metadata”): ```kotlin -val klass = metadata.toKmClass() +val klass = metadata.kmClass println(klass.functions.map { it.name }) println(klass.properties.map { it.name }) ``` @@ -92,7 +92,7 @@ if (Flag.Function.IS_SUSPEND(function.flags)) { ## Writing metadata To create metadata of a Kotlin class file from scratch, construct an instance of `KmClass`/`KmPackage`/`KmLambda`, fill it with the data and call corresponding `KotlinClassMetadata.write` function. -Resulting `KotlinClassMetadata.annotationData` can be used to write `kotlin.Metadata` annotation on a class file. +Resulting `kotlin.Metadata` annotation can be written to a class file. When using metadata writers from Kotlin source code, it's very convenient to use Kotlin scoping functions such as `apply` to reduce boilerplate: @@ -113,7 +113,7 @@ val klass = KmClass().apply { ... } -val annotation = KotlinClassMetadata.writeClass(klass).annotationData +val annotation = KotlinClassMetadata.writeClass(klass) // Write annotation directly or use annotation.kind, annotation.data1, annotation.data2, etc. ``` @@ -131,29 +131,10 @@ The only difference is that the source for the reader (and the result of the wri // Read the module metadata val bytes = File("META-INF/main.kotlin_module").readBytes() val metadata = KotlinModuleMetadata.read(bytes) -val module = metadata.toKmModule() +val module = metadata.kmModule ... // Write the module metadata -val bytes = KotlinModuleMetadata.write(module).bytes +val bytes = KotlinModuleMetadata.write(module) File("META-INF/main.kotlin_module").writeBytes(bytes) ``` - -## Laziness - -Note that until you load the actual underlying data of a `KotlinClassMetadata` or `KotlinModuleMetadata` instance by invoking one of the `toKm...` methods, -the data is not completely parsed and verified. If you need to check if the data is not horribly corrupted before proceeding, ensure that either of those is called: - -```kotlin -val metadata: KotlinClassMetadata.Class = ... - -try { - // Guarantees eager parsing of the underlying data - metadata.toKmClass() -} catch (e: Exception) { - System.err.println("Metadata is corrupted!") -} -``` - - - diff --git a/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api b/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api index ec850d20e61..63b17ad3577 100644 --- a/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api +++ b/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api @@ -1254,30 +1254,30 @@ public abstract class kotlinx/metadata/jvm/KotlinClassMetadata { public static final field MULTI_FILE_CLASS_PART_KIND I public static final field SYNTHETIC_CLASS_KIND I public synthetic fun (Lkotlin/Metadata;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getAnnotationData ()Lkotlin/Metadata; public static final fun read (Lkotlin/Metadata;)Lkotlinx/metadata/jvm/KotlinClassMetadata; - public static final fun writeClass (Lkotlinx/metadata/KmClass;)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class; - public static final fun writeClass (Lkotlinx/metadata/KmClass;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class; - public static final fun writeClass (Lkotlinx/metadata/KmClass;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class; - public static final fun writeFileFacade (Lkotlinx/metadata/KmPackage;)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade; - public static final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade; - public static final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade; - public static final fun writeLambda (Lkotlinx/metadata/KmLambda;)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public static final fun writeLambda (Lkotlinx/metadata/KmLambda;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public static final fun writeLambda (Lkotlinx/metadata/KmLambda;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public static final fun writeMultiFileClassFacade (Ljava/util/List;)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade; - public static final fun writeMultiFileClassFacade (Ljava/util/List;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade; - public static final fun writeMultiFileClassFacade (Ljava/util/List;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade; - public static final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart; - public static final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart; - public static final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart; - public static final fun writeSyntheticClass ()Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public static final fun writeSyntheticClass ([I)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public static final fun writeSyntheticClass ([II)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; + public static final fun writeClass (Lkotlinx/metadata/KmClass;)Lkotlin/Metadata; + public static final fun writeClass (Lkotlinx/metadata/KmClass;[I)Lkotlin/Metadata; + public static final fun writeClass (Lkotlinx/metadata/KmClass;[II)Lkotlin/Metadata; + public static final fun writeFileFacade (Lkotlinx/metadata/KmPackage;)Lkotlin/Metadata; + public static final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[I)Lkotlin/Metadata; + public static final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[II)Lkotlin/Metadata; + public static final fun writeLambda (Lkotlinx/metadata/KmLambda;)Lkotlin/Metadata; + public static final fun writeLambda (Lkotlinx/metadata/KmLambda;[I)Lkotlin/Metadata; + public static final fun writeLambda (Lkotlinx/metadata/KmLambda;[II)Lkotlin/Metadata; + public static final fun writeMultiFileClassFacade (Ljava/util/List;)Lkotlin/Metadata; + public static final fun writeMultiFileClassFacade (Ljava/util/List;[I)Lkotlin/Metadata; + public static final fun writeMultiFileClassFacade (Ljava/util/List;[II)Lkotlin/Metadata; + public static final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;)Lkotlin/Metadata; + public static final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[I)Lkotlin/Metadata; + public static final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[II)Lkotlin/Metadata; + public static final fun writeSyntheticClass ()Lkotlin/Metadata; + public static final fun writeSyntheticClass ([I)Lkotlin/Metadata; + public static final fun writeSyntheticClass ([II)Lkotlin/Metadata; } public final class kotlinx/metadata/jvm/KotlinClassMetadata$Class : kotlinx/metadata/jvm/KotlinClassMetadata { public final fun accept (Lkotlinx/metadata/KmClassVisitor;)V + public final fun getKmClass ()Lkotlinx/metadata/KmClass; public final fun toKmClass ()Lkotlinx/metadata/KmClass; } @@ -1291,34 +1291,35 @@ public final class kotlinx/metadata/jvm/KotlinClassMetadata$Class$Writer : kotli public final class kotlinx/metadata/jvm/KotlinClassMetadata$Companion { public final fun read (Lkotlin/Metadata;)Lkotlinx/metadata/jvm/KotlinClassMetadata; - public final fun writeClass (Lkotlinx/metadata/KmClass;)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class; - public final fun writeClass (Lkotlinx/metadata/KmClass;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class; - public final fun writeClass (Lkotlinx/metadata/KmClass;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class; - public static synthetic fun writeClass$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmClass;[IIILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinClassMetadata$Class; - public final fun writeFileFacade (Lkotlinx/metadata/KmPackage;)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade; - public final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade; - public final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade; - public static synthetic fun writeFileFacade$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmPackage;[IIILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinClassMetadata$FileFacade; - public final fun writeLambda (Lkotlinx/metadata/KmLambda;)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public final fun writeLambda (Lkotlinx/metadata/KmLambda;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public final fun writeLambda (Lkotlinx/metadata/KmLambda;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public static synthetic fun writeLambda$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmLambda;[IIILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public final fun writeMultiFileClassFacade (Ljava/util/List;)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade; - public final fun writeMultiFileClassFacade (Ljava/util/List;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade; - public final fun writeMultiFileClassFacade (Ljava/util/List;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade; - public static synthetic fun writeMultiFileClassFacade$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Ljava/util/List;[IIILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade; - public final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart; - public final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[I)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart; - public final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[II)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart; - public static synthetic fun writeMultiFileClassPart$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmPackage;Ljava/lang/String;[IIILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart; - public final fun writeSyntheticClass ()Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public final fun writeSyntheticClass ([I)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public final fun writeSyntheticClass ([II)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; - public static synthetic fun writeSyntheticClass$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;[IIILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass; + public final fun writeClass (Lkotlinx/metadata/KmClass;)Lkotlin/Metadata; + public final fun writeClass (Lkotlinx/metadata/KmClass;[I)Lkotlin/Metadata; + public final fun writeClass (Lkotlinx/metadata/KmClass;[II)Lkotlin/Metadata; + public static synthetic fun writeClass$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmClass;[IIILjava/lang/Object;)Lkotlin/Metadata; + public final fun writeFileFacade (Lkotlinx/metadata/KmPackage;)Lkotlin/Metadata; + public final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[I)Lkotlin/Metadata; + public final fun writeFileFacade (Lkotlinx/metadata/KmPackage;[II)Lkotlin/Metadata; + public static synthetic fun writeFileFacade$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmPackage;[IIILjava/lang/Object;)Lkotlin/Metadata; + public final fun writeLambda (Lkotlinx/metadata/KmLambda;)Lkotlin/Metadata; + public final fun writeLambda (Lkotlinx/metadata/KmLambda;[I)Lkotlin/Metadata; + public final fun writeLambda (Lkotlinx/metadata/KmLambda;[II)Lkotlin/Metadata; + public static synthetic fun writeLambda$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmLambda;[IIILjava/lang/Object;)Lkotlin/Metadata; + public final fun writeMultiFileClassFacade (Ljava/util/List;)Lkotlin/Metadata; + public final fun writeMultiFileClassFacade (Ljava/util/List;[I)Lkotlin/Metadata; + public final fun writeMultiFileClassFacade (Ljava/util/List;[II)Lkotlin/Metadata; + public static synthetic fun writeMultiFileClassFacade$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Ljava/util/List;[IIILjava/lang/Object;)Lkotlin/Metadata; + public final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;)Lkotlin/Metadata; + public final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[I)Lkotlin/Metadata; + public final fun writeMultiFileClassPart (Lkotlinx/metadata/KmPackage;Ljava/lang/String;[II)Lkotlin/Metadata; + public static synthetic fun writeMultiFileClassPart$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;Lkotlinx/metadata/KmPackage;Ljava/lang/String;[IIILjava/lang/Object;)Lkotlin/Metadata; + public final fun writeSyntheticClass ()Lkotlin/Metadata; + public final fun writeSyntheticClass ([I)Lkotlin/Metadata; + public final fun writeSyntheticClass ([II)Lkotlin/Metadata; + public static synthetic fun writeSyntheticClass$default (Lkotlinx/metadata/jvm/KotlinClassMetadata$Companion;[IIILjava/lang/Object;)Lkotlin/Metadata; } public final class kotlinx/metadata/jvm/KotlinClassMetadata$FileFacade : kotlinx/metadata/jvm/KotlinClassMetadata { public final fun accept (Lkotlinx/metadata/KmPackageVisitor;)V + public final fun getKmPackage ()Lkotlinx/metadata/KmPackage; public final fun toKmPackage ()Lkotlinx/metadata/KmPackage; } @@ -1345,6 +1346,7 @@ public final class kotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassFacade public final class kotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart : kotlinx/metadata/jvm/KotlinClassMetadata { public final fun accept (Lkotlinx/metadata/KmPackageVisitor;)V public final fun getFacadeClassName ()Ljava/lang/String; + public final fun getKmPackage ()Lkotlinx/metadata/KmPackage; public final fun toKmPackage ()Lkotlinx/metadata/KmPackage; } @@ -1358,6 +1360,7 @@ public final class kotlinx/metadata/jvm/KotlinClassMetadata$MultiFileClassPart$W public final class kotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass : kotlinx/metadata/jvm/KotlinClassMetadata { public final fun accept (Lkotlinx/metadata/KmLambdaVisitor;)V + public final fun getKmLambda ()Lkotlinx/metadata/KmLambda; public final fun isLambda ()Z public final fun toKmLambda ()Lkotlinx/metadata/KmLambda; } @@ -1371,24 +1374,28 @@ public final class kotlinx/metadata/jvm/KotlinClassMetadata$SyntheticClass$Write } public final class kotlinx/metadata/jvm/KotlinClassMetadata$Unknown : kotlinx/metadata/jvm/KotlinClassMetadata { + public static final field INSTANCE Lkotlinx/metadata/jvm/KotlinClassMetadata$Unknown; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class kotlinx/metadata/jvm/KotlinModuleMetadata { public static final field Companion Lkotlinx/metadata/jvm/KotlinModuleMetadata$Companion; public synthetic fun ([BLkotlinx/metadata/internal/metadata/jvm/deserialization/ModuleMapping;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun accept (Lkotlinx/metadata/jvm/KmModuleVisitor;)V - public final fun getBytes ()[B + public final fun getKmModule ()Lkotlinx/metadata/jvm/KmModule; public static final fun read ([B)Lkotlinx/metadata/jvm/KotlinModuleMetadata; public final fun toKmModule ()Lkotlinx/metadata/jvm/KmModule; - public static final fun write (Lkotlinx/metadata/jvm/KmModule;)Lkotlinx/metadata/jvm/KotlinModuleMetadata; - public static final fun write (Lkotlinx/metadata/jvm/KmModule;[I)Lkotlinx/metadata/jvm/KotlinModuleMetadata; + public static final fun write (Lkotlinx/metadata/jvm/KmModule;)[B + public static final fun write (Lkotlinx/metadata/jvm/KmModule;[I)[B } public final class kotlinx/metadata/jvm/KotlinModuleMetadata$Companion { public final fun read ([B)Lkotlinx/metadata/jvm/KotlinModuleMetadata; - public final fun write (Lkotlinx/metadata/jvm/KmModule;)Lkotlinx/metadata/jvm/KotlinModuleMetadata; - public final fun write (Lkotlinx/metadata/jvm/KmModule;[I)Lkotlinx/metadata/jvm/KotlinModuleMetadata; - public static synthetic fun write$default (Lkotlinx/metadata/jvm/KotlinModuleMetadata$Companion;Lkotlinx/metadata/jvm/KmModule;[IILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinModuleMetadata; + public final fun write (Lkotlinx/metadata/jvm/KmModule;)[B + public final fun write (Lkotlinx/metadata/jvm/KmModule;[I)[B + public static synthetic fun write$default (Lkotlinx/metadata/jvm/KotlinModuleMetadata$Companion;Lkotlinx/metadata/jvm/KmModule;[IILjava/lang/Object;)[B } public final class kotlinx/metadata/jvm/KotlinModuleMetadata$Writer : kotlinx/metadata/jvm/KmModuleVisitor { @@ -1396,8 +1403,8 @@ public final class kotlinx/metadata/jvm/KotlinModuleMetadata$Writer : kotlinx/me public fun visitAnnotation (Lkotlinx/metadata/KmAnnotation;)V public fun visitOptionalAnnotationClass ()Lkotlinx/metadata/KmClassVisitor; public fun visitPackageParts (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;)V - public final fun write ([I)Lkotlinx/metadata/jvm/KotlinModuleMetadata; - public static synthetic fun write$default (Lkotlinx/metadata/jvm/KotlinModuleMetadata$Writer;[IILjava/lang/Object;)Lkotlinx/metadata/jvm/KotlinModuleMetadata; + public final fun write ([I)[B + public static synthetic fun write$default (Lkotlinx/metadata/jvm/KotlinModuleMetadata$Writer;[IILjava/lang/Object;)[B } public abstract interface annotation class kotlinx/metadata/jvm/UnstableMetadataApi : java/lang/annotation/Annotation { diff --git a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinClassMetadata.kt b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinClassMetadata.kt index 8e96dd36183..d0efd54ae11 100644 --- a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinClassMetadata.kt +++ b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinClassMetadata.kt @@ -27,14 +27,24 @@ import kotlin.LazyThreadSafetyMode.PUBLICATION * trying to cover as much as possible. * Normally, one would need at least a [Class] and a [FileFacade], as these are two most common kinds. * - * Most of the subclasses offer a conversion method to transform metadata into a Km data structure — for example, [KotlinClassMetadata.Class.toKmClass]. + * Most of the subclasses declare a property to view metadata as a Km data structure — for example, [KotlinClassMetadata.Class.kmClass]. + * Some of them also can contain additional properties, e.g. [KotlinClassMetadata.MultiFileClassPart.facadeClassName]. * Km data structures represent Kotlin declarations and offer a variety of properties to introspect and alter them. - * Note that parsing may be lazy, depending on the implementation; therefore, one may not see an [IllegalArgumentException] indicating malformed metadata - * until one calls `toKmClass` or a similar method. + * After desired changes are made, it is possible to get a new raw metadata instance with a corresponding `write` function, such as [KotlinClassMetadata.writeClass]. * - * @property annotationData Raw contents of the metadata represented by [Metadata] annotation in the class file. + * Here is an example of reading a content name of some metadata: + * ``` + * fun displayName(metadata: Metadata): String = when (val kcm = KotlinClassMetadata.read(metadata)) { + * is KotlinClassMetadata.Class -> "Class ${kcm.kmClass.name}" + * is KotlinClassMetadata.FileFacade -> "File facade with functions: ${kcm.kmPackage.functions.joinToString { it.name }}" + * is KotlinClassMetadata.SyntheticClass -> kcm.kmLambda?.function?.name?.let { "Lambda $it" } ?: "Synthetic class" + * is KotlinClassMetadata.MultiFileClassFacade -> "Multifile class facade with parts: ${kcm.partClassNames.joinToString()}" + * is KotlinClassMetadata.MultiFileClassPart -> "Multifile class part ${kcm.facadeClassName}" + * is KotlinClassMetadata.Unknown -> "Unknown metadata" + * } + * ``` */ -sealed class KotlinClassMetadata(val annotationData: Metadata) { +sealed class KotlinClassMetadata(internal val annotationData: Metadata) { /** * Represents metadata of a class file containing a declaration of a Kotlin class. @@ -43,18 +53,26 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { * [Class] metadata, even if such declaration was in the same source file. See [FileFacade] for details. */ class Class internal constructor(annotationData: Metadata) : KotlinClassMetadata(annotationData) { - private val classData by lazy(PUBLICATION) { - JvmProtoBufUtil.readClassDataFrom(annotationData.requireNotEmpty(), annotationData.data2) + + /** + * Returns the [KmClass] representation of this metadata. + * + * Returns the same (mutable) [KmClass] instance every time. + */ + public val kmClass: KmClass = KmClass().apply { + val (strings, proto) = JvmProtoBufUtil.readClassDataFrom(annotationData.requireNotEmpty(), annotationData.data2) + proto.accept(this, strings) } /** * Returns a new [KmClass] instance created from this class metadata. - * - * @throws IllegalArgumentException if metadata is malformed or inconsistent and cannot be transformed into [KmClass]. */ - fun toKmClass(): KmClass = wrapIntoMetadataExceptionWhenNeeded { - KmClass().apply(this::accept) - } + @Deprecated( + "To avoid excessive copying, use .kmClass property instead. Note that it returns a view and not a copy.", + ReplaceWith("kmClass"), + DeprecationLevel.WARNING + ) + fun toKmClass(): KmClass = KmClass().also { newKm -> kmClass.accept(newKm) } // defensive copy /** * Makes the given visitor visit the metadata of this class. @@ -62,10 +80,7 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { * @param v the visitor that must visit this class */ @Deprecated(VISITOR_API_MESSAGE) - fun accept(v: KmClassVisitor) { - val (strings, proto) = classData - proto.accept(v, strings) - } + fun accept(v: KmClassVisitor) = kmClass.accept(v) /** * A [KmClassVisitor] that generates the metadata of a Kotlin class. @@ -107,18 +122,26 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { * Classes would have their own JVM classfiles and their own metadata of [Class] kind. */ class FileFacade internal constructor(annotationData: Metadata) : KotlinClassMetadata(annotationData) { - private val packageData by lazy(PUBLICATION) { - JvmProtoBufUtil.readPackageDataFrom(annotationData.requireNotEmpty(), annotationData.data2) + + /** + * Returns the [KmPackage] representation of this metadata. + * + * Returns the same (mutable) [KmPackage] instance every time. + */ + public val kmPackage: KmPackage = KmPackage().apply { + val (strings, proto) = JvmProtoBufUtil.readPackageDataFrom(annotationData.requireNotEmpty(), annotationData.data2) + proto.accept(this, strings) } /** * Creates a new [KmPackage] instance from this file facade metadata. - * - * @throws IllegalArgumentException if metadata is malformed or inconsistent and cannot be transformed into [KmPackage]. */ - fun toKmPackage(): KmPackage = wrapIntoMetadataExceptionWhenNeeded { - KmPackage().apply(this::accept) - } + @Deprecated( + "To avoid excessive copying, use .kmPackage property instead. Note that it returns a view and not a copy.", + ReplaceWith("kmPackage"), + DeprecationLevel.WARNING + ) + fun toKmPackage(): KmPackage = KmPackage().also { newPkg -> kmPackage.accept(newPkg) } /** * Makes the given visitor visit metadata of this file facade. @@ -126,10 +149,7 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { * @param v the visitor that must visit this file facade */ @Deprecated(VISITOR_API_MESSAGE) - fun accept(v: KmPackageVisitor) { - val (strings, proto) = packageData - proto.accept(v, strings) - } + fun accept(v: KmPackageVisitor) = kmPackage.accept(v) /** * A [KmPackageVisitor] that generates the metadata of a Kotlin file facade. @@ -167,21 +187,10 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { * method implementations, `$WhenMappings` class for optimized `when` over enums, etc. */ class SyntheticClass internal constructor(annotationData: Metadata) : KotlinClassMetadata(annotationData) { - private val functionData by lazy(PUBLICATION) { + private val functionData = annotationData.data1.takeIf(Array<*>::isNotEmpty)?.let { data1 -> JvmProtoBufUtil.readFunctionDataFrom(data1, annotationData.data2) } - } - - /** - * Creates a new [KmLambda] instance from this synthetic class metadata. - * Returns `null` if this synthetic class does not represent a lambda. - * - * @throws IllegalArgumentException if metadata is malformed or inconsistent and cannot be transformed into [KmLambda]. - */ - fun toKmLambda(): KmLambda? = wrapIntoMetadataExceptionWhenNeeded { - if (isLambda) KmLambda().apply(this::accept) else null - } /** * Returns `true` if this synthetic class is a class file compiled for a Kotlin lambda. @@ -189,6 +198,28 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { val isLambda: Boolean get() = annotationData.data1.isNotEmpty() + + /** + * Returns the [KmLambda] representation of this metadata, or `null` if this synthetic class does not represent a lambda. + * + * Returns the same (mutable) [KmLambda] instance every time. + */ + public val kmLambda: KmLambda? = if (!isLambda) null else KmLambda().apply { + val (strings, proto) = functionData!! + proto.accept(this, strings) + } + + /** + * Creates a new [KmLambda] instance from this synthetic class metadata. + * Returns `null` if this synthetic class does not represent a lambda. + */ + @Deprecated( + "To avoid excessive copying, use .kmLambda property instead. Note that it returns a view and not a copy.", + ReplaceWith("kmLambda"), + DeprecationLevel.WARNING + ) + fun toKmLambda(): KmLambda? = if (isLambda) KmLambda().apply(this::accept) else null + /** * Makes the given visitor visit metadata of this file facade if this synthetic class represents a Kotlin lambda * (`isLambda` == true). @@ -203,8 +234,7 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { "accept(KmLambdaVisitor) is only possible for synthetic classes which are lambdas (isLambda = true)" ) - val (strings, proto) = functionData!! - proto.accept(v, strings) + kmLambda!!.accept(v) } /** @@ -329,8 +359,14 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { * @see JvmMultifileClass */ class MultiFileClassPart internal constructor(annotationData: Metadata) : KotlinClassMetadata(annotationData) { - private val packageData by lazy(PUBLICATION) { - JvmProtoBufUtil.readPackageDataFrom(annotationData.requireNotEmpty(), annotationData.data2) + /** + * Returns the [KmPackage] representation of this metadata. + * + * Returns the same (mutable) [KmPackage] instance every time. + */ + public val kmPackage: KmPackage = KmPackage().apply { + val (strings, proto) = JvmProtoBufUtil.readPackageDataFrom(annotationData.requireNotEmpty(), annotationData.data2) + proto.accept(this, strings) } /** @@ -341,12 +377,13 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { /** * Creates a new [KmPackage] instance from this multi-file class part metadata. - * - * @throws IllegalArgumentException if metadata is malformed or inconsistent and cannot be transformed into [KmPackage]. */ - fun toKmPackage(): KmPackage = wrapIntoMetadataExceptionWhenNeeded { - KmPackage().apply(this::accept) - } + @Deprecated( + "To avoid excessive copying, use .kmPackage property instead. Note that it returns a view and not a copy.", + ReplaceWith("kmPackage"), + DeprecationLevel.WARNING + ) + fun toKmPackage(): KmPackage = KmPackage().also { newKmp -> kmPackage.accept(newKmp) } /** * Makes the given visitor visit metadata of this multi-file class part. @@ -355,8 +392,7 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { */ @Deprecated(VISITOR_API_MESSAGE) fun accept(v: KmPackageVisitor) { - val (strings, proto) = packageData - proto.accept(v, strings) + kmPackage.accept(v) } /** @@ -398,7 +434,7 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { * Represents metadata of an unknown class file. This class is used if an old version of this library is used against a new kind * of class files generated by the Kotlin compiler, unsupported by this library. */ - class Unknown internal constructor(annotationData: Metadata) : KotlinClassMetadata(annotationData) + data object Unknown : KotlinClassMetadata(Metadata()) /** * Collection of methods for reading and writing [KotlinClassMetadata], @@ -420,9 +456,9 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { fun writeClass( kmClass: KmClass, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION, - extraInt: Int = 0 - ): Class = wrapWriteIntoIAE { - Class.Writer().also { kmClass.accept(it) }.write(metadataVersion, extraInt) + extraInt: Int = 0, + ): Metadata = wrapWriteIntoIAE { + Class.Writer().also { kmClass.accept(it) }.write(metadataVersion, extraInt).annotationData } /** @@ -440,9 +476,9 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { fun writeFileFacade( kmPackage: KmPackage, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION, - extraInt: Int = 0 - ): FileFacade = wrapWriteIntoIAE { - FileFacade.Writer().also { kmPackage.accept(it) }.write(metadataVersion, extraInt) + extraInt: Int = 0, + ): Metadata = wrapWriteIntoIAE { + FileFacade.Writer().also { kmPackage.accept(it) }.write(metadataVersion, extraInt).annotationData } /** @@ -460,9 +496,9 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { fun writeLambda( kmLambda: KmLambda, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION, - extraInt: Int = 0 - ): SyntheticClass = wrapWriteIntoIAE { - SyntheticClass.Writer().also { kmLambda.accept(it) }.write(metadataVersion, extraInt) + extraInt: Int = 0, + ): Metadata = wrapWriteIntoIAE { + SyntheticClass.Writer().also { kmLambda.accept(it) }.write(metadataVersion, extraInt).annotationData } /** @@ -479,8 +515,8 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { @JvmOverloads fun writeSyntheticClass( metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION, - extraInt: Int = 0 - ): SyntheticClass = SyntheticClass.Writer().write(metadataVersion, extraInt) + extraInt: Int = 0, + ): Metadata = SyntheticClass.Writer().write(metadataVersion, extraInt).annotationData /** * Writes metadata of the multi-file class facade. @@ -497,8 +533,8 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { @JvmOverloads fun writeMultiFileClassFacade( partClassNames: List, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION, - extraInt: Int = 0 - ): MultiFileClassFacade = MultiFileClassFacade.Writer().write(partClassNames, metadataVersion, extraInt) + extraInt: Int = 0, + ): Metadata = MultiFileClassFacade.Writer().write(partClassNames, metadataVersion, extraInt).annotationData /** * Writes the metadata of the multi-file class part. @@ -517,9 +553,9 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { kmPackage: KmPackage, facadeClassName: String, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION, - extraInt: Int = 0 - ): MultiFileClassPart = wrapWriteIntoIAE { - MultiFileClassPart.Writer().also { kmPackage.accept(it) }.write(facadeClassName, metadataVersion, extraInt) + extraInt: Int = 0, + ): Metadata = wrapWriteIntoIAE { + MultiFileClassPart.Writer().also { kmPackage.accept(it) }.write(facadeClassName, metadataVersion, extraInt).annotationData } /** @@ -542,14 +578,15 @@ sealed class KotlinClassMetadata(val annotationData: Metadata) { fun read(annotationData: Metadata): KotlinClassMetadata { checkMetadataVersionForRead(annotationData) - // All data is loaded lazily, no exceptions here to handle - return when (annotationData.kind) { - CLASS_KIND -> Class(annotationData) - FILE_FACADE_KIND -> FileFacade(annotationData) - SYNTHETIC_CLASS_KIND -> SyntheticClass(annotationData) - MULTI_FILE_CLASS_FACADE_KIND -> MultiFileClassFacade(annotationData) - MULTI_FILE_CLASS_PART_KIND -> MultiFileClassPart(annotationData) - else -> Unknown(annotationData) + return wrapIntoMetadataExceptionWhenNeeded { + when (annotationData.kind) { + CLASS_KIND -> Class(annotationData) + FILE_FACADE_KIND -> FileFacade(annotationData) + SYNTHETIC_CLASS_KIND -> SyntheticClass(annotationData) + MULTI_FILE_CLASS_FACADE_KIND -> MultiFileClassFacade(annotationData) + MULTI_FILE_CLASS_PART_KIND -> MultiFileClassPart(annotationData) + else -> Unknown + } } } diff --git a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt index d7c044da2d8..0454fadac70 100644 --- a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt +++ b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt @@ -38,17 +38,27 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.serializeToByteArray */ @UnstableMetadataApi class KotlinModuleMetadata private constructor( - @Suppress("MemberVisibilityCanBePrivate") val bytes: ByteArray, - @get:IgnoreInApiDump internal val data: ModuleMapping + private val bytes: ByteArray, + private val data: ModuleMapping, ) { + + /** + * Returns the [KmModule] representation of this metadata. + * + * Returns the same (mutable) [KmModule] instance every time. + */ + public val kmModule: KmModule = KmModule().apply(this::accept) + /** * Visits metadata of this module with a new [KmModule] instance and returns that instance. - * - * @throws IllegalArgumentException if parsed metadata is inconsistent and can't be transformed into [KmModule]. */ - fun toKmModule(): KmModule = wrapIntoMetadataExceptionWhenNeeded { - KmModule().apply(this::accept) - } + @Deprecated( + "To avoid excessive copying, use .kmModule property instead. Note that it returns a view and not a copy.", + ReplaceWith("kmModule"), + DeprecationLevel.WARNING + ) + fun toKmModule(): KmModule = KmModule().apply(kmModule::accept) + /** * A [KmModuleVisitor] that generates the metadata of a Kotlin JVM module file. @@ -97,9 +107,8 @@ class KotlinModuleMetadata private constructor( * [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default */ @Deprecated("Writer API is deprecated as excessive and cumbersome. Please use KotlinModuleMetadata.write(kmModule, metadataVersion)") - fun write(metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata { - val bytes = b.build().serializeToByteArray(JvmMetadataVersion(*metadataVersion), 0) - return KotlinModuleMetadata(bytes, dataFromBytes(bytes)) + fun write(metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): ByteArray { + return b.build().serializeToByteArray(JvmMetadataVersion(*metadataVersion), 0) } } @@ -158,12 +167,12 @@ class KotlinModuleMetadata private constructor( * @param metadataVersion metadata version to be written to the metadata (see [Metadata.metadataVersion]), * [KotlinClassMetadata.COMPATIBLE_METADATA_VERSION] by default * - * @throws IllegalArgumentException if [kmModule] is not correct and can't be written or if [metadataVersion] is not supported for writing. + * @throws IllegalArgumentException if [kmModule] is not correct and cannot be written or if [metadataVersion] is not supported for writing. */ @UnstableMetadataApi @JvmStatic @JvmOverloads - fun write(kmModule: KmModule, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): KotlinModuleMetadata = wrapWriteIntoIAE { + fun write(kmModule: KmModule, metadataVersion: IntArray = COMPATIBLE_METADATA_VERSION): ByteArray = wrapWriteIntoIAE { Writer().also { kmModule.accept(it) }.write(metadataVersion) } diff --git a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JavaUsageTest.java b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JavaUsageTest.java index b23c9c7a5a1..ee9d7e0354a 100644 --- a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JavaUsageTest.java +++ b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JavaUsageTest.java @@ -21,17 +21,17 @@ public class JavaUsageTest { @Test public void testKotlinClassHeader() { Metadata m = MetadataSmokeTest.class.getAnnotation(Metadata.class); - KmClass clazz1 = ((KotlinClassMetadata.Class) Objects.requireNonNull(KotlinClassMetadata.read(m))).toKmClass(); + KmClass clazz1 = ((KotlinClassMetadata.Class) Objects.requireNonNull(KotlinClassMetadata.read(m))).getKmClass(); KotlinClassHeader kh = new KotlinClassHeader(m.k(), m.mv(), m.d1(), m.d2(), m.xs(), m.pn(), m.xi()); - KmClass clazz2 = ((KotlinClassMetadata.Class) Objects.requireNonNull(KotlinClassMetadata.read(kh))).toKmClass(); + KmClass clazz2 = ((KotlinClassMetadata.Class) Objects.requireNonNull(KotlinClassMetadata.read(kh))).getKmClass(); assertEquals(clazz1.getName(), clazz2.getName()); } @Test public void testWritingBackWithDefaults() { Metadata m = MetadataSmokeTest.class.getAnnotation(Metadata.class); - KmClass clazz1 = ((KotlinClassMetadata.Class) Objects.requireNonNull(KotlinClassMetadata.read(m))).toKmClass(); - Metadata written = KotlinClassMetadata.writeClass(clazz1).getAnnotationData(); + KmClass clazz1 = ((KotlinClassMetadata.Class) Objects.requireNonNull(KotlinClassMetadata.read(m))).getKmClass(); + Metadata written = KotlinClassMetadata.writeClass(clazz1); assertArrayEquals(written.mv(), KotlinClassMetadata.COMPATIBLE_METADATA_VERSION); assertEquals(0, written.xi()); } diff --git a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataExceptionsTest.kt b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataExceptionsTest.kt index 194d0d2e1e4..c307dc3896e 100644 --- a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataExceptionsTest.kt +++ b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataExceptionsTest.kt @@ -20,7 +20,7 @@ class MetadataExceptionsTest { val malformedMetadata = Metadata(KotlinClassMetadata.CLASS_KIND, KotlinClassMetadata.COMPATIBLE_METADATA_VERSION, arrayOf(malformedInput)) val e = assertFailsWith { - (KotlinClassMetadata.read(malformedMetadata) as KotlinClassMetadata.Class).toKmClass() + (KotlinClassMetadata.read(malformedMetadata) as KotlinClassMetadata.Class) } assertIs(e.cause) } diff --git a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataSmokeTest.kt b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataSmokeTest.kt index d404c0a7afa..6e5c0737b8b 100644 --- a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataSmokeTest.kt +++ b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/MetadataSmokeTest.kt @@ -60,7 +60,7 @@ class MetadataSmokeTest { } } - val annotationData = KotlinClassMetadata.writeClass(klass).annotationData + val annotationData = KotlinClassMetadata.writeClass(klass) // Then, produce the bytecode of a .class file with ASM @@ -180,7 +180,7 @@ class MetadataSmokeTest { } ) - val classWithUnstableParameterNames = newMetadata.toKmClass() + val classWithUnstableParameterNames = newMetadata.readAsKmClass() classWithUnstableParameterNames.constructors.forEach { assertTrue(Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) } classWithUnstableParameterNames.functions.forEach { assertTrue(Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) } @@ -217,7 +217,27 @@ class MetadataSmokeTest { val kmClassCopy = KotlinClassMetadata .writeClass(kmClass, metadata.metadataVersion, metadata.extraInt) - .toKmClass() + .readAsKmClass() assertEquals(kmClassCopy.jvmFlags, jvmClassFlags) } + + @Test + fun testDisplayNameSample() { + class A {} + + val b: (Int) -> Int = fun(x: Int) = x + + assertEquals("Class .kotlinx/metadata/test/MetadataSmokeTest\$testDisplayNameSample\$A", displayName(A::class.java.getMetadata())) + assertEquals("Lambda ", displayName(b::class.java.getMetadata())) + } + + fun displayName(metadata: Metadata): String = when (val kcm = KotlinClassMetadata.read(metadata)) { + is KotlinClassMetadata.Class -> "Class ${kcm.kmClass.name}" + is KotlinClassMetadata.FileFacade -> "File facade with functions: ${kcm.kmPackage.functions.joinToString { it.name }}" + is KotlinClassMetadata.SyntheticClass -> kcm.kmLambda?.function?.name?.let { "Lambda $it" } ?: "Synthetic class" + is KotlinClassMetadata.MultiFileClassFacade -> "Multifile class facade with parts: ${kcm.partClassNames.joinToString()}" + is KotlinClassMetadata.MultiFileClassPart -> "Multifile class part ${kcm.facadeClassName}" + is KotlinClassMetadata.Unknown -> "Unknown metadata" + } + } diff --git a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt index df5a6bf6515..fcc296b0622 100644 --- a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt +++ b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt @@ -14,7 +14,7 @@ internal fun Class<*>.getMetadata(): Metadata { internal fun Metadata.readAsKmClass(): KmClass { val clazz = KotlinClassMetadata.read(this) as? KotlinClassMetadata.Class - return clazz?.toKmClass() ?: error("Not a KotlinClassMetadata.Class: $clazz") + return clazz?.kmClass ?: error("Not a KotlinClassMetadata.Class: $clazz") } internal fun Class<*>.readMetadataAsKmClass(): KmClass = getMetadata().readAsKmClass() diff --git a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt index 8c4bba289b0..39852bfed24 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt @@ -11,7 +11,7 @@ import kotlinx.metadata.jvm.UnstableMetadataApi import java.io.File class Kotlinp(private val settings: KotlinpSettings) { - internal fun renderClassFile(classFile: KotlinClassMetadata?): String = + internal fun renderClassFile(classFile: KotlinClassMetadata): String = when (classFile) { is KotlinClassMetadata.Class -> ClassPrinter(settings).print(classFile) is KotlinClassMetadata.FileFacade -> FileFacadePrinter(settings).print(classFile) @@ -21,14 +21,17 @@ class Kotlinp(private val settings: KotlinpSettings) { } is KotlinClassMetadata.MultiFileClassFacade -> MultiFileClassFacadePrinter().print(classFile) is KotlinClassMetadata.MultiFileClassPart -> MultiFileClassPartPrinter(settings).print(classFile) - is KotlinClassMetadata.Unknown -> buildString { appendLine("unknown file (k=${classFile.annotationData.kind})") } - null -> buildString { appendLine("unsupported file") } + is KotlinClassMetadata.Unknown -> buildString { appendLine("unknown file") } } - internal fun readClassFile(file: File): KotlinClassMetadata? { - val header = file.readKotlinClassHeader() ?: throw KotlinpException("file is not a Kotlin class file: $file") + + internal fun readClassFile(file: File): Metadata { + return file.readKotlinClassHeader() ?: throw KotlinpException("file is not a Kotlin class file: $file") + } + + internal fun readMetadata(metadata: Metadata): KotlinClassMetadata { return try { - KotlinClassMetadata.read(header) + KotlinClassMetadata.read(metadata) } catch (e: IllegalArgumentException) { throw KotlinpException("inconsistent Kotlin metadata: ${e.message}") } diff --git a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Main.kt b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Main.kt index 6e156ff01b7..0ebf3cef75a 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Main.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Main.kt @@ -43,7 +43,7 @@ object Main { val text = try { when (file.extension) { - "class" -> kotlinp.renderClassFile(kotlinp.readClassFile(file)) + "class" -> kotlinp.renderClassFile(kotlinp.readMetadata(kotlinp.readClassFile(file))) "kotlin_module" -> @OptIn(UnstableMetadataApi::class) kotlinp.renderModuleFile(kotlinp.readModuleFile(file)) else -> throw KotlinpException("only .class and .kotlin_module files are supported") } diff --git a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt index 5ec0fcfe8c9..5c34660b65b 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt @@ -567,7 +567,7 @@ class ClassPrinter(private val settings: KotlinpSettings) : AbstractPrinter { override fun print(klass: KotlinClassMetadata.FileFacade): String { - print(klass.toKmPackage()) + print(klass.kmPackage) return sb.toString() } } @@ -635,7 +635,7 @@ class LambdaPrinter(private val settings: KotlinpSettings) : AbstractPrinter { override fun print(klass: KotlinClassMetadata.MultiFileClassPart): String { sb.appendLine(" // facade: ${klass.facadeClassName}") - print(klass.toKmPackage()) + print(klass.kmPackage) return sb.toString() } } @@ -696,7 +696,7 @@ class ModuleFilePrinter(private val settings: KotlinpSettings) { @UnstableMetadataApi fun print(metadata: KotlinModuleMetadata): String { - val kmModule = metadata.toKmModule() + val kmModule = metadata.kmModule kmModule.packageParts.forEach { (fqName, kmPackageParts) -> visitPackageParts(fqName, kmPackageParts.fileFacades, kmPackageParts.multiFileClassParts) } diff --git a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt index a524772e10b..7cde7b7328c 100644 --- a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt +++ b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt @@ -49,8 +49,8 @@ fun compileAndPrintAllFiles( when (outputFile.extension) { "kotlin_module" -> { val moduleFile = kotlinp.readModuleFile(outputFile)!! - val transformedWithVisitors = transformModuleFileWithReadWriteVisitors(moduleFile) - val transformedWithNodes = transformModuleFileWithNodes(moduleFile) + val transformedWithVisitors = KotlinModuleMetadata.read(transformModuleFileWithReadWriteVisitors(moduleFile)) + val transformedWithNodes = KotlinModuleMetadata.read(transformModuleFileWithNodes(moduleFile)) for ((sb, moduleFileToRender) in listOf( main to moduleFile, afterVisitors to transformedWithVisitors, afterNodes to transformedWithNodes @@ -60,9 +60,10 @@ fun compileAndPrintAllFiles( } } "class" -> { - val classFile = kotlinp.readClassFile(outputFile)!! + val metadata = kotlinp.readClassFile(outputFile) + val classFile = kotlinp.readMetadata(metadata) val classFile2 = transformClassFileWithReadWriteVisitors(classFile) - val classFile3 = transformClassFileWithNodes(classFile) + val classFile3 = KotlinClassMetadata.read(transformClassFileWithNodes(metadata, classFile)) for ((sb, classFileToRender) in listOf( main to classFile, afterVisitors to classFile2, afterNodes to classFile3 @@ -130,24 +131,25 @@ private fun transformClassFileWithReadWriteVisitors(classFile: KotlinClassMetada } // Reads the class file and writes it back with KmClass/KmFunction/... elements. -private fun transformClassFileWithNodes(classFile: KotlinClassMetadata): KotlinClassMetadata = +private fun transformClassFileWithNodes(metadata: Metadata, classFile: KotlinClassMetadata): Metadata = when (classFile) { is KotlinClassMetadata.Class -> - KotlinClassMetadata.writeClass(classFile.toKmClass()) + KotlinClassMetadata.writeClass(classFile.kmClass) is KotlinClassMetadata.FileFacade -> - KotlinClassMetadata.writeFileFacade(classFile.toKmPackage()) + KotlinClassMetadata.writeFileFacade(classFile.kmPackage) is KotlinClassMetadata.SyntheticClass -> - classFile.toKmLambda()?.let { KotlinClassMetadata.writeLambda(it) } ?: KotlinClassMetadata.writeSyntheticClass() + classFile.kmLambda?.let { KotlinClassMetadata.writeLambda(it) } ?: KotlinClassMetadata.writeSyntheticClass() is KotlinClassMetadata.MultiFileClassPart -> - KotlinClassMetadata.writeMultiFileClassPart(classFile.toKmPackage(), classFile.facadeClassName) - else -> classFile + KotlinClassMetadata.writeMultiFileClassPart(classFile.kmPackage, classFile.facadeClassName) + is KotlinClassMetadata.MultiFileClassFacade -> KotlinClassMetadata.writeMultiFileClassFacade(classFile.partClassNames) + is KotlinClassMetadata.Unknown -> metadata } @Suppress("DEPRECATION") // We're testing that reading/writing with KmNodes is identical to direct @OptIn(UnstableMetadataApi::class) -private fun transformModuleFileWithReadWriteVisitors(moduleFile: KotlinModuleMetadata): KotlinModuleMetadata = +private fun transformModuleFileWithReadWriteVisitors(moduleFile: KotlinModuleMetadata): ByteArray = KotlinModuleMetadata.Writer().apply(moduleFile::accept).write() @OptIn(UnstableMetadataApi::class) -private fun transformModuleFileWithNodes(moduleFile: KotlinModuleMetadata): KotlinModuleMetadata = - KotlinModuleMetadata.write(moduleFile.toKmModule()) +private fun transformModuleFileWithNodes(moduleFile: KotlinModuleMetadata): ByteArray = + KotlinModuleMetadata.write(moduleFile.kmModule)