Compare module metadata in JVM ABI consistency tests
This commit is contained in:
committed by
Space Team
parent
ba217ad688
commit
b74501ee93
+22
-7
@@ -5,19 +5,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.abicmp.checkers
|
||||
|
||||
import org.jetbrains.kotlin.abicmp.reports.MetadataPropertyReport
|
||||
import org.jetbrains.kotlin.abicmp.reports.NamedDiffEntry
|
||||
import kotlin.metadata.KmConstructor
|
||||
import kotlin.metadata.KmFunction
|
||||
import kotlin.metadata.KmProperty
|
||||
import kotlin.metadata.KmTypeAlias
|
||||
import org.jetbrains.kotlin.abicmp.reports.MetadataPropertyReport
|
||||
import org.jetbrains.kotlin.abicmp.reports.NamedDiffEntry
|
||||
import kotlin.metadata.jvm.KmModule
|
||||
import kotlin.metadata.jvm.KmPackageParts
|
||||
import kotlin.metadata.jvm.UnstableMetadataApi
|
||||
|
||||
interface GenericMetadataChecker<T> : Checker {
|
||||
fun check(metadata1: T, metadata2: T, report: MetadataPropertyReport)
|
||||
}
|
||||
|
||||
abstract class GenericMetadataPropertyChecker<T>(name: String) :
|
||||
PropertyChecker<String, T>("class.metadata.$name"),
|
||||
PropertyChecker<String, T>(name),
|
||||
GenericMetadataChecker<T> {
|
||||
|
||||
override fun check(metadata1: T, metadata2: T, report: MetadataPropertyReport) {
|
||||
@@ -29,22 +32,34 @@ abstract class GenericMetadataPropertyChecker<T>(name: String) :
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
fun moduleMetadataPropertyChecker(name: String, propertyGetter: (KmModule) -> String) =
|
||||
object : GenericMetadataPropertyChecker<KmModule>("module.metadata.$name") {
|
||||
override fun getProperty(node: KmModule) = propertyGetter(node)
|
||||
}
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
fun packagePartsPropertyChecker(name: String, propertyGetter: (KmPackageParts) -> String) =
|
||||
object : GenericMetadataPropertyChecker<KmPackageParts>("module.metadata.$name") {
|
||||
override fun getProperty(node: KmPackageParts) = propertyGetter(node)
|
||||
}
|
||||
|
||||
fun constructorMetadataPropertyChecker(name: String, propertyGetter: (KmConstructor) -> String) =
|
||||
object : GenericMetadataPropertyChecker<KmConstructor>("constructor.$name") {
|
||||
object : GenericMetadataPropertyChecker<KmConstructor>("class.metadata.constructor.$name") {
|
||||
override fun getProperty(node: KmConstructor) = propertyGetter(node)
|
||||
}
|
||||
|
||||
fun functionMetadataPropertyChecker(name: String, propertyGetter: (KmFunction) -> String) =
|
||||
object : GenericMetadataPropertyChecker<KmFunction>("function.$name") {
|
||||
object : GenericMetadataPropertyChecker<KmFunction>("class.metadata.function.$name") {
|
||||
override fun getProperty(node: KmFunction) = propertyGetter(node)
|
||||
}
|
||||
|
||||
fun typeAliasMetadataPropertyChecker(name: String, propertyGetter: (KmTypeAlias) -> String) =
|
||||
object : GenericMetadataPropertyChecker<KmTypeAlias>("typeAlias.$name") {
|
||||
object : GenericMetadataPropertyChecker<KmTypeAlias>("class.metadata.typeAlias.$name") {
|
||||
override fun getProperty(node: KmTypeAlias) = propertyGetter(node)
|
||||
}
|
||||
|
||||
fun propertyMetadataPropertyChecker(name: String, propertyGetter: (KmProperty) -> String) =
|
||||
object : GenericMetadataPropertyChecker<KmProperty>("property.$name") {
|
||||
object : GenericMetadataPropertyChecker<KmProperty>("class.metadata.property.$name") {
|
||||
override fun getProperty(node: KmProperty) = propertyGetter(node)
|
||||
}
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.abicmp.reports
|
||||
import org.jetbrains.kotlin.abicmp.tag
|
||||
import java.io.PrintWriter
|
||||
|
||||
class MetadataPropertyReport(val id: String, val header1: String, val header2: String) : ComparisonReport {
|
||||
open class MetadataPropertyReport(val id: String, val header1: String, val header2: String) : ComparisonReport {
|
||||
|
||||
private val propertyDiffs = ArrayList<NamedDiffEntry>()
|
||||
protected val propertyDiffs = ArrayList<NamedDiffEntry>()
|
||||
|
||||
override fun isEmpty() = propertyDiffs.isEmpty()
|
||||
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.abicmp.reports
|
||||
|
||||
import java.io.PrintWriter
|
||||
|
||||
class ModuleMetadataReport(header1: String, header2: String) : MetadataPropertyReport("MODULE METADATA", header1, header2) {
|
||||
|
||||
private val packagePartsReports = ArrayList<MetadataPropertyReport>()
|
||||
|
||||
override fun isEmpty() = propertyDiffs.isEmpty() && getFilteredPackagePartsReports().isEmpty()
|
||||
|
||||
override fun writeAsHtml(output: PrintWriter) {
|
||||
if (isEmpty()) return
|
||||
super.writeAsHtml(output)
|
||||
packagePartsReports.forEach { it.writeAsHtml(output) }
|
||||
}
|
||||
|
||||
fun TextTreeBuilderContext.appendModuleMetadataReport() {
|
||||
node("MODULE METADATA") {
|
||||
appendNamedDiffEntries(header1, header2, propertyDiffs, "Property")
|
||||
|
||||
for (report in getFilteredPackagePartsReports()) {
|
||||
with(report) { appendReport() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun packagePartsReport(id: String) = MetadataPropertyReport(id, header1, header2).also { packagePartsReports.add(it) }
|
||||
|
||||
private fun getFilteredPackagePartsReports() = packagePartsReports.filter { !it.isEmpty() }.sortedBy { it.id }
|
||||
|
||||
}
|
||||
+20
@@ -153,6 +153,23 @@ private val allPackageMetadataCheckers = listOf(
|
||||
fileFacadeMetadataListChecker("localDelegatedProperties") { loadLocalDelegatedProperties(it).keys.toList() }
|
||||
)
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
private val allPackagePartsMetadataCheckers = listOf(
|
||||
packagePartsPropertyChecker("multiFileParts") {
|
||||
it.multiFileClassParts.toList().map { filePart -> "(${filePart.first}, ${filePart.second})" }.toList().sorted()
|
||||
.joinToString(prefix = "[", postfix = "]")
|
||||
},
|
||||
packagePartsPropertyChecker("fileFacades") { it.fileFacades.toList().sorted().joinToString(prefix = "[", postfix = "]") }
|
||||
)
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
private val allModuleMetadataCheckers = listOf(
|
||||
moduleMetadataPropertyChecker("optionalAnnotations") {
|
||||
it.optionalAnnotationClasses.map { clazz -> clazz.name }.sorted().joinToString(prefix = "[", postfix = "]")
|
||||
},
|
||||
moduleMetadataPropertyChecker("packageParts") { it.packageParts.keys.toList().sorted().joinToString(prefix = "[", postfix = "]") }
|
||||
)
|
||||
|
||||
private val allMultifileClassFacadeMetadataCheckers = listOf(
|
||||
multiFileClassFacadeMetadataListChecker("partClassNames") { it.partClassNames }
|
||||
)
|
||||
@@ -190,6 +207,7 @@ inline fun checkerConfiguration(b: CheckerConfigurationBuilder.() -> Unit): Chec
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
class CheckerConfiguration(private val enabledExclusively: Set<String>, private val disabled: Set<String>) {
|
||||
|
||||
private fun <T : Checker> List<T>.filterOutDisabled() = filter { it.isEnabled() }
|
||||
@@ -206,6 +224,8 @@ class CheckerConfiguration(private val enabledExclusively: Set<String>, private
|
||||
val enabledMultifileClassFacadeMetadataCheckers = allMultifileClassFacadeMetadataCheckers.filterOutDisabled()
|
||||
val enabledMultifileClassPartMetadataCheckers = allMultifileClassPartMetadataCheckers.filterOutDisabled()
|
||||
val enabledAllSyntheticClassMetadataCheckers = allSyntheticClassMetadataCheckers.filterOutDisabled()
|
||||
val enabledModuleMetadataCheckers = allModuleMetadataCheckers.filterOutDisabled()
|
||||
val enabledPackagePartsMetadataCheckers = allPackagePartsMetadataCheckers.filterOutDisabled()
|
||||
|
||||
private fun Checker.isEnabled(): Boolean {
|
||||
if (enabledExclusively.isNotEmpty() && name !in enabledExclusively) return false
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.abicmp.tasks
|
||||
|
||||
import org.jetbrains.kotlin.abicmp.reports.ModuleMetadataReport
|
||||
import kotlin.metadata.jvm.KotlinModuleMetadata
|
||||
import kotlin.metadata.jvm.UnstableMetadataApi
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
class ModuleMetadataTask(
|
||||
private val configuration: CheckerConfiguration,
|
||||
metadata1Bytes: ByteArray,
|
||||
metadata2Bytes: ByteArray,
|
||||
private val report: ModuleMetadataReport,
|
||||
) : Runnable {
|
||||
|
||||
private val metadata1 = metadata1Bytes.toKmModule()
|
||||
private val metadata2 = metadata2Bytes.toKmModule()
|
||||
|
||||
|
||||
override fun run() {
|
||||
for (checker in configuration.enabledModuleMetadataCheckers) {
|
||||
checker.check(metadata1, metadata2, report)
|
||||
}
|
||||
|
||||
checkPackageParts()
|
||||
}
|
||||
|
||||
private fun checkPackageParts() {
|
||||
val packageParts1 = metadata1.packageParts
|
||||
val packageParts2 = metadata2.packageParts
|
||||
|
||||
val commonIds = packageParts1.keys.intersect(packageParts2.keys).sorted()
|
||||
for (id in commonIds) {
|
||||
val packagePart1 = packageParts1[id]!!
|
||||
val packagePart2 = packageParts2[id]!!
|
||||
val packagePartsReport = report.packagePartsReport(id)
|
||||
PackagePartsMetadataTask(configuration, packagePart1, packagePart2, packagePartsReport).run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
private fun ByteArray.toKmModule() = KotlinModuleMetadata.read(this).kmModule
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.abicmp.tasks
|
||||
|
||||
import org.jetbrains.kotlin.abicmp.reports.MetadataPropertyReport
|
||||
import kotlin.metadata.jvm.KmPackageParts
|
||||
import kotlin.metadata.jvm.UnstableMetadataApi
|
||||
|
||||
@OptIn(UnstableMetadataApi::class)
|
||||
class PackagePartsMetadataTask(
|
||||
private val configuration: CheckerConfiguration,
|
||||
private val packagePart1: KmPackageParts,
|
||||
private val packagePart2: KmPackageParts,
|
||||
private val packagePartsReport: MetadataPropertyReport
|
||||
): Runnable {
|
||||
override fun run() {
|
||||
for (checker in configuration.enabledPackagePartsMetadataCheckers) {
|
||||
checker.check(packagePart1, packagePart2, packagePartsReport)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user