diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/metadata/utils/MetadataDeclarationsComparator.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/metadata/utils/MetadataDeclarationsComparator.kt index b073ecb2d76..af1d975206d 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/metadata/utils/MetadataDeclarationsComparator.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/metadata/utils/MetadataDeclarationsComparator.kt @@ -5,25 +5,28 @@ package org.jetbrains.kotlin.descriptors.commonizer.metadata.utils +import com.intellij.util.containers.FactoryMap import kotlinx.metadata.* import kotlinx.metadata.klib.* +import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.EntityKind.AnnotationKind +import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.EntityKind.TypeKind +import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.EntityKind.FlagKind import org.jetbrains.kotlin.descriptors.commonizer.utils.KNI_BRIDGE_FUNCTION_PREFIX import java.util.* +import kotlin.reflect.KProperty import kotlin.reflect.KProperty0 /** * Compares two metadata modules ([KlibModuleMetadata]). Returns [Result], which may hold a list * of found [Mismatch]s. * - * The entry point is [MetadataDeclarationsComparator.Companion.compareModules] function. + * The entry point is [MetadataDeclarationsComparator.Companion.compare] function. */ // TODO: extract to kotlinx-metadata-klib library? +@Suppress("unused") class MetadataDeclarationsComparator private constructor(private val config: Config) { interface Config { - val rootPathElement: String - get() = "" - /** * Certain auxiliary metadata entities may be intentionally excluded from comparison. * Ex: Kotlin/Native interface bridge functions. @@ -51,16 +54,195 @@ class MetadataDeclarationsComparator private constructor(private val config: Con } } + @Suppress("MemberVisibilityCanBePrivate") + sealed interface PathElement { + val name: String + + object Root : PathElement { + override val name get() = "Root" + } + + class Module(val moduleA: KlibModuleMetadata, val moduleB: KlibModuleMetadata) : PathElement { + override val name get() = moduleA.name + } + + class Package(packageFqName: String, val fragmentsA: List, val fragmentsB: List) : PathElement { + override val name = packageFqName.ifEmpty { "" } + } + + class Class(val clazzA: KmClass, val clazzB: KmClass) : PathElement { + override val name get() = clazzA.name + } + + class TypeAlias(val typeAliasA: KmTypeAlias, val typeAliasB: KmTypeAlias) : PathElement { + override val name get() = typeAliasA.name + } + + class Property(val propertyA: KmProperty, val propertyB: KmProperty) : PathElement { + override val name get() = propertyA.name + } + + class Function(val functionA: KmFunction, val functionB: KmFunction) : PathElement { + override val name get() = functionA.name + } + + class Constructor(val constructorA: KmConstructor, val constructorB: KmConstructor) : PathElement { + override val name get() = "constructor" + } + + class ValueParameter(val parameterA: KmValueParameter, val parameterB: KmValueParameter, val index: Int) : PathElement { + override val name get() = index.toString() + } + + class TypeParameter(val parameterA: KmTypeParameter, val parameterB: KmTypeParameter, val index: Int) : PathElement { + override val name get() = index.toString() + } + + class Type(val typeA: KmType, val typeB: KmType, val kind: TypeKind, val index: Int?) : PathElement { + override val name get() = if (index != null) "$kind $index" else kind.toString() + } + + class TypeArgument(val argumentA: KmTypeProjection, val argumentB: KmTypeProjection, val index: Int) : PathElement { + override val name get() = index.toString() + } + + class EnumEntry(val entryA: KlibEnumEntry, val entryB: KlibEnumEntry) : PathElement { + override val name get() = entryA.name + } + + companion object { + internal fun guess(entityA: E, entityB: E, entityKind: EntityKind, entityKey: String?): PathElement { + return when { + entityA is KmClass && entityB is KmClass -> Class(entityA, entityB) + entityA is KmTypeAlias && entityB is KmTypeAlias -> TypeAlias(entityA, entityB) + entityA is KmProperty && entityB is KmProperty -> Property(entityA, entityB) + entityA is KmFunction && entityB is KmFunction -> Function(entityA, entityB) + entityA is KmConstructor && entityB is KmConstructor -> Constructor(entityA, entityB) + entityA is KmValueParameter && entityB is KmValueParameter -> { + // there is single value parameter for property setter that does not have index, use 0 as fallback value + val index = entityKey?.toInt() ?: 0 + ValueParameter(entityA, entityB, index) + } + entityA is KmTypeParameter && entityB is KmTypeParameter -> { + val index = entityKey!!.toInt() + TypeParameter(entityA, entityB, index) + } + entityA is KmType && entityB is KmType -> { + val optionalIndex = entityKey?.toInt() + val typeKind = entityKind as TypeKind + Type(entityA, entityB, typeKind, optionalIndex) + } + entityA is KmTypeProjection && entityB is KmTypeProjection -> { + val index = entityKey!!.toInt() + TypeArgument(entityA, entityB, index) + } + entityA is KlibEnumEntry && entityB is KlibEnumEntry -> EnumEntry(entityA, entityB) + else -> error("Unknown combination of entities: ${entityA::class.java}, ${entityB::class.java}") + } + } + } + } + + sealed interface EntityKind { + enum class AnnotationKind : EntityKind { + REGULAR, + GETTER, + SETTER; + + override fun toString() = "AnnotationKind.$name" + } + + enum class TypeKind : EntityKind { + RETURN, + SUPERTYPE, + UNDERLYING, + EXPANDED, + RECEIVER, + ABBREVIATED, + OUTER, + UPPER_BOUND, + VALUE_PARAMETER, + VALUE_PARAMETER_VARARG, + TYPE_ARGUMENT; + + override fun toString() = "TypeKind.$name" + } + + enum class FlagKind : EntityKind { + REGULAR, + GETTER, + SETTER; + + override fun toString() = "FlagKind.$name" + } + + companion object { + val ModuleName by EntityKindImpl + + val Classifier by EntityKindImpl + + val Class by EntityKindImpl + val TypeAlias by EntityKindImpl + val Property by EntityKindImpl + val Function by EntityKindImpl + val Constructor by EntityKindImpl + + val FunctionValueParameter by EntityKindImpl + val SetterValueParameter by EntityKindImpl + + val TypeParameter by EntityKindImpl + val TypeParameterId by EntityKindImpl + val TypeParameterName by EntityKindImpl + val TypeParameterVariance by EntityKindImpl + + val TypeArgument by EntityKindImpl + val TypeArgumentVariance by EntityKindImpl + + val CompanionObject by EntityKindImpl + val NestedClass by EntityKindImpl + val SealedSubclass by EntityKindImpl + val EnumEntry by EntityKindImpl + val EnumEntryInKlib by EntityKindImpl + val EnumEntryInKlibOrdinal by EntityKindImpl + + val CompileTimeValue by EntityKindImpl + + val Contract by EntityKindImpl + val Effect by EntityKindImpl + val EffectType by EntityKindImpl + val EffectInvocationKind by EntityKindImpl + val EffectConstructorArguments by EntityKindImpl + val EffectConclusion by EntityKindImpl + val EffectExpressionParameterIndex by EntityKindImpl + val EffectExpressionConstantValue by EntityKindImpl + val EffectExpressionIsInstanceType by EntityKindImpl + val EffectExpressionAndArguments by EntityKindImpl + val EffectExpressionOrArguments by EntityKindImpl + + val FlexibleTypeUpperBounds by EntityKindImpl + val TypeFlexibilityId by EntityKindImpl + } + + private class EntityKindImpl(val name: String) : EntityKind { + override fun toString() = name + + companion object { + private val cache = FactoryMap.create { name -> EntityKindImpl(name) } + operator fun getValue(companion: EntityKind.Companion, property: KProperty<*>): EntityKind = cache.getValue(property.name) + } + } + } + sealed class Mismatch { - abstract val kind: String + abstract val kind: EntityKind abstract val name: String - abstract val path: List + abstract val path: List // an entity has different non-nullable values data class DifferentValues( - override val kind: String, + override val kind: EntityKind, override val name: String, - override val path: List, + override val path: List, val valueA: Any, val valueB: Any ) : Mismatch() @@ -68,9 +250,9 @@ class MetadataDeclarationsComparator private constructor(private val config: Con // an entity is missing at one side and present at another side, // or: an entity has nullable value at one side and non-nullable value at another side data class MissingEntity( - override val kind: String, + override val kind: EntityKind, override val name: String, - override val path: List, + override val path: List, val existentValue: Any, val missingInA: Boolean ) : Mismatch() { @@ -81,9 +263,9 @@ class MetadataDeclarationsComparator private constructor(private val config: Con private val mismatches = mutableListOf() - private class Context(pathElement: String, parent: Context? = null) { - val path: List = parent?.path.orEmpty() + pathElement - fun next(pathElement: String): Context = Context(pathElement, this) + private class Context(pathElement: PathElement, parent: Context? = null) { + val path: List = parent?.path.orEmpty() + pathElement + fun next(pathElement: PathElement): Context = Context(pathElement, this) } private fun toResult() = if (mismatches.isEmpty()) Result.Success else Result.Failure(mismatches) @@ -92,13 +274,13 @@ class MetadataDeclarationsComparator private constructor(private val config: Con metadataA: KlibModuleMetadata, metadataB: KlibModuleMetadata ): Result { - val rootContext = Context(config.rootPathElement) + val rootContext = Context(PathElement.Root) - compareValues(rootContext, metadataA.name, metadataB.name, "ModuleName") + compareValues(rootContext, metadataA.name, metadataB.name, EntityKind.ModuleName) if (mismatches.isNotEmpty()) return toResult() - val moduleContext = rootContext.next("Module ${metadataA.name}") + val moduleContext = rootContext.next(PathElement.Module(metadataA, metadataB)) compareAnnotationLists(moduleContext, metadataA.annotations, metadataB.annotations) compareModuleFragmentLists(moduleContext, metadataA.fragments, metadataB.fragments) @@ -110,7 +292,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, annotationListA: List, annotationListB: List, - annotationKind: String = "Annotation" + annotationKind: AnnotationKind = AnnotationKind.REGULAR ) { compareRepetitiveEntityLists( entityListA = annotationListA, @@ -144,7 +326,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con entityListB = fragmentListB, groupingKeySelector = { _, fragment -> fragment.fqName.orEmpty() }, groupedEntityListsComparator = { packageFqName: String, fragmentsA: List, fragmentsB: List -> - val packageContext = moduleContext.next("Package ${packageFqName.ifEmpty { "" }}") + val packageContext = moduleContext.next(PathElement.Package(packageFqName, fragmentsA, fragmentsB)) val classesA: List = fragmentsA.flatMap { it.classes } val classesB: List = fragmentsB.flatMap { it.classes } @@ -174,7 +356,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = containerContext, entityListA = classListA, entityListB = classListB, - entityKind = "Class", + entityKind = EntityKind.Class, groupingKeySelector = { _, clazz -> clazz.name }, entitiesComparator = ::compareClasses ) @@ -189,7 +371,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = containerContext, entityListA = typeAliasListA, entityListB = typeAliasListB, - entityKind = "TypeAlias", + entityKind = EntityKind.TypeAlias, groupingKeySelector = { _, typeAlias -> typeAlias.name }, entitiesComparator = ::compareTypeAliases ) @@ -204,7 +386,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = containerContext, entityListA = propertyListA, entityListB = propertyListB, - entityKind = "Property", + entityKind = EntityKind.Property, groupingKeySelector = { _, property -> property.name }, entitiesComparator = ::compareProperties ) @@ -219,7 +401,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = containerContext, entityListA = functionListA, entityListB = functionListB, - entityKind = "Function", + entityKind = EntityKind.Function, groupingKeySelector = { _, function -> function.mangle() }, entitiesComparator = ::compareFunctions ) @@ -234,7 +416,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = containerContext, entityListA = constructorListA, entityListB = constructorListB, - entityKind = "Constructor", + entityKind = EntityKind.Constructor, groupingKeySelector = { _, constructor -> constructor.mangle() }, entitiesComparator = ::compareConstructors ) @@ -249,7 +431,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = containerContext, entityListA = valueParameterListA, entityListB = valueParameterListB, - entityKind = "ValueParameter", + entityKind = EntityKind.FunctionValueParameter, groupingKeySelector = { index, _ -> index.toString() }, entitiesComparator = ::compareValueParameters ) @@ -259,7 +441,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, typeListA: List, typeListB: List, - typeKind: String + typeKind: TypeKind ) { compareUniqueEntityLists( containerContext = containerContext, @@ -280,7 +462,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = containerContext, entityListA = typeParameterListA, entityListB = typeParameterListB, - entityKind = "TypeParameter", + entityKind = EntityKind.TypeParameter, groupingKeySelector = { index, _ -> index.toString() }, entitiesComparator = ::compareTypeParameters ) @@ -290,7 +472,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, effectExpressionListA: List, effectExpressionListB: List, - effectExpressionKind: String + effectExpressionKind: EntityKind ) { compareUniqueEntityLists( containerContext = containerContext, @@ -312,27 +494,27 @@ class MetadataDeclarationsComparator private constructor(private val config: Con compareTypeParameterLists(classContext, classA.typeParameters, classB.typeParameters) - compareTypeLists(classContext, classA.supertypes, classB.supertypes, "Supertype") + compareTypeLists(classContext, classA.supertypes, classB.supertypes, TypeKind.SUPERTYPE) compareConstructorLists(classContext, classA.constructors, classB.constructors) compareTypeAliasLists(classContext, classA.typeAliases, classB.typeAliases) comparePropertyLists(classContext, classA.properties, classB.properties) compareFunctionLists(classContext, classA.functions, classB.functions) - compareNullableValues(classContext, classA.companionObject, classB.companionObject, "CompanionObject") - compareValueLists(classContext, classA.nestedClasses, classB.nestedClasses, "NestedClass") - compareValueLists(classContext, classA.sealedSubclasses, classB.sealedSubclasses, "SealedSubclass") - compareValueLists(classContext, classA.enumEntries, classB.enumEntries, "EnumEntry") + compareNullableValues(classContext, classA.companionObject, classB.companionObject, EntityKind.CompanionObject) + compareValueLists(classContext, classA.nestedClasses, classB.nestedClasses, EntityKind.NestedClass) + compareValueLists(classContext, classA.sealedSubclasses, classB.sealedSubclasses, EntityKind.SealedSubclass) + compareValueLists(classContext, classA.enumEntries, classB.enumEntries, EntityKind.EnumEntry) compareUniqueEntityLists( containerContext = classContext, entityListA = classA.klibEnumEntries, entityListB = classB.klibEnumEntries, - entityKind = "KlibEnumEntry", + entityKind = EntityKind.EnumEntryInKlib, groupingKeySelector = { _, enumEntry -> enumEntry.name } ) { klibEnumEntryContext, entryA, entryB -> compareAnnotationLists(klibEnumEntryContext, entryA.annotations, entryB.annotations) - compareNullableValues(klibEnumEntryContext, entryA.ordinal, entryB.ordinal, "Ordinal") + compareNullableValues(klibEnumEntryContext, entryA.ordinal, entryB.ordinal, EntityKind.EnumEntryInKlibOrdinal) } } @@ -350,14 +532,14 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = typeAliasContext, entityA = typeAliasA.underlyingType, entityB = typeAliasB.underlyingType, - entityKind = "UnderlyingType", + entityKind = TypeKind.UNDERLYING, entitiesComparator = ::compareTypes ) compareEntities( containerContext = typeAliasContext, entityA = typeAliasA.expandedType, entityB = typeAliasB.expandedType, - entityKind = "ExpandedType", + entityKind = TypeKind.EXPANDED, entitiesComparator = ::compareTypes ) } @@ -369,12 +551,12 @@ class MetadataDeclarationsComparator private constructor(private val config: Con propertyB: KmProperty ) { compareFlags(propertyContext, propertyA.flags, propertyB.flags, PROPERTY_FLAGS) - compareFlags(propertyContext, propertyA.getterFlags, propertyB.getterFlags, PROPERTY_ACCESSOR_FLAGS, "GetterFlag") - compareFlags(propertyContext, propertyA.setterFlags, propertyB.setterFlags, PROPERTY_ACCESSOR_FLAGS, "SetterFlag") + compareFlags(propertyContext, propertyA.getterFlags, propertyB.getterFlags, PROPERTY_ACCESSOR_FLAGS, FlagKind.GETTER) + compareFlags(propertyContext, propertyA.setterFlags, propertyB.setterFlags, PROPERTY_ACCESSOR_FLAGS, FlagKind.SETTER) compareAnnotationLists(propertyContext, propertyA.annotations, propertyB.annotations) - compareAnnotationLists(propertyContext, propertyA.getterAnnotations, propertyB.getterAnnotations, "GetterAnnotation") - compareAnnotationLists(propertyContext, propertyA.setterAnnotations, propertyB.setterAnnotations, "SetterAnnotation") + compareAnnotationLists(propertyContext, propertyA.getterAnnotations, propertyB.getterAnnotations, AnnotationKind.GETTER) + compareAnnotationLists(propertyContext, propertyA.setterAnnotations, propertyB.setterAnnotations, AnnotationKind.SETTER) compareTypeParameterLists(propertyContext, propertyA.typeParameters, propertyB.typeParameters) @@ -382,14 +564,14 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = propertyContext, entityA = propertyA.receiverParameterType, entityB = propertyB.receiverParameterType, - entityKind = "ReceiverParameterType", + entityKind = TypeKind.RECEIVER, entitiesComparator = ::compareTypes ) compareEntities( containerContext = propertyContext, entityA = propertyA.returnType, entityB = propertyB.returnType, - entityKind = "ReturnType", + entityKind = TypeKind.RETURN, entitiesComparator = ::compareTypes ) @@ -397,11 +579,11 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = propertyContext, entityA = propertyA.setterParameter, entityB = propertyB.setterParameter, - entityKind = "SetterValueParameter", + entityKind = EntityKind.SetterValueParameter, entitiesComparator = ::compareValueParameters ) - compareNullableValues(propertyContext, propertyA.compileTimeValue, propertyB.compileTimeValue, "CompileTimeValue") + compareNullableValues(propertyContext, propertyA.compileTimeValue, propertyB.compileTimeValue, EntityKind.CompileTimeValue) } @Suppress("DuplicatedCode") @@ -419,14 +601,14 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = functionContext, entityA = functionA.receiverParameterType, entityB = functionB.receiverParameterType, - entityKind = "ReceiverParameterType", + entityKind = TypeKind.RECEIVER, entitiesComparator = ::compareTypes ) compareEntities( containerContext = functionContext, entityA = functionA.returnType, entityB = functionB.returnType, - entityKind = "ReturnType", + entityKind = TypeKind.RETURN, entitiesComparator = ::compareTypes ) @@ -436,29 +618,29 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = functionContext, entityA = functionA.contract, entityB = functionB.contract, - entityKind = "Contract" + entityKind = EntityKind.Contract ) { contractContext, contractA, contractB -> compareUniqueEntityLists( containerContext = contractContext, entityListA = contractA.effects, entityListB = contractB.effects, - entityKind = "Effect", + entityKind = EntityKind.Effect, groupingKeySelector = { index, _ -> index.toString() } ) { effectContext, effectA, effectB -> - compareValues(effectContext, effectA.type, effectB.type, "EffectType") - compareNullableValues(effectContext, effectA.invocationKind, effectB.invocationKind, "EffectInvocationKind") + compareValues(effectContext, effectA.type, effectB.type, EntityKind.EffectType) + compareNullableValues(effectContext, effectA.invocationKind, effectB.invocationKind, EntityKind.EffectInvocationKind) compareEffectExpressionLists( containerContext = effectContext, effectExpressionListA = effectA.constructorArguments, effectExpressionListB = effectB.constructorArguments, - effectExpressionKind = "ConstructorArguments" + effectExpressionKind = EntityKind.EffectConstructorArguments ) compareNullableEntities( containerContext = effectContext, entityA = effectA.conclusion, entityB = effectB.conclusion, - entityKind = "Conclusion", + entityKind = EntityKind.EffectConclusion, entitiesComparator = ::compareEffectExpressions ) } @@ -488,14 +670,14 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = valueParameterContext, entityA = valueParameterA.type, entityB = valueParameterB.type, - entityKind = "Type", + entityKind = TypeKind.VALUE_PARAMETER, entitiesComparator = ::compareTypes ) compareNullableEntities( containerContext = valueParameterContext, entityA = valueParameterA.varargElementType, entityB = valueParameterB.varargElementType, - entityKind = "VarargElementType", + entityKind = TypeKind.VALUE_PARAMETER_VARARG, entitiesComparator = ::compareTypes ) } @@ -508,37 +690,37 @@ class MetadataDeclarationsComparator private constructor(private val config: Con compareFlags(typeContext, typeA.flags, typeB.flags, TYPE_FLAGS) compareAnnotationLists(typeContext, typeA.annotations, typeB.annotations) - compareValues(typeContext, typeA.classifier, typeB.classifier, "Classifier") + compareValues(typeContext, typeA.classifier, typeB.classifier, EntityKind.Classifier) compareUniqueEntityLists( containerContext = typeContext, entityListA = typeA.arguments, entityListB = typeB.arguments, - entityKind = "TypeProjection", + entityKind = EntityKind.TypeArgument, groupingKeySelector = { index, _ -> index.toString() } ) { typeProjectionContext, typeProjectionA, typeProjectionB -> compareNullableEntities( containerContext = typeProjectionContext, entityA = typeProjectionA.type, entityB = typeProjectionB.type, - entityKind = "Type", + entityKind = TypeKind.TYPE_ARGUMENT, entitiesComparator = ::compareTypes ) - compareNullableValues(typeProjectionContext, typeProjectionA.variance, typeProjectionB.variance, "Variance") + compareNullableValues(typeProjectionContext, typeProjectionA.variance, typeProjectionB.variance, EntityKind.TypeArgumentVariance) } compareNullableEntities( containerContext = typeContext, entityA = typeA.abbreviatedType, entityB = typeB.abbreviatedType, - entityKind = "AbbreviatedType", + entityKind = TypeKind.ABBREVIATED, entitiesComparator = ::compareTypes ) compareNullableEntities( containerContext = typeContext, entityA = typeA.outerType, entityB = typeB.outerType, - entityKind = "OuterType", + entityKind = TypeKind.OUTER, entitiesComparator = ::compareTypes ) @@ -546,16 +728,16 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = typeContext, entityA = typeA.flexibleTypeUpperBound, entityB = typeB.flexibleTypeUpperBound, - entityKind = "FlexibleTypeUpperBounds", + entityKind = EntityKind.FlexibleTypeUpperBounds, ) { typeUpperBoundContext, upperBoundA, upperBoundB -> compareEntities( containerContext = typeUpperBoundContext, entityA = upperBoundA.type, entityB = upperBoundB.type, - entityKind = "Type", + entityKind = TypeKind.UPPER_BOUND, entitiesComparator = ::compareTypes ) - compareNullableValues(typeUpperBoundContext, upperBoundA.typeFlexibilityId, upperBoundB.typeFlexibilityId, "TypeFlexibilityId") + compareNullableValues(typeUpperBoundContext, upperBoundA.typeFlexibilityId, upperBoundB.typeFlexibilityId, EntityKind.TypeFlexibilityId) } } @@ -567,11 +749,11 @@ class MetadataDeclarationsComparator private constructor(private val config: Con compareFlags(typeParameterContext, typeParameterA.flags, typeParameterB.flags, TYPE_PARAMETER_FLAGS) compareAnnotationLists(typeParameterContext, typeParameterA.annotations, typeParameterB.annotations) - compareValues(typeParameterContext, typeParameterA.id, typeParameterB.id, "Id") - compareValues(typeParameterContext, typeParameterA.name, typeParameterB.name, "Name") + compareValues(typeParameterContext, typeParameterA.id, typeParameterB.id, EntityKind.TypeParameterId) + compareValues(typeParameterContext, typeParameterA.name, typeParameterB.name, EntityKind.TypeParameterName) - compareValues(typeParameterContext, typeParameterA.variance, typeParameterB.variance, "Variance") - compareTypeLists(typeParameterContext, typeParameterA.upperBounds, typeParameterB.upperBounds, "UpperBoundType") + compareValues(typeParameterContext, typeParameterA.variance, typeParameterB.variance, EntityKind.TypeParameterVariance) + compareTypeLists(typeParameterContext, typeParameterA.upperBounds, typeParameterB.upperBounds, TypeKind.UPPER_BOUND) } private fun compareEffectExpressions( @@ -580,14 +762,14 @@ class MetadataDeclarationsComparator private constructor(private val config: Con effectExpressionB: KmEffectExpression ) { compareFlags(effectExpressionContext, effectExpressionA.flags, effectExpressionB.flags, EFFECT_EXPRESSION_FLAGS) - compareNullableValues(effectExpressionContext, effectExpressionA.parameterIndex, effectExpressionB.parameterIndex, "ParameterIndex") - compareNullableValues(effectExpressionContext, effectExpressionA.constantValue, effectExpressionB.constantValue, "ConstantValue") + compareNullableValues(effectExpressionContext, effectExpressionA.parameterIndex, effectExpressionB.parameterIndex, EntityKind.EffectExpressionParameterIndex) + compareNullableValues(effectExpressionContext, effectExpressionA.constantValue, effectExpressionB.constantValue, EntityKind.EffectExpressionConstantValue) compareNullableEntities( containerContext = effectExpressionContext, entityA = effectExpressionA.isInstanceType, entityB = effectExpressionB.isInstanceType, - entityKind = "IsInstanceType", + entityKind = EntityKind.EffectExpressionIsInstanceType, entitiesComparator = ::compareTypes ) @@ -595,13 +777,13 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext = effectExpressionContext, effectExpressionListA = effectExpressionA.andArguments, effectExpressionListB = effectExpressionB.andArguments, - effectExpressionKind = "AndArguments" + effectExpressionKind = EntityKind.EffectExpressionAndArguments ) compareEffectExpressionLists( containerContext = effectExpressionContext, effectExpressionListA = effectExpressionA.orArguments, effectExpressionListB = effectExpressionB.orArguments, - effectExpressionKind = "OrArguments" + effectExpressionKind = EntityKind.EffectExpressionOrArguments ) } @@ -609,7 +791,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, valueA: E, valueB: E, - valueKind: String, + valueKind: EntityKind, valueName: String? = null ) { if (valueA != valueB) @@ -620,7 +802,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, listA: Collection, listB: Collection, - valueKind: String + valueKind: EntityKind ) { if (listA.isEmpty() && listB.isEmpty()) return @@ -638,7 +820,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, valueA: E?, valueB: E?, - valueKind: String + valueKind: EntityKind ) { when { valueA == null && valueB != null -> { @@ -657,11 +839,11 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, entityA: E, entityB: E, - entityKind: String, + entityKind: EntityKind, entityKey: String? = null, entitiesComparator: (Context, E, E) -> Unit ) { - val entityContext = containerContext.next("$entityKind${if (entityKey.isNullOrEmpty()) "" else " $entityKey"}") + val entityContext = containerContext.next(PathElement.guess(entityA, entityB, entityKind, entityKey)) entitiesComparator(entityContext, entityA, entityB) } @@ -669,7 +851,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, entityA: E?, entityB: E?, - entityKind: String, + entityKind: EntityKind, entityKey: String? = null, entitiesComparator: (Context, E, E) -> Unit ) { @@ -690,7 +872,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con containerContext: Context, entityListA: List, entityListB: List, - entityKind: String, + entityKind: EntityKind, groupingKeySelector: (index: Int, E) -> String, entitiesComparator: (Context, E, E) -> Unit ) { @@ -743,7 +925,7 @@ class MetadataDeclarationsComparator private constructor(private val config: Con flagsA: Flags, flagsB: Flags, flagsToCompare: Array>, - flagKind: String = "Flag" + flagKind: FlagKind = FlagKind.REGULAR ) { for (flag in flagsToCompare) { val valueA = flag.get()(flagsA) diff --git a/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/assertions.kt b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/assertions.kt index 72709bef6c6..b237af58818 100644 --- a/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/assertions.kt +++ b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/assertions.kt @@ -9,8 +9,7 @@ import kotlinx.metadata.klib.KlibModuleMetadata import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget import org.jetbrains.kotlin.descriptors.commonizer.identityString import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator -import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.Mismatch -import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.Result +import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.* import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.SerializedMetadataLibraryProvider import org.jetbrains.kotlin.library.SerializedMetadata import java.io.File @@ -31,7 +30,7 @@ fun assertModulesAreEqual(reference: SerializedMetadata, generated: SerializedMe is Result.Success -> Unit is Result.Failure -> { val mismatches = result.mismatches - .filter(FILTER_OUR_ACCEPTABLE_MISMATCHES) + .filter(FILTER_OUT_ACCEPTABLE_MISMATCHES) .sortedBy { it::class.java.simpleName + "_" + it.kind } if (mismatches.isEmpty()) return @@ -50,23 +49,29 @@ fun assertModulesAreEqual(reference: SerializedMetadata, generated: SerializedMe } } -private val FILTER_OUR_ACCEPTABLE_MISMATCHES: (Mismatch) -> Boolean = { mismatch -> +private val FILTER_OUT_ACCEPTABLE_MISMATCHES: (Mismatch) -> Boolean = { mismatch -> var isAcceptableMismatch = false // don't filter it out by default if (mismatch is Mismatch.MissingEntity) { - if (mismatch.kind == "AbbreviatedType") { + if (mismatch.kind == EntityKind.TypeKind.ABBREVIATED) { val usefulPath = mismatch.path - .dropWhile { !it.startsWith("Package ") } + .dropWhile { it !is PathElement.Package } .drop(1) - .joinToString(" > ") { it.substringBefore(' ') } if (mismatch.missingInA) { - if (usefulPath == "TypeAlias > ExpandedType") { + if (usefulPath.size == 2 + && usefulPath[0] is PathElement.TypeAlias + && (usefulPath[1] as? PathElement.Type)?.kind == EntityKind.TypeKind.EXPANDED + ) { // extra abbreviated type appeared in commonized declaration, it's OK isAcceptableMismatch = true } } else /*if (mismatch.missingInB)*/ { - if ("> ReturnType >" in usefulPath && usefulPath.endsWith("TypeProjection > Type")) { + if (usefulPath.size > 2 + && usefulPath.any { (it as? PathElement.Type)?.kind == EntityKind.TypeKind.RETURN } + && usefulPath[usefulPath.size - 2] is PathElement.TypeArgument + && (usefulPath[usefulPath.size - 1] as? PathElement.Type)?.kind == EntityKind.TypeKind.TYPE_ARGUMENT + ) { // extra abbreviated type gone in type argument of commonized declaration, it's OK isAcceptableMismatch = true }