diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt index 4cf9b601c57..07e672b9295 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt @@ -842,7 +842,7 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() { nsReturnsRetained = hasAttribute(cursor, NS_RETURNS_RETAINED), isOptional = (clang_Cursor_isObjCOptional(cursor) != 0), isInit = (clang_Cursor_isObjCInitMethod(cursor) != 0), - isDesginatedInitializer = hasAttribute(cursor, OBJC_DESGINATED_INITIALIZER) + isExplicitlyDesignatedInitializer = hasAttribute(cursor, OBJC_DESGINATED_INITIALIZER) ) } diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt index b42eba077d6..ee491635ec9 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt @@ -143,7 +143,7 @@ sealed class ObjCClassOrProtocol(val name: String) : ObjCContainer(), TypeDeclar data class ObjCMethod( val selector: String, val encoding: String, val parameters: List, private val returnType: Type, val isClass: Boolean, val nsConsumesSelf: Boolean, val nsReturnsRetained: Boolean, - val isOptional: Boolean, val isInit: Boolean, val isDesginatedInitializer: Boolean + val isOptional: Boolean, val isInit: Boolean, val isExplicitlyDesignatedInitializer: Boolean ) { fun returnsInstancetype(): Boolean = returnType is ObjCInstanceType diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt index cf48de819e7..f70d055badb 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt @@ -67,7 +67,8 @@ private fun ObjCMethod.getFirstKotlinParameterNameCandidate(forConstructorOrFact class ObjCMethodStub(private val stubGenerator: StubGenerator, val method: ObjCMethod, - private val container: ObjCContainer) : KotlinStub, NativeBacked { + private val container: ObjCContainer, + private val isDesignatedInitializer: Boolean) : KotlinStub, NativeBacked { override fun generate(context: StubGenerationContext): Sequence = if (context.nativeBridges.isSupported(this)) { @@ -86,7 +87,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator, when (container) { is ObjCClass -> { // TODO: consider generating non-designated initializers as factories. - val designated = method.isDesginatedInitializer || + val designated = isDesignatedInitializer || stubGenerator.configuration.disableDesignatedInitializerChecks result.add("") @@ -364,25 +365,8 @@ private val ObjCClassOrProtocol.superTypes: Sequence private fun ObjCClassOrProtocol.declaredMethods(isClass: Boolean): Sequence = this.methods.asSequence().filter { it.isClass == isClass } -private fun Sequence.inheritedTo(container: ObjCClassOrProtocol, isMeta: Boolean): Sequence { - // 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 Sequence.inheritedTo(container: ObjCClassOrProtocol, isMeta: Boolean): Sequence = + this // TODO: exclude methods that are marked as unavailable in [container]. private fun ObjCClassOrProtocol.inheritedMethods(isClass: Boolean): Sequence = this.immediateSuperTypes.flatMap { it.methodsWithInherited(isClass) } @@ -392,6 +376,27 @@ private fun ObjCClassOrProtocol.inheritedMethods(isClass: Boolean): Sequence = (this.declaredMethods(isClass) + this.inheritedMethods(isClass)).distinctBy { it.selector } +private fun ObjCClass.getDesignatedInitializerSelectors(result: MutableSet): Set { + // 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 explicitly. + // Simulate the similar behaviour: + val explicitlyDesignatedInitializers = this.methods.filter { it.isExplicitlyDesignatedInitializer && !it.isClass } + + if (explicitlyDesignatedInitializers.isNotEmpty()) { + explicitlyDesignatedInitializers.mapTo(result) { it.selector } + } else { + this.declaredMethods(isClass = false).filter { it.isInit }.mapTo(result) { it.selector } + this.baseClass?.getDesignatedInitializerSelectors(result) + } + + this.superTypes.filterIsInstance() + .flatMap { it.declaredMethods(isClass = false) }.filter { it.isInit } + .mapTo(result) { it.selector } + + return result +} + private fun ObjCMethod.isOverride(container: ObjCClassOrProtocol): Boolean = container.superTypes.any { superType -> superType.methods.any(this::replaces) } @@ -446,8 +451,17 @@ abstract class ObjCContainerStub(stubGenerator: StubGenerator, } } + private val designatedInitializerSelectors = if (container is ObjCClass && !isMeta) { + container.getDesignatedInitializerSelectors(mutableSetOf()) + } else { + emptySet() + } + private val methodToStub = methods.map { - it to ObjCMethodStub(stubGenerator, it, container) + it to ObjCMethodStub( + stubGenerator, it, container, + isDesignatedInitializer = it.selector in designatedInitializerSelectors + ) }.toMap() private val methodStubs get() = methodToStub.values @@ -568,7 +582,7 @@ class ObjCCategoryStub( // TODO: consider removing members that are also present in the class or its supertypes. private val methodToStub = category.methods.map { - it to ObjCMethodStub(stubGenerator, it, category) + it to ObjCMethodStub(stubGenerator, it, category, isDesignatedInitializer = false) }.toMap() private val methodStubs get() = methodToStub.values