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 43be0772a28..63d3fc9bf2d 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 @@ -325,7 +325,17 @@ private fun Type.hasUnalignedMembers(): Boolean = when (this) { // TODO: should the recursive checks be made in indexer when computing `hasUnalignedFields`? } -private val ObjCMethod.kotlinName: String get() = selector.split(":").first() +private val ObjCMethod.kotlinName: String + get() { + val candidate = selector.split(":").first() + val trimmed = candidate.trimEnd('_') + return if (trimmed == "equals" && parameters.size == 1 + || (trimmed == "hashCode" || trimmed == "toString") && parameters.size == 0) { + candidate + "_" + } else { + candidate + } + } private val ObjCClassOrProtocol.protocolsWithSupers: Sequence get() = this.protocols.asSequence().flatMap { sequenceOf(it) + it.protocolsWithSupers } diff --git a/backend.native/tests/interop/objc/smoke.h b/backend.native/tests/interop/objc/smoke.h index 6ef3c8a45d2..fcdb43ea957 100644 --- a/backend.native/tests/interop/objc/smoke.h +++ b/backend.native/tests/interop/objc/smoke.h @@ -185,3 +185,23 @@ NSObject* createNSObject() { @interface MultipleInheritanceClash2 : MultipleInheritanceClashBase @property MultipleInheritanceClashBase* delegate; @end; + +@interface TestClashingWithAny1 : NSObject +-(NSString*)toString; +-(NSString*)toString_; +-(int)hashCode; +-(BOOL)equals:(id _Nullable)other; +@end; + +@interface TestClashingWithAny2 : NSObject +-(void)toString; +-(void)hashCode; +-(void)equals:(int)p; // May clash. +@end; + +@interface TestClashingWithAny3 : NSObject +// Not clashing actually. +-(NSString*)toString:(int)p; +-(int)hashCode:(int)p; +-(BOOL)equals; +@end; diff --git a/backend.native/tests/interop/objc/smoke.kt b/backend.native/tests/interop/objc/smoke.kt index a069e1da462..1d3c2b67024 100644 --- a/backend.native/tests/interop/objc/smoke.kt +++ b/backend.native/tests/interop/objc/smoke.kt @@ -24,6 +24,7 @@ fun run() { testVarargs() testOverrideInit() testMultipleInheritanceClash() + testClashingWithAny() assertEquals(2, ForwardDeclaredEnum.TWO.value) @@ -334,6 +335,30 @@ fun testMultipleInheritanceClash() { assertEquals(clash2, clash2.delegate()) } +fun testClashingWithAny() { + assertEquals("description", TestClashingWithAny1().toString()) + assertEquals("toString", TestClashingWithAny1().toString_()) + assertEquals("toString_", TestClashingWithAny1().toString__()) + assertEquals(1, TestClashingWithAny1().hashCode()) + assertEquals(31, TestClashingWithAny1().hashCode_()) + assertFalse(TestClashingWithAny1().equals(TestClashingWithAny1())) + assertTrue(TestClashingWithAny1().equals_(TestClashingWithAny1())) + + assertEquals("description", TestClashingWithAny2().toString()) + assertEquals(Unit, TestClashingWithAny2().toString_()) + assertEquals(2, TestClashingWithAny2().hashCode()) + assertEquals(Unit, TestClashingWithAny2().hashCode_()) + assertFalse(TestClashingWithAny2().equals(TestClashingWithAny2())) + assertEquals(Unit, TestClashingWithAny2().equals_(42)) + + assertEquals("description", TestClashingWithAny3().toString()) + assertEquals("toString:11", TestClashingWithAny3().toString(11)) + assertEquals(3, TestClashingWithAny3().hashCode()) + assertEquals(4, TestClashingWithAny3().hashCode(3)) + assertFalse(TestClashingWithAny3().equals(TestClashingWithAny3())) + assertTrue(TestClashingWithAny3().equals()) +} + fun nsArrayOf(vararg elements: Any): NSArray = NSMutableArray().apply { elements.forEach { this.addObject(it as ObjCObject) diff --git a/backend.native/tests/interop/objc/smoke.m b/backend.native/tests/interop/objc/smoke.m index 4f5479ee6f2..5485ba105bf 100644 --- a/backend.native/tests/interop/objc/smoke.m +++ b/backend.native/tests/interop/objc/smoke.m @@ -187,3 +187,70 @@ static CustomRetainMethodsImpl* retainedCustomRetainMethodsImpl; @implementation MultipleInheritanceClash2 @end; + +@implementation TestClashingWithAny1 +-(NSString*)description { + return @"description"; +} + +-(NSString*)toString { + return @"toString"; +} + +-(NSString*)toString_ { + return @"toString_"; +} + +-(NSUInteger)hash { + return 1; +} + +-(int)hashCode { + return 31; +} + +-(BOOL)equals:(id _Nullable)other { + return YES; +} +@end; + +@implementation TestClashingWithAny2 +-(NSString*)description { + return @"description"; +} + +-(void)toString { +} + +-(NSUInteger)hash { + return 2; +} + +-(void)hashCode { +} + +-(void)equals:(int)p { +} +@end; + +@implementation TestClashingWithAny3 +-(NSString*)description { + return @"description"; +} + +-(NSString*)toString:(int)p { + return [NSString stringWithFormat:@"%s:%d", "toString", p]; +} + +-(NSUInteger)hash { + return 3; +} + +-(int)hashCode:(int)p { + return p + 1; +} + +-(BOOL)equals { + return YES; +} +@end;