[KLIB] ABI reader: Show fake overrides for classes inherited from classes produced by Native interop tool

^KT-54402
This commit is contained in:
Dmitriy Dolovov
2023-07-28 14:19:32 +02:00
committed by Space Team
parent 18668539e9
commit 32e4b7a76f
@@ -20,6 +20,9 @@ import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.library.abi.* import org.jetbrains.kotlin.library.abi.*
import org.jetbrains.kotlin.library.abi.AbiClassifierReference.ClassReference import org.jetbrains.kotlin.library.abi.AbiClassifierReference.ClassReference
import org.jetbrains.kotlin.library.abi.AbiTypeNullability.* import org.jetbrains.kotlin.library.abi.AbiTypeNullability.*
import org.jetbrains.kotlin.library.abi.impl.LibraryDeserializer.ContainingEntity.Class.Companion.excludeFakeOverrides
import org.jetbrains.kotlin.library.abi.impl.LibraryDeserializer.TypeDeserializer.Companion.underlyingTypeId
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
@@ -91,6 +94,8 @@ private class LibraryDeserializer(
supportedSignatureVersions: Set<AbiSignatureVersion>, supportedSignatureVersions: Set<AbiSignatureVersion>,
private val compositeFilter: AbiReadingFilter.Composite? private val compositeFilter: AbiReadingFilter.Composite?
) { ) {
private val platform: BuiltInsPlatform? = library.builtInsPlatform?.let(BuiltInsPlatform::parseFromString)
private val interner = IrInterningService() private val interner = IrInterningService()
private val annotationsInterner = object { private val annotationsInterner = object {
@@ -188,13 +193,14 @@ private class LibraryDeserializer(
return null return null
val flags = ClassFlags.decode(proto.base.flags) val flags = ClassFlags.decode(proto.base.flags)
val modality = flags.modality.toAbiModality( val modality = flags.modality.toAbiModality(
containingClassModality = null // Open nested classes in a final class remain open. containingClassModality = null // Open nested classes in a final class remain open.
) )
val qualifiedName = deserializeQualifiedName(proto.name, containingEntity) val qualifiedName = deserializeQualifiedName(proto.name, containingEntity)
val thisClassEntity = ContainingEntity.Class(qualifiedName, modality) val thisClassEntity = ContainingEntity.Class(qualifiedName, modality, lazyExcludeFakeOverrides = {
platform != BuiltInsPlatform.NATIVE || !isDirectlyInheritedFromNativeInteropClass(proto)
})
// Note: For inner classes pass the `parentTypeParameterResolver` to the constructor so that it could be // Note: For inner classes pass the `parentTypeParameterResolver` to the constructor so that it could be
// possible to resolve TPs by delegating to the parent TP resolver. For non-inner classes just keep // possible to resolve TPs by delegating to the parent TP resolver. For non-inner classes just keep
@@ -211,7 +217,7 @@ private class LibraryDeserializer(
return AbiClassImpl( return AbiClassImpl(
qualifiedName = qualifiedName, qualifiedName = qualifiedName,
signatures = deserializeSignatures(proto.base), signatures = deserializeIdSignature(proto.base.symbol).toAbiSignatures(),
annotations = annotations, annotations = annotations,
modality = modality, modality = modality,
kind = when (val kind = flags.kind) { kind = when (val kind = flags.kind) {
@@ -233,6 +239,24 @@ private class LibraryDeserializer(
) )
} }
private fun isDirectlyInheritedFromNativeInteropClass(proto: ProtoClass): Boolean {
fun extractIdSignature(typeId: Int): IdSignature? {
val type = fileReader.type(typeId)
val symbolId = when (type.kindCase) {
ProtoType.KindCase.DNN -> return extractIdSignature(type.dnn.underlyingTypeId)
ProtoType.KindCase.SIMPLE -> type.simple.classifier
ProtoType.KindCase.LEGACYSIMPLE -> type.legacySimple.classifier
ProtoType.KindCase.DYNAMIC, ProtoType.KindCase.ERROR, ProtoType.KindCase.KIND_NOT_SET, null -> return null
}
return deserializeIdSignature(symbolId)
}
return proto.superTypeList.any { superTypeId ->
val idSignature = extractIdSignature(superTypeId) ?: return@any false
with(idSignature) { Flags.IS_NATIVE_INTEROP_LIBRARY.test() }
}
}
private inline fun deserializeTypes( private inline fun deserializeTypes(
typeIds: List<Int>, typeIds: List<Int>,
typeParameterResolver: TypeParameterResolver, typeParameterResolver: TypeParameterResolver,
@@ -244,7 +268,7 @@ private class LibraryDeserializer(
private fun deserializeEnumEntry(proto: ProtoEnumEntry, containingEntity: ContainingEntity): AbiEnumEntry { private fun deserializeEnumEntry(proto: ProtoEnumEntry, containingEntity: ContainingEntity): AbiEnumEntry {
return AbiEnumEntryImpl( return AbiEnumEntryImpl(
qualifiedName = deserializeQualifiedName(proto.name, containingEntity), qualifiedName = deserializeQualifiedName(proto.name, containingEntity),
signatures = deserializeSignatures(proto.base), signatures = deserializeIdSignature(proto.base.symbol).toAbiSignatures(),
annotations = deserializeAnnotations(proto.base) annotations = deserializeAnnotations(proto.base)
) )
} }
@@ -257,17 +281,29 @@ private class LibraryDeserializer(
): AbiFunction? { ): AbiFunction? {
val annotations = deserializeAnnotations(proto.base) val annotations = deserializeAnnotations(proto.base)
val containingClassModality = when (containingEntity) { val containingProperty: ContainingEntity.Property?
is ContainingEntity.Class -> containingEntity.modality val containingClass: ContainingEntity.Class?
is ContainingEntity.Property -> containingEntity.containingClassModality
else -> null when (containingEntity) {
is ContainingEntity.Class -> {
containingProperty = null
containingClass = containingEntity
}
is ContainingEntity.Property -> {
containingProperty = containingEntity
containingClass = containingEntity.containingClass
}
else -> {
containingProperty = null
containingClass = null
}
} }
val parentPropertyVisibilityStatus = (containingEntity as? ContainingEntity.Property)?.propertyVisibilityStatus val parentPropertyVisibilityStatus = containingProperty?.propertyVisibilityStatus
if (!computeVisibilityStatus( if (!computeVisibilityStatus(
proto.base, proto.base,
annotations, annotations,
containingClassModality, containingClass?.modality,
parentPropertyVisibilityStatus parentPropertyVisibilityStatus
).isPubliclyVisible ).isPubliclyVisible
) { ) {
@@ -275,7 +311,7 @@ private class LibraryDeserializer(
} }
val flags = FunctionFlags.decode(proto.base.flags) val flags = FunctionFlags.decode(proto.base.flags)
if (flags.isFakeOverride) // TODO: FO of class with supertype from interop library if (flags.isFakeOverride && containingClass.excludeFakeOverrides)
return null return null
val nameAndType = BinaryNameAndType.decode(proto.nameType) val nameAndType = BinaryNameAndType.decode(proto.nameType)
@@ -289,14 +325,14 @@ private class LibraryDeserializer(
// Reuse the TP resolved from the class, as constructors can't have own TPs. // Reuse the TP resolved from the class, as constructors can't have own TPs.
parentTypeParameterResolver!! parentTypeParameterResolver!!
} }
containingEntity is ContainingEntity.Property -> { containingProperty != null -> {
// 1. A TP of a serialized property accessor has signature that points to the property itself. // 1. A TP of a serialized property accessor has signature that points to the property itself.
// So for the need of TP resolution it's necessary to pass the name of the property to the TP resolver. // So for the need of TP resolution it's necessary to pass the name of the property to the TP resolver.
// 2. Properties don't have their own TPs, but their accessors can have TPs. This means that there is // 2. Properties don't have their own TPs, but their accessors can have TPs. This means that there is
// no need to create a TP resolver for a property, only for the accessor. To make rendering of // no need to create a TP resolver for a property, only for the accessor. To make rendering of
// accessor's TPs consistent with the position of the accessor inside the declaration's tree, // accessor's TPs consistent with the position of the accessor inside the declaration's tree,
// it's necessary to adjust the "level" field inside the TP resolver by 1. // it's necessary to adjust the "level" field inside the TP resolver by 1.
TypeParameterResolver(containingEntity.propertyName, parentTypeParameterResolver, levelAdjustment = 1) TypeParameterResolver(containingProperty.propertyName, parentTypeParameterResolver, levelAdjustment = 1)
} }
else -> TypeParameterResolver(functionName, parentTypeParameterResolver) else -> TypeParameterResolver(functionName, parentTypeParameterResolver)
} }
@@ -316,7 +352,7 @@ private class LibraryDeserializer(
AbiConstructorImpl( AbiConstructorImpl(
qualifiedName = functionName, qualifiedName = functionName,
signatures = deserializeSignatures(proto.base), signatures = deserializeIdSignature(proto.base.symbol).toAbiSignatures(),
annotations = annotations, annotations = annotations,
isInline = flags.isInline, isInline = flags.isInline,
contextReceiverParametersCount = contextReceiversCount, contextReceiverParametersCount = contextReceiversCount,
@@ -329,9 +365,9 @@ private class LibraryDeserializer(
AbiFunctionImpl( AbiFunctionImpl(
qualifiedName = functionName, qualifiedName = functionName,
signatures = deserializeSignatures(proto.base), signatures = deserializeIdSignature(proto.base.symbol).toAbiSignatures(),
annotations = annotations, annotations = annotations,
modality = flags.modality.toAbiModality(containingClassModality), modality = flags.modality.toAbiModality(containingClass?.modality),
isInline = flags.isInline, isInline = flags.isInline,
isSuspend = flags.isSuspend, isSuspend = flags.isSuspend,
typeParameters = deserializeTypeParameters(proto.typeParameterList, thisFunctionTypeParameterResolver), typeParameters = deserializeTypeParameters(proto.typeParameterList, thisFunctionTypeParameterResolver),
@@ -349,24 +385,24 @@ private class LibraryDeserializer(
typeParameterResolver: TypeParameterResolver? typeParameterResolver: TypeParameterResolver?
): AbiProperty? { ): AbiProperty? {
val annotations = deserializeAnnotations(proto.base) val annotations = deserializeAnnotations(proto.base)
val containingClassModality = (containingEntity as? ContainingEntity.Class)?.modality val containingClass: ContainingEntity.Class? = containingEntity as? ContainingEntity.Class
val visibilityStatus = computeVisibilityStatus(proto.base, annotations, containingClassModality) val visibilityStatus = computeVisibilityStatus(proto.base, annotations, containingClass?.modality)
if (!visibilityStatus.isPubliclyVisible) if (!visibilityStatus.isPubliclyVisible)
return null return null
val flags = PropertyFlags.decode(proto.base.flags) val flags = PropertyFlags.decode(proto.base.flags)
if (flags.isFakeOverride) // TODO: FO of class with supertype from interop library if (flags.isFakeOverride && containingClass.excludeFakeOverrides)
return null return null
val qualifiedName = deserializeQualifiedName(proto.name, containingEntity) val qualifiedName = deserializeQualifiedName(proto.name, containingEntity)
val thisPropertyEntity = ContainingEntity.Property(qualifiedName, containingClassModality, visibilityStatus) val thisPropertyEntity = ContainingEntity.Property(qualifiedName, containingClass, visibilityStatus)
return AbiPropertyImpl( return AbiPropertyImpl(
qualifiedName = qualifiedName, qualifiedName = qualifiedName,
signatures = deserializeSignatures(proto.base), signatures = deserializeIdSignature(proto.base.symbol).toAbiSignatures(),
annotations = annotations, annotations = annotations,
modality = flags.modality.toAbiModality(containingClassModality), modality = flags.modality.toAbiModality(containingClass?.modality),
kind = when { kind = when {
flags.isConst -> AbiPropertyKind.CONST_VAL flags.isConst -> AbiPropertyKind.CONST_VAL
flags.isVar -> AbiPropertyKind.VAR flags.isVar -> AbiPropertyKind.VAR
@@ -395,15 +431,16 @@ private class LibraryDeserializer(
return containingEntity.computeNestedName(fileReader.string(nameId)) return containingEntity.computeNestedName(fileReader.string(nameId))
} }
private fun deserializeSignatures(proto: ProtoDeclarationBase): AbiSignatures { private fun deserializeIdSignature(symbolId: Long): IdSignature {
val signature = deserializeIdSignature(proto.symbol) val signatureId = BinarySymbolData.decode(symbolId).signatureId
return signatureDeserializer.deserializeIdSignature(signatureId)
return AbiSignaturesImpl(
signatureV1 = if (needV1Signatures) signature.render(IdSignatureRenderer.LEGACY) else null,
signatureV2 = if (needV2Signatures) signature.render(IdSignatureRenderer.DEFAULT) else null
)
} }
private fun IdSignature.toAbiSignatures(): AbiSignatures = AbiSignaturesImpl(
signatureV1 = if (needV1Signatures) render(IdSignatureRenderer.LEGACY) else null,
signatureV2 = if (needV2Signatures) render(IdSignatureRenderer.DEFAULT) else null
)
private fun deserializeTypeParameters( private fun deserializeTypeParameters(
protos: List<ProtoTypeParameter>, protos: List<ProtoTypeParameter>,
typeParameterResolver: TypeParameterResolver, typeParameterResolver: TypeParameterResolver,
@@ -422,11 +459,11 @@ private class LibraryDeserializer(
private fun deserializeAnnotations(proto: ProtoDeclarationBase): Set<AbiQualifiedName> { private fun deserializeAnnotations(proto: ProtoDeclarationBase): Set<AbiQualifiedName> {
fun deserialize(annotation: ProtoConstructorCall): AbiQualifiedName { fun deserialize(annotation: ProtoConstructorCall): AbiQualifiedName {
val signature = deserializeIdSignature(annotation.symbol) val idSignature = deserializeIdSignature(annotation.symbol)
val annotationClassName = when { val annotationClassName = when {
signature is CommonSignature -> signature idSignature is CommonSignature -> idSignature
signature is CompositeSignature && signature.container is FileSignature -> signature.inner as CommonSignature idSignature is CompositeSignature && idSignature.container is FileSignature -> idSignature.inner as CommonSignature
else -> error("Unexpected annotation signature encountered: ${signature::class.java}, ${signature.render()}") else -> error("Unexpected annotation signature encountered: ${idSignature::class.java}, ${idSignature.render()}")
}.extractQualifiedName { rawRelativeName -> }.extractQualifiedName { rawRelativeName ->
check(rawRelativeName.endsWith(INIT_SUFFIX)) { check(rawRelativeName.endsWith(INIT_SUFFIX)) {
"Annotation constructor name does not have '$INIT_SUFFIX' suffix: $rawRelativeName" "Annotation constructor name does not have '$INIT_SUFFIX' suffix: $rawRelativeName"
@@ -469,11 +506,6 @@ private class LibraryDeserializer(
else -> VisibilityStatus.NON_PUBLIC else -> VisibilityStatus.NON_PUBLIC
} }
private fun deserializeIdSignature(symbolId: Long): IdSignature {
val signatureId = BinarySymbolData.decode(symbolId).signatureId
return signatureDeserializer.deserializeIdSignature(signatureId)
}
private fun deserializeValueParameter( private fun deserializeValueParameter(
proto: ProtoValueParameter, proto: ProtoValueParameter,
typeParameterResolver: TypeParameterResolver typeParameterResolver: TypeParameterResolver
@@ -497,13 +529,23 @@ private class LibraryDeserializer(
override fun computeNestedName(simpleName: String) = qualifiedName(packageName, simpleName) override fun computeNestedName(simpleName: String) = qualifiedName(packageName, simpleName)
} }
class Class(val className: AbiQualifiedName, val modality: AbiModality) : ContainingEntity { class Class(
val className: AbiQualifiedName,
val modality: AbiModality,
lazyExcludeFakeOverrides: () -> Boolean
) : ContainingEntity {
private val excludeFakeOverrides: Boolean by lazy(LazyThreadSafetyMode.NONE, lazyExcludeFakeOverrides)
override fun computeNestedName(simpleName: String) = qualifiedName(className, simpleName) override fun computeNestedName(simpleName: String) = qualifiedName(className, simpleName)
companion object {
val Class?.excludeFakeOverrides: Boolean get() = this?.excludeFakeOverrides ?: false
}
} }
class Property( class Property(
val propertyName: AbiQualifiedName, val propertyName: AbiQualifiedName,
val containingClassModality: AbiModality?, val containingClass: Class?,
val propertyVisibilityStatus: VisibilityStatus val propertyVisibilityStatus: VisibilityStatus
) : ContainingEntity { ) : ContainingEntity {
override fun computeNestedName(simpleName: String) = qualifiedName(propertyName, simpleName) override fun computeNestedName(simpleName: String) = qualifiedName(propertyName, simpleName)
@@ -588,7 +630,7 @@ private class LibraryDeserializer(
ProtoType.KindCase.LEGACYSIMPLE -> deserializeSimpleType(proto.legacySimple, typeParameterResolver) ProtoType.KindCase.LEGACYSIMPLE -> deserializeSimpleType(proto.legacySimple, typeParameterResolver)
ProtoType.KindCase.DYNAMIC -> DynamicTypeImpl ProtoType.KindCase.DYNAMIC -> DynamicTypeImpl
ProtoType.KindCase.ERROR -> ErrorTypeImpl ProtoType.KindCase.ERROR -> ErrorTypeImpl
ProtoType.KindCase.KIND_NOT_SET -> error("Unexpected IR type: $kindCase") ProtoType.KindCase.KIND_NOT_SET, null -> error("Unexpected IR type: $kindCase")
} }
} }
} }
@@ -600,9 +642,7 @@ private class LibraryDeserializer(
proto: ProtoIrDefinitelyNotNullType, proto: ProtoIrDefinitelyNotNullType,
typeParameterResolver: TypeParameterResolver, typeParameterResolver: TypeParameterResolver,
): AbiType { ): AbiType {
assert(proto.typesCount == 1) { "Only DefinitelyNotNull type is now supported" } val underlyingType = deserializeType(proto.underlyingTypeId, typeParameterResolver)
val underlyingType = deserializeType(proto.getTypes(0), typeParameterResolver)
return if (underlyingType is AbiType.Simple && underlyingType.nullability != DEFINITELY_NOT_NULL) return if (underlyingType is AbiType.Simple && underlyingType.nullability != DEFINITELY_NOT_NULL)
SimpleTypeImpl(underlyingType.classifierReference, underlyingType.arguments, DEFINITELY_NOT_NULL) SimpleTypeImpl(underlyingType.classifierReference, underlyingType.arguments, DEFINITELY_NOT_NULL)
else else
@@ -638,26 +678,26 @@ private class LibraryDeserializer(
typeParameterResolver: TypeParameterResolver typeParameterResolver: TypeParameterResolver
): AbiType.Simple { ): AbiType.Simple {
val symbolData = BinarySymbolData.decode(symbolId) val symbolData = BinarySymbolData.decode(symbolId)
val signature = signatureDeserializer.deserializeIdSignature(symbolData.signatureId) val idSignature = signatureDeserializer.deserializeIdSignature(symbolData.signatureId)
val symbolKind = symbolData.kind val symbolKind = symbolData.kind
return when { return when {
symbolKind == CLASS_SYMBOL && signature is CommonSignature -> { symbolKind == CLASS_SYMBOL && idSignature is CommonSignature -> {
// Publicly visible class or interface. // Publicly visible class or interface.
SimpleTypeImpl( SimpleTypeImpl(
classifierReference = ClassReferenceImpl( classifierReference = ClassReferenceImpl(
className = signature.extractQualifiedName() className = idSignature.extractQualifiedName()
), ),
arguments = deserializeTypeArguments(typeArgumentIds, typeParameterResolver), arguments = deserializeTypeArguments(typeArgumentIds, typeParameterResolver),
nullability = nullability nullability = nullability
) )
} }
symbolKind == CLASS_SYMBOL && signature is CompositeSignature && signature.container is FileSignature -> { symbolKind == CLASS_SYMBOL && idSignature is CompositeSignature && idSignature.container is FileSignature -> {
// Non-publicly visible classifier. Practically, this can only be a private top-level interface // Non-publicly visible classifier. Practically, this can only be a private top-level interface
// that some publicly visible class inherits. Need to memoize it to avoid displaying it later among // that some publicly visible class inherits. Need to memoize it to avoid displaying it later among
// supertypes of the inherited class. // supertypes of the inherited class.
val className = (signature.inner as CommonSignature).extractQualifiedName() val className = (idSignature.inner as CommonSignature).extractQualifiedName()
nonPublicTopLevelClassNames += className nonPublicTopLevelClassNames += className
SimpleTypeImpl( SimpleTypeImpl(
@@ -667,13 +707,13 @@ private class LibraryDeserializer(
) )
} }
symbolKind == TYPE_PARAMETER_SYMBOL && signature is CompositeSignature -> { symbolKind == TYPE_PARAMETER_SYMBOL && idSignature is CompositeSignature -> {
// A type-parameter. // A type-parameter.
SimpleTypeImpl( SimpleTypeImpl(
classifierReference = TypeParameterReferenceImpl( classifierReference = TypeParameterReferenceImpl(
tag = typeParameterResolver.resolveTypeParameterTag( tag = typeParameterResolver.resolveTypeParameterTag(
declarationName = (signature.container as CommonSignature).extractQualifiedName(), declarationName = (idSignature.container as CommonSignature).extractQualifiedName(),
index = (signature.inner as LocalSignature).index() index = (idSignature.inner as LocalSignature).index()
) )
), ),
arguments = emptyList(), arguments = emptyList(),
@@ -681,7 +721,7 @@ private class LibraryDeserializer(
) )
} }
else -> error("Unexpected combination of symbol kind ($symbolKind) and a signature: ${signature::class.java}, ${signature.render()}") else -> error("Unexpected combination of symbol kind ($symbolKind) and a signature: ${idSignature::class.java}, ${idSignature.render()}")
} }
} }
@@ -702,6 +742,11 @@ private class LibraryDeserializer(
) )
} }
} }
companion object {
val ProtoIrDefinitelyNotNullType.underlyingTypeId: Int
get() = typesList.singleOrNull() ?: error("Only DefinitelyNotNull type is now supported")
}
} }
fun deserialize(): AbiTopLevelDeclarations { fun deserialize(): AbiTopLevelDeclarations {