Repository: JetBrains/kotlin
File: kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportNamer.kt (Kotlin)

Code before:

private fun StringBuilder.mangledBySuffixUnderscores() = this.mangledSequence { append("_") }

private fun ObjCExportMapper.getClassDescriptor(member: CallableMemberDescriptor) = getClassIfCategory(member) ?: member.containingDeclaration as? ClassDescriptor

private fun ObjCExportMapper.inSameClassHierarchy(first: CallableMemberDescriptor, second: CallableMemberDescriptor): Boolean {
    if (this.isTopLevel(first) || this.isTopLevel(second)) {
        return this.isTopLevel(first) && this.isTopLevel(second) &&
                first.propertyIfAccessor.findSourceFile() == second.propertyIfAccessor.findSourceFile()
    }

    val firstClass = getClassDescriptor(first) ?: return false
    val secondClass = getClassDescriptor(second) ?: return false

    if (first is ConstructorDescriptor) {
        return firstClass == secondClass || second !is ConstructorDescriptor && firstClass.isSubclassOf(secondClass)
    }

    if (second is ConstructorDescriptor) {
        return secondClass == firstClass || first !is ConstructorDescriptor && secondClass.isSubclassOf(firstClass)
    }

    return firstClass.isSubclassOf(secondClass) || secondClass.isSubclassOf(firstClass)
}

private fun ObjCExportMapper.canHaveCommonSubtype(first: CallableMemberDescriptor, second: CallableMemberDescriptor, ignoreInterfaceMethodCollisions: Boolean): Boolean {
    val firstClass = getClassDescriptor(first) ?: return false
    val secondClass = getClassDescriptor(second) ?: return false

    if (firstClass.isFinalClass || secondClass.isFinalClass) {
        return false
    }

    return (firstClass.isInterface || secondClass.isInterface) && !ignoreInterfaceMethodCollisions
}

private fun ObjCExportMapper.canBeInheritedBySameClass(
        first: CallableMemberDescriptor,
        second: CallableMemberDescriptor,
        ignoreInterfaceMethodCollisions: Boolean
): Boolean = inSameClassHierarchy(first, second) || canHaveCommonSubtype(first, second, ignoreInterfaceMethodCollisions)

private fun ObjCExportMapper.canHaveSameSelector(first: FunctionDescriptor, second: FunctionDescriptor, ignoreInterfaceMethodCollisions: Boolean): Boolean {
    assert(isBaseMethod(first))
    assert(isBaseMethod(second))

    if (!canBeInheritedBySameClass(first, second, ignoreInterfaceMethodCollisions)) {
        return true
    }

    if (first.dispatchReceiverParameter == null || second.dispatchReceiverParameter == null) {

Review comment (bug):
It is not clear to me why extracting this method was necessary.
In particular, the refactoring makes it harder to verify that, in the absence of the flag, this PR doesn't alter the behavior.

What was wrong with simply adding a condition here? https://github.com/JetBrains/kotlin/blob/e2640b4afac5b4e6e2eb4aa17165593a764cb715/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportNamer.kt#L885

Code after:
            this@mangledSequence.mangle()
            this@mangledSequence.toString()
        }

private fun StringBuilder.mangledBySuffixUnderscores() = this.mangledSequence { append("_") }

private fun ObjCExportMapper.canHaveCommonSubtype(first: ClassDescriptor, second: ClassDescriptor, ignoreInterfaceMethodCollisions: Boolean): Boolean {
    if (first.isSubclassOf(second) || second.isSubclassOf(first)) {
        return true
    }

    if (first.isFinalClass || second.isFinalClass) {
        return false
    }

    return (first.isInterface || second.isInterface) && !ignoreInterfaceMethodCollisions
}

private fun ObjCExportMapper.canBeInheritedBySameClass(
        first: CallableMemberDescriptor,
        second: CallableMemberDescriptor,
        ignoreInterfaceMethodCollisions: Boolean
): Boolean {
    if (this.isTopLevel(first) || this.isTopLevel(second)) {
        return this.isTopLevel(first) && this.isTopLevel(second) &&
                first.propertyIfAccessor.findSourceFile() == second.propertyIfAccessor.findSourceFile()
    }

    val firstClass = this.getClassIfCategory(first) ?: first.containingDeclaration as ClassDescriptor
    val secondClass = this.getClassIfCategory(second) ?: second.containingDeclaration as ClassDescriptor

    if (first is ConstructorDescriptor) {
        return firstClass == secondClass || second !is ConstructorDescriptor && firstClass.isSubclassOf(secondClass)
    }

    if (second is ConstructorDescriptor) {
        return secondClass == firstClass || first !is ConstructorDescriptor && secondClass.isSubclassOf(firstClass)
    }

    return canHaveCommonSubtype(firstClass, secondClass, ignoreInterfaceMethodCollisions)
}

private fun ObjCExportMapper.canHaveSameSelector(first: FunctionDescriptor, second: FunctionDescriptor, ignoreInterfaceMethodCollisions: Boolean): Boolean {
    assert(isBaseMethod(first))
    assert(isBaseMethod(second))

    if (!canBeInheritedBySameClass(first, second, ignoreInterfaceMethodCollisions)) {
        return true
    }

    if (first.dispatchReceiverParameter == null || second.dispatchReceiverParameter == null) {