From 2865d8bd45294ebadd5c640b7dbb24574a10420c Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Mon, 28 Jun 2021 17:40:12 +0300 Subject: [PATCH] Deprecate Obj-C 'alloc' and 'allocWithZone:' methods in Kotlin Using these methods in Kotlin is usually a mistake. --- .../kotlin/native/interop/gen/ObjCStubs.kt | 18 ++++++++++++++++++ .../kotlin/native/interop/gen/StubIr.kt | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt index 668b1f8e5a1..f0a0570b26f 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt @@ -148,7 +148,22 @@ private class ObjCMethodStubBuilder( fun isDefaultConstructor(): Boolean = method.isInit && method.parameters.isEmpty() + private fun deprecateObjCAlloc() { + // Motivation: 'alloc' and 'allocWithZone:' Obj-C methods were never intended to be directly accessible + // in Kotlin. + // Using these methods in Kotlin is error-prone: init methods are not accessible, + // so a call to alloc method is likely not followed by a call to an init method, + // which is usually a mistake. + // Swift also doesn't allow calling Obj-C alloc methods. + // Removing them gracefully, via the deprecation cycle: + if (method.isAlloc()) { + annotations += AnnotationStub.Deprecated.deprecatedObjCAlloc + } + } + override fun build(): List { + deprecateObjCAlloc() + val replacement = if (method.isInit) { val parameters = method.getKotlinParameters(context, forConstructorOrFactory = true) when (container) { @@ -243,6 +258,9 @@ private fun deprecatedInit(className: String, initParameterNames: List, return AnnotationStub.Deprecated("Use $replacementKind instead", replaceWith, DeprecationLevel.ERROR) } +private fun ObjCMethod.isAlloc(): Boolean = + this.isClass && (this.selector == "alloc" || this.selector == "allocWithZone:") + internal val ObjCMethod.kotlinName: String get() { val candidate = selector.split(":").first() diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt index 3d5af9d9d6e..a871c7c5e45 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt @@ -238,6 +238,12 @@ sealed class AnnotationStub(val classifier: Classifier) { "", DeprecationLevel.WARNING ) + + val deprecatedObjCAlloc = Deprecated( + "Use constructor or factory method instead", + "", + DeprecationLevel.WARNING + ) } }