Skip to content

Commit

Permalink
Update kotlin-metadata-jvm (#255)
Browse files Browse the repository at this point in the history
* Use stable kotlin-metadata-jvm version
* Fixed check for properties declared in a companion object
* Use readLenient to be more lenient w.r.t. newer metadata versions
  • Loading branch information
fzhinkin authored Jul 15, 2024
1 parent 040922e commit 6428c88
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 57 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/api/AsmMetadataLoading.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.*

Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/api/KotlinMetadataSignature.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand All @@ -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<AnnotationNode>
Expand Down Expand Up @@ -172,14 +172,14 @@ 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? {
if (outerClassMetadata !is KotlinClassMetadata.Class) {
// Happens when outerClassMetadata == KotlinClassMetadata$FileFacade for an example
return null
}
val outerKClass = outerClassMetadata.toKmClass()
val outerKClass = outerClassMetadata.kmClass
return name + "$" + outerKClass.companionObject
}
83 changes: 42 additions & 41 deletions src/main/kotlin/api/KotlinMetadataVisibilities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<JvmMemberSignature, MemberVisibility>,
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<ClassVisibility>()
}
Expand All @@ -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,
Expand All @@ -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(
Expand All @@ -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.readLenient(header)
}


Expand All @@ -92,62 +83,72 @@ 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<MemberVisibility>()

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<KmTypeParameter>.containsReified() = any { Flag.TypeParameter.IS_REIFIED(it.flags) }
fun List<KmTypeParameter>.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) {
val isReified = property.typeParameters.containsReified()
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)
Expand Down
18 changes: 8 additions & 10 deletions src/main/kotlin/api/KotlinSignaturesLoading.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@

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.*
import java.io.*
import java.util.*
import java.util.jar.*
import kotlin.metadata.KmProperty
import kotlin.metadata.visibility

@ExternalApi
@Suppress("unused")
Expand Down Expand Up @@ -132,10 +131,9 @@ private fun FieldNode.buildFieldSignature(
}

val property = companionClassCandidate?.kmProperty(name)

if (property != null && JvmFlag.Property.IS_MOVED_FROM_INTERFACE_COMPANION(property.flags)) {
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
Expand Down Expand Up @@ -163,7 +161,7 @@ private fun ClassNode.kmProperty(name: String?): KmProperty? {
return null
}

return metadata.toKmClass().properties.firstOrNull {
return metadata.kmClass.properties.firstOrNull {
it.name == name
}
}
Expand Down Expand Up @@ -198,7 +196,7 @@ private fun MethodNode.buildMethodSignature(
private fun List<MethodNode>.annotationsFor(methodSignature: JvmMethodSignature?): List<AnnotationNode> {
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()
Expand All @@ -207,7 +205,7 @@ private fun List<MethodNode>.annotationsFor(methodSignature: JvmMethodSignature?
private fun List<FieldNode>.annotationsFor(fieldSignature: JvmFieldSignature?): List<AnnotationNode> {
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()
Expand Down

0 comments on commit 6428c88

Please sign in to comment.