[K/N] KT-56464: implementation of HiddenFromObjC for classes in backend

This commit is contained in:
Sergey Bogolepov
2023-04-25 18:05:40 +03:00
committed by Space Team
parent 6651e6ed8c
commit fce878d63a
10 changed files with 54 additions and 17 deletions
@@ -596,9 +596,36 @@ private class BackendChecker(
if (declaration.isKotlinObjCClass()) {
checkKotlinObjCClass(declaration)
}
checkHiddenFromObjCRestrictions(declaration)
super.visitClass(declaration)
}
private fun IrClass.isHiddenFromObjC(): Boolean {
return annotations.any { annotationCall ->
val annotationClass = annotationCall.symbol.owner.parentAsClass
annotationClass.annotations.hasAnnotation(KonanFqNames.hidesFromObjC)
}
}
private fun checkHiddenFromObjCRestrictions(declaration: IrClass) {
// If declaration itself. is marked as hidden, we don't need to do anything
if (declaration.isHiddenFromObjC()) return
// Enum entries inherit from their classes, so if enum class is marked as hidden, there is no need to
// produce additional errors.
if (declaration.kind == ClassKind.ENUM_ENTRY) return
// Private and local classes does not leak to Objective-C API surface, so it is OK for them
// to inherit from hidden types.
if (DescriptorVisibilities.isPrivate(declaration.visibility) || declaration.isLocal) return
if (declaration.superClass?.isHiddenFromObjC() == true) {
reportError(declaration, "Only @HiddenFromObjC declaration can inherit from class annotated with @HiddenFromObjC")
}
declaration.getSuperInterfaces().forEach {
if (it.isHiddenFromObjC()) {
reportError(declaration, "Only @HiddenFromObjC declaration can implement interface annotated with @HiddenFromObjC")
}
}
}
}
private fun BackendChecker.checkCanGenerateCCall(expression: IrCall, isInvoke: Boolean) {
@@ -108,6 +108,16 @@ private fun CallableMemberDescriptor.isHiddenFromObjC(): Boolean = when {
}
}
/**
* Check if the given class or its enclosing declaration is marked as @HiddenFromObjC.
*/
internal fun ClassDescriptor.isHiddenFromObjC(): Boolean = when {
(this.containingDeclaration as? ClassDescriptor)?.isHiddenFromObjC() == true -> true
else -> annotations.any { annotation ->
annotation.annotationClass?.annotations?.any { it.fqName == KonanFqNames.hidesFromObjC } == true
}
}
internal fun ObjCExportMapper.shouldBeExposed(descriptor: ClassDescriptor): Boolean =
shouldBeVisible(descriptor) && !isSpecialMapped(descriptor) && !descriptor.defaultType.isObjCObjectType()
@@ -175,7 +185,7 @@ internal fun ObjCExportMapper.shouldBeVisible(descriptor: ClassDescriptor): Bool
descriptor.isEffectivelyPublicApi && when (descriptor.kind) {
ClassKind.CLASS, ClassKind.INTERFACE, ClassKind.ENUM_CLASS, ClassKind.OBJECT -> true
ClassKind.ENUM_ENTRY, ClassKind.ANNOTATION_CLASS -> false
} && !descriptor.isExpect && !descriptor.isInlined() && !isHiddenByDeprecation(descriptor)
} && !descriptor.isExpect && !descriptor.isInlined() && !isHiddenByDeprecation(descriptor) && !descriptor.isHiddenFromObjC()
private fun ObjCExportMapper.isBase(descriptor: CallableMemberDescriptor): Boolean =
descriptor.overriddenDescriptors.all { !shouldBeExposed(it) }