Improve detection of Objective-C designated initializers
This commit is contained in:
committed by
SvyatoslavScherbina
parent
5184343058
commit
515457fea0
+25
-3
@@ -323,11 +323,33 @@ private val ObjCClassOrProtocol.superTypes: Sequence<ObjCClassOrProtocol>
|
|||||||
private fun ObjCClassOrProtocol.declaredMethods(isClass: Boolean): Sequence<ObjCMethod> =
|
private fun ObjCClassOrProtocol.declaredMethods(isClass: Boolean): Sequence<ObjCMethod> =
|
||||||
this.methods.asSequence().filter { it.isClass == isClass }
|
this.methods.asSequence().filter { it.isClass == isClass }
|
||||||
|
|
||||||
|
private fun Sequence<ObjCMethod>.inheritedTo(container: ObjCClassOrProtocol, isMeta: Boolean): Sequence<ObjCMethod> {
|
||||||
|
// Note: Objective-C initializers act as usual methods and thus are inherited by subclasses.
|
||||||
|
// Swift considers all super initializers to be available (unless otherwise specified explicitly),
|
||||||
|
// but seems to consider them as non-designated if class declares its own ones.
|
||||||
|
// Simulate the similar behaviour:
|
||||||
|
return if (!isMeta && container.declaredMethods(isMeta).any { it.isDesginatedInitializer }) {
|
||||||
|
this.map {
|
||||||
|
if (it.isDesginatedInitializer) {
|
||||||
|
it.copy(isDesginatedInitializer = false)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: exclude methods that are marked as unavailable in [container].
|
||||||
|
}
|
||||||
|
|
||||||
private fun ObjCClassOrProtocol.inheritedMethods(isClass: Boolean): Sequence<ObjCMethod> =
|
private fun ObjCClassOrProtocol.inheritedMethods(isClass: Boolean): Sequence<ObjCMethod> =
|
||||||
this.superTypes.flatMap { it.declaredMethods(isClass) }.distinctBy { it.selector }
|
this.immediateSuperTypes.flatMap { it.methodsWithInherited(isClass) }
|
||||||
|
.distinctBy { it.selector }
|
||||||
|
.inheritedTo(this, isClass)
|
||||||
|
|
||||||
private fun ObjCClassOrProtocol.methodsWithInherited(isClass: Boolean): Sequence<ObjCMethod> =
|
private fun ObjCClassOrProtocol.methodsWithInherited(isClass: Boolean): Sequence<ObjCMethod> =
|
||||||
this.selfAndSuperTypes.flatMap { it.declaredMethods(isClass) }.distinctBy { it.selector }
|
(this.declaredMethods(isClass) + this.inheritedMethods(isClass)).distinctBy { it.selector }
|
||||||
|
|
||||||
private fun ObjCMethod.isOverride(container: ObjCClassOrProtocol): Boolean =
|
private fun ObjCMethod.isOverride(container: ObjCClassOrProtocol): Boolean =
|
||||||
container.superTypes.any { superType -> superType.methods.any(this::replaces) }
|
container.superTypes.any { superType -> superType.methods.any(this::replaces) }
|
||||||
@@ -364,7 +386,7 @@ abstract class ObjCContainerStub(stubGenerator: StubGenerator,
|
|||||||
// Add methods inherited from multiple supertypes that must be defined according to Kotlin rules:
|
// Add methods inherited from multiple supertypes that must be defined according to Kotlin rules:
|
||||||
methods += container.immediateSuperTypes
|
methods += container.immediateSuperTypes
|
||||||
.flatMap { superType ->
|
.flatMap { superType ->
|
||||||
val methodsWithInherited = superType.methodsWithInherited(isMeta)
|
val methodsWithInherited = superType.methodsWithInherited(isMeta).inheritedTo(container, isMeta)
|
||||||
// Select only those which are represented as non-abstract in Kotlin:
|
// Select only those which are represented as non-abstract in Kotlin:
|
||||||
when (superType) {
|
when (superType) {
|
||||||
is ObjCClass -> methodsWithInherited
|
is ObjCClass -> methodsWithInherited
|
||||||
|
|||||||
Reference in New Issue
Block a user