From 53d2e975b68fc1d6697ccb21b008135ca13bc6b4 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Tue, 2 Jul 2024 12:47:08 +0200 Subject: [PATCH 1/4] Use stable kotlin-metadata-jvm version --- gradle/libs.versions.toml | 2 +- src/main/kotlin/api/AsmMetadataLoading.kt | 2 +- .../kotlin/api/KotlinMetadataSignature.kt | 8 +- .../kotlin/api/KotlinMetadataVisibilities.kt | 83 ++++++++++--------- .../kotlin/api/KotlinSignaturesLoading.kt | 9 +- 5 files changed, 51 insertions(+), 53 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9c867c6f..9c970f4f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ androidGradlePlugin = "7.2.2" [libraries] ## region Application libraries -kotlinx-metadata = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version = "0.6.2" } +kotlinx-metadata = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version = "2.0.0" } javaDiffUtils = { module = "io.github.java-diff-utils:java-diff-utils", version.ref = "javaDiffUtils" } diff --git a/src/main/kotlin/api/AsmMetadataLoading.kt b/src/main/kotlin/api/AsmMetadataLoading.kt index b8f473de..b7a4d303 100644 --- a/src/main/kotlin/api/AsmMetadataLoading.kt +++ b/src/main/kotlin/api/AsmMetadataLoading.kt @@ -5,7 +5,7 @@ package kotlinx.validation.api -import kotlinx.metadata.jvm.* +import kotlin.metadata.jvm.* import org.objectweb.asm.* import org.objectweb.asm.tree.* diff --git a/src/main/kotlin/api/KotlinMetadataSignature.kt b/src/main/kotlin/api/KotlinMetadataSignature.kt index 4fb6d426..d5b0fc72 100644 --- a/src/main/kotlin/api/KotlinMetadataSignature.kt +++ b/src/main/kotlin/api/KotlinMetadataSignature.kt @@ -5,7 +5,7 @@ package kotlinx.validation.api -import kotlinx.metadata.jvm.* +import kotlin.metadata.jvm.* import kotlinx.validation.* import org.objectweb.asm.* import org.objectweb.asm.tree.* @@ -30,7 +30,7 @@ public data class ClassBinarySignature internal constructor( internal interface MemberBinarySignature { val jvmMember: JvmMemberSignature val name: String get() = jvmMember.name - val desc: String get() = jvmMember.desc + val desc: String get() = jvmMember.descriptor val access: AccessFlags val isPublishedApi: Boolean val annotations: List @@ -172,7 +172,7 @@ internal fun FieldNode.isCompanionField(outerClassMetadata: KotlinClassMetadata? val metadata = outerClassMetadata ?: return false // Non-classes are not affected by the problem if (metadata !is KotlinClassMetadata.Class) return false - return metadata.toKmClass().companionObject == name + return metadata.kmClass.companionObject == name } internal fun ClassNode.companionName(outerClassMetadata: KotlinClassMetadata?): String? { @@ -180,6 +180,6 @@ internal fun ClassNode.companionName(outerClassMetadata: KotlinClassMetadata?): // Happens when outerClassMetadata == KotlinClassMetadata$FileFacade for an example return null } - val outerKClass = outerClassMetadata.toKmClass() + val outerKClass = outerClassMetadata.kmClass return name + "$" + outerKClass.companionObject } diff --git a/src/main/kotlin/api/KotlinMetadataVisibilities.kt b/src/main/kotlin/api/KotlinMetadataVisibilities.kt index 946579b9..7ab0259f 100644 --- a/src/main/kotlin/api/KotlinMetadataVisibilities.kt +++ b/src/main/kotlin/api/KotlinMetadataVisibilities.kt @@ -5,20 +5,18 @@ package kotlinx.validation.api -import kotlinx.metadata.* -import kotlinx.metadata.jvm.* -import kotlinx.metadata.jvm.KotlinClassMetadata.Companion.COMPATIBLE_METADATA_VERSION +import kotlin.metadata.* +import kotlin.metadata.jvm.* import org.objectweb.asm.tree.* internal class ClassVisibility( val name: String, - val flags: Flags?, + val visibility: Visibility?, + val classKind: ClassKind?, val members: Map, val facadeClassName: String? = null ) { - val visibility get() = flags - val isCompanion: Boolean get() = flags != null && Flag.Class.IS_COMPANION_OBJECT(flags) - + val isCompanion: Boolean get() = classKind == ClassKind.COMPANION_OBJECT var companionVisibilities: ClassVisibility? = null val partVisibilities = mutableListOf() } @@ -29,7 +27,7 @@ internal fun ClassVisibility.findMember(signature: JvmMemberSignature): MemberVi internal data class MemberVisibility( val member: JvmMemberSignature, - val visibility: Flags?, + val visibility: Visibility?, val isReified: Boolean, /* * This property includes both annotations on the member itself, @@ -38,24 +36,25 @@ internal data class MemberVisibility( val propertyAnnotation: PropertyAnnotationHolders? = null ) -private fun isPublic(visibility: Flags?, isPublishedApi: Boolean) = +private fun isPublic(visibility: Visibility?, isPublishedApi: Boolean) = visibility == null - || Flag.IS_PUBLIC(visibility) - || Flag.IS_PROTECTED(visibility) - || (isPublishedApi && Flag.IS_INTERNAL(visibility)) + || visibility == Visibility.PUBLIC + || visibility == Visibility.PROTECTED + || (isPublishedApi && visibility == Visibility.INTERNAL) internal fun ClassVisibility.isPublic(isPublishedApi: Boolean) = isPublic(visibility, isPublishedApi) internal fun MemberVisibility.isPublic(isPublishedApi: Boolean) = - // Assuming isReified implies inline - !isReified && isPublic(visibility, isPublishedApi) + // Assuming isReified implies inline + !isReified && isPublic(visibility, isPublishedApi) -internal fun MemberVisibility.isInternal(): Boolean = visibility != null && Flag.IS_INTERNAL(visibility) +internal fun MemberVisibility.isInternal(): Boolean = visibility == Visibility.INTERNAL internal val ClassNode.kotlinMetadata: KotlinClassMetadata? get() { val metadata = findAnnotation("kotlin/Metadata", false) ?: return null + @Suppress("UNCHECKED_CAST") val header = with(metadata) { Metadata( @@ -68,15 +67,7 @@ internal val ClassNode.kotlinMetadata: KotlinClassMetadata? extraInt = get("xi") as Int? ) } - return KotlinClassMetadata.read(header) - ?: error( - """ - Incompatible version of Kotlin metadata. - Maximal supported Kotlin metadata version: ${COMPATIBLE_METADATA_VERSION.joinToString(".")}, - $name Kotlin metadata version: ${header.metadataVersion.joinToString(".")}. - As a workaround, it is possible to manually update 'kotlinx-metadata-jvm' version in your project. - """.trimIndent() - ) + return KotlinClassMetadata.readStrict(header) } @@ -92,42 +83,47 @@ internal class PropertyAnnotationHolders( ) internal fun KotlinClassMetadata.toClassVisibility(classNode: ClassNode): ClassVisibility { - var flags: Flags? = null + var visibility: Visibility? = null + var kind: ClassKind? = null var _facadeClassName: String? = null val members = mutableListOf() fun addMember( signature: JvmMemberSignature?, - flags: Flags, + visibility: Visibility?, isReified: Boolean, propertyAnnotation: PropertyAnnotationHolders? = null ) { if (signature != null) { - members.add(MemberVisibility(signature, flags, isReified, propertyAnnotation)) + members.add(MemberVisibility(signature, visibility, isReified, propertyAnnotation)) } } val container: KmDeclarationContainer? = when (this) { is KotlinClassMetadata.Class -> - toKmClass().also { klass -> - flags = klass.flags + kmClass.also { klass -> + visibility = klass.visibility + kind = klass.kind for (constructor in klass.constructors) { - addMember(constructor.signature, constructor.flags, isReified = false) + addMember(constructor.signature, constructor.visibility, isReified = false) } } + is KotlinClassMetadata.FileFacade -> - toKmPackage() + kmPackage + is KotlinClassMetadata.MultiFileClassPart -> - toKmPackage().also { _facadeClassName = this.facadeClassName } + kmPackage.also { _facadeClassName = this.facadeClassName } + else -> null } if (container != null) { - fun List.containsReified() = any { Flag.TypeParameter.IS_REIFIED(it.flags) } + fun List.containsReified() = any { it.isReified } for (function in container.functions) { - addMember(function.signature, function.flags, function.typeParameters.containsReified()) + addMember(function.signature, function.visibility, function.typeParameters.containsReified()) } for (property in container.properties) { @@ -135,19 +131,24 @@ internal fun KotlinClassMetadata.toClassVisibility(classNode: ClassNode): ClassV val propertyAnnotations = PropertyAnnotationHolders(property.fieldSignature, property.syntheticMethodForAnnotations) - addMember(property.getterSignature, property.getterFlags, isReified, propertyAnnotations) - addMember(property.setterSignature, property.setterFlags, isReified, propertyAnnotations) + addMember(property.getterSignature, property.getter.visibility, isReified, propertyAnnotations) + addMember(property.setterSignature, property.setter?.visibility, isReified, propertyAnnotations) val fieldVisibility = when { - Flag.Property.IS_LATEINIT(property.flags) -> property.setterFlags - property.getterSignature == null && property.setterSignature == null -> property.flags // JvmField or const case - else -> flagsOf(Flag.IS_PRIVATE) + property.isLateinit -> property.setter!!.visibility + property.getterSignature == null && property.setterSignature == null -> property.visibility // JvmField or const case + else -> Visibility.PRIVATE } - addMember(property.fieldSignature, fieldVisibility, isReified = false, propertyAnnotation = propertyAnnotations) + addMember( + property.fieldSignature, + fieldVisibility, + isReified = false, + propertyAnnotation = propertyAnnotations + ) } } - return ClassVisibility(classNode.name, flags, members.associateBy { it.member }, _facadeClassName) + return ClassVisibility(classNode.name, visibility, kind, members.associateBy { it.member }, _facadeClassName) } internal fun ClassNode.toClassVisibility() = kotlinMetadata?.toClassVisibility(this) diff --git a/src/main/kotlin/api/KotlinSignaturesLoading.kt b/src/main/kotlin/api/KotlinSignaturesLoading.kt index 0acb585f..5c7d0c10 100644 --- a/src/main/kotlin/api/KotlinSignaturesLoading.kt +++ b/src/main/kotlin/api/KotlinSignaturesLoading.kt @@ -5,10 +5,7 @@ package kotlinx.validation.api -import kotlinx.metadata.Flag -import kotlinx.metadata.KmProperty -import kotlinx.metadata.internal.metadata.jvm.deserialization.JvmFlags -import kotlinx.metadata.jvm.* +import kotlin.metadata.jvm.* import kotlinx.validation.* import org.objectweb.asm.* import org.objectweb.asm.tree.* @@ -198,7 +195,7 @@ private fun MethodNode.buildMethodSignature( private fun List.annotationsFor(methodSignature: JvmMethodSignature?): List { if (methodSignature == null) return emptyList() - return firstOrNull { it.name == methodSignature.name && it.desc == methodSignature.desc } + return firstOrNull { it.name == methodSignature.name && it.desc == methodSignature.descriptor } ?.run { visibleAnnotations.orEmpty() + invisibleAnnotations.orEmpty() } ?: emptyList() @@ -207,7 +204,7 @@ private fun List.annotationsFor(methodSignature: JvmMethodSignature? private fun List.annotationsFor(fieldSignature: JvmFieldSignature?): List { if (fieldSignature == null) return emptyList() - return firstOrNull { it.name == fieldSignature.name && it.desc == fieldSignature.desc } + return firstOrNull { it.name == fieldSignature.name && it.desc == fieldSignature.descriptor } ?.run { visibleAnnotations.orEmpty() + invisibleAnnotations.orEmpty() } ?: emptyList() From 1ef03badefab31f916055828bad5a8b31684d866 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Fri, 12 Jul 2024 15:49:56 +0200 Subject: [PATCH 2/4] Removed obsolete API use after merge --- src/main/kotlin/api/KotlinSignaturesLoading.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/api/KotlinSignaturesLoading.kt b/src/main/kotlin/api/KotlinSignaturesLoading.kt index 5c7d0c10..977401c4 100644 --- a/src/main/kotlin/api/KotlinSignaturesLoading.kt +++ b/src/main/kotlin/api/KotlinSignaturesLoading.kt @@ -12,6 +12,8 @@ import org.objectweb.asm.tree.* import java.io.* import java.util.* import java.util.jar.* +import kotlin.metadata.KmProperty +import kotlin.metadata.visibility @ExternalApi @Suppress("unused") @@ -130,7 +132,7 @@ private fun FieldNode.buildFieldSignature( val property = companionClassCandidate?.kmProperty(name) - if (property != null && JvmFlag.Property.IS_MOVED_FROM_INTERFACE_COMPANION(property.flags)) { + if (property != null && property.isMovedFromInterfaceCompanion) { /* * The property was moved from the companion object. Take all the annotations from there * to be able to filter out the non-public markers. @@ -160,7 +162,7 @@ private fun ClassNode.kmProperty(name: String?): KmProperty? { return null } - return metadata.toKmClass().properties.firstOrNull { + return metadata.kmClass.properties.firstOrNull { it.name == name } } From 3013d4177ec9dedc0754c0287ce3af45d8305978 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Fri, 12 Jul 2024 16:50:39 +0200 Subject: [PATCH 3/4] Fixed check for properties declared in a companion object --- src/main/kotlin/api/KotlinSignaturesLoading.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/api/KotlinSignaturesLoading.kt b/src/main/kotlin/api/KotlinSignaturesLoading.kt index 977401c4..15e915aa 100644 --- a/src/main/kotlin/api/KotlinSignaturesLoading.kt +++ b/src/main/kotlin/api/KotlinSignaturesLoading.kt @@ -131,10 +131,9 @@ private fun FieldNode.buildFieldSignature( } val property = companionClassCandidate?.kmProperty(name) - - if (property != null && property.isMovedFromInterfaceCompanion) { + if (property != null) { /* - * The property was moved from the companion object. Take all the annotations from there + * The property was declared in the companion object. Take all the annotations from there * to be able to filter out the non-public markers. * * See https://github.com/Kotlin/binary-compatibility-validator/issues/90 From 27919300e532a7f10cfe43ae5bd6a34f8a0ada40 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Fri, 12 Jul 2024 17:09:24 +0200 Subject: [PATCH 4/4] Use readLenient to be more lenient W.r.t. newer metadata versions --- src/main/kotlin/api/KotlinMetadataVisibilities.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/api/KotlinMetadataVisibilities.kt b/src/main/kotlin/api/KotlinMetadataVisibilities.kt index 7ab0259f..e73a66a6 100644 --- a/src/main/kotlin/api/KotlinMetadataVisibilities.kt +++ b/src/main/kotlin/api/KotlinMetadataVisibilities.kt @@ -67,7 +67,7 @@ internal val ClassNode.kotlinMetadata: KotlinClassMetadata? extraInt = get("xi") as Int? ) } - return KotlinClassMetadata.readStrict(header) + return KotlinClassMetadata.readLenient(header) }