Skip to content

Commit 415c5c1

Browse files
authored
Merge pull request #41905 from cabmeurer/cabmeurer/add-snake_case-to-CXXMethodBridging
[cxx-interop] Add snake_case to CXXMethodBridging
2 parents e9f7e8d + 7d50071 commit 415c5c1

File tree

6 files changed

+92
-12
lines changed

6 files changed

+92
-12
lines changed

include/swift/ClangImporter/CXXMethodBridging.h

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ struct CXXMethodBridging {
1818
if (nameIsBlacklist())
1919
return Kind::unknown;
2020

21-
// this should be handled as snake case. See: rdar://89453010
21+
// This should be handled as snake case. See: rdar://89453010
2222
// case. In the future we could
2323
// import these too, though.
2424
auto nameKind = classifyNameKind();
2525
if (nameKind != NameKind::title && nameKind != NameKind::camel &&
26-
nameKind != NameKind::lower)
26+
nameKind != NameKind::lower && nameKind != NameKind::snake)
2727
return Kind::unknown;
2828

2929
if (getClangName().startswith_insensitive("set")) {
@@ -62,16 +62,18 @@ struct CXXMethodBridging {
6262
}
6363

6464
NameKind classifyNameKind() {
65-
bool allLower = llvm::all_of(getClangName(), islower);
65+
bool hasUpper = llvm::any_of(
66+
getClangName(), [](unsigned char ch) { return std::isupper(ch); });
6667

67-
if (getClangName().empty())
68+
if (getClangName().empty()) {
6869
return NameKind::unknown;
70+
}
6971

70-
if (getClangName().contains('_'))
71-
return allLower ? NameKind::snake : NameKind::unknown;
72-
73-
if (allLower)
72+
if (getClangName().contains('_')) {
73+
return hasUpper ? NameKind::unknown : NameKind::snake;
74+
} else if (!hasUpper) {
7475
return NameKind::lower;
76+
}
7577

7678
return islower(getClangName().front()) ? NameKind::camel : NameKind::title;
7779
}
@@ -83,7 +85,7 @@ struct CXXMethodBridging {
8385
return method->getName();
8486
}
8587

86-
// this should be handled as snake case. See: rdar://89453010
88+
// This should be handled as snake case. See: rdar://89453010
8789
std::string importNameAsCamelCaseName() {
8890
std::string output;
8991
auto kind = classify();
@@ -103,6 +105,24 @@ struct CXXMethodBridging {
103105
// The first character is always lowercase.
104106
output.front() = std::tolower(output.front());
105107

108+
if (classifyNameKind() == NameKind::snake) {
109+
for (std::size_t i = 0; i < output.size(); i++) {
110+
size_t next = i + 1;
111+
if (output[i] == '_') {
112+
// If the first or last element is an underscore, remove it.
113+
if (i == 0 || next == output.size()) {
114+
output.erase(i, 1);
115+
} else if (next < output.size()) {
116+
// If the current element is an underscore, capitalize the element
117+
// next to it, and remove the extra element.
118+
output[i] = std::toupper(output[next]);
119+
output.erase(next, 1);
120+
}
121+
}
122+
}
123+
return output;
124+
}
125+
106126
// We already lowercased the first element, so start at one. Look at the
107127
// current element and the next one. To handle cases like UTF8String, start
108128
// making all the uppercase characters lower, until we see an upper case

test/Interop/Cxx/ergonomics/Inputs/implicit-computed-properties.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,22 @@ class PrivatePropertyWithSameName {
191191
void setValue(int i);
192192
};
193193

194+
struct SnakeCaseGetterSetter {
195+
int value = 42;
196+
int get_foo() const { return value; };
197+
void set_foo(int v) { value = v; };
198+
};
199+
200+
struct SnakeCaseUTF8Str {
201+
int value = 42;
202+
int get_utf8_string() const { return value; };
203+
void set_utf8_string(int v) { value = v; };
204+
};
205+
206+
struct SnakeCaseTrailing {
207+
int value = 42;
208+
int get_x_() const { return value; };
209+
void set_x_(int v) { value = v; } ;
210+
};
211+
194212
#endif // SWIFT_IMPLICIT_COMPUTED_PROPERTIES_H

test/Interop/Cxx/ergonomics/implicit-computed-properties-module-interface.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
// CHECK: struct IntGetterSetterSnakeCase {
112112
// CHECK-NEXT: init()
113113
// CHECK-NEXT: init(val: Int32)
114+
// CHECK-NEXT: var x: Int32
114115
// CHECK-NEXT: func get_x() -> Int32
115116
// CHECK-NEXT: mutating func set_x(_ v: Int32)
116117
// CHECK-NEXT: var val: Int32
@@ -266,3 +267,30 @@
266267
// CHECK-NEXT: func getValue() -> Int32
267268
// CHECK-NEXT: mutating func setValue(_ i: Int32)
268269
// CHECK-NEXT: }
270+
271+
// CHECK: struct SnakeCaseGetterSetter {
272+
// CHECK-NEXT: init()
273+
// CHECK-NEXT: init(value: Int32)
274+
// CHECK-NEXT: var foo: Int32
275+
// CHECK-NEXT: func get_foo() -> Int32
276+
// CHECK-NEXT: mutating func set_foo(_ v: Int32)
277+
// CHECK-NEXT: var value: Int32
278+
// CHECK-NEXT: }
279+
280+
// CHECK: struct SnakeCaseUTF8Str {
281+
// CHECK-NEXT: init()
282+
// CHECK-NEXT: init(value: Int32)
283+
// CHECK-NEXT: var utf8String: Int32
284+
// CHECK-NEXT: func get_utf8_string() -> Int32
285+
// CHECK-NEXT: mutating func set_utf8_string(_ v: Int32)
286+
// CHECK-NEXT: var value: Int32
287+
// CHECK-NEXT: }
288+
289+
// CHECK: struct SnakeCaseTrailing {
290+
// CHECK-NEXT: init()
291+
// CHECK-NEXT: init(value: Int32)
292+
// CHECK-NEXT: var x: Int32
293+
// CHECK-NEXT: func get_x_() -> Int32
294+
// CHECK-NEXT: mutating func set_x_(_ v: Int32)
295+
// CHECK-NEXT: var value: Int32
296+
// CHECK-NEXT: }

test/Interop/Cxx/ergonomics/implicit-computed-properties.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ ImplicitComputedPropertiesTestSuite.test("UpperCaseMix") {
3232
}
3333

3434
ImplicitComputedPropertiesTestSuite.test("GetterOnly") {
35-
var d = GetterOnly()
35+
let d = GetterOnly()
3636
expectEqual(d.foo, 42)
3737
}
3838

@@ -79,4 +79,18 @@ ImplicitComputedPropertiesTestSuite.test("non trivial") {
7979
expectEqual(Object.x.value, 20)
8080
}
8181

82+
ImplicitComputedPropertiesTestSuite.test("SnakeCaseGetterSetter") {
83+
var object = SnakeCaseGetterSetter()
84+
expectEqual(object.foo, 42)
85+
object.foo = 32
86+
expectEqual(object.foo, 32)
87+
}
88+
89+
ImplicitComputedPropertiesTestSuite.test("SnakeCaseUTF8Str") {
90+
var object = SnakeCaseUTF8Str()
91+
expectEqual(object.utf8String, 42)
92+
object.utf8String = 32
93+
expectEqual(object.utf8String, 32)
94+
}
95+
8296
runAllTests()

test/SILOptimizer/array_element_propagation_ossa_nontrivial.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ bb0(%arg0 : @owned $MyKlass, %arg1 : @owned $MyKlass, %arg2 : @owned $MyKlass):
204204
return %52 : $()
205205
}
206206

207-
sil [ossa] @unkown_use : $@convention(thin) (@owned MyKlass) -> () {
207+
sil [ossa] @unknown_use : $@convention(thin) (@owned MyKlass) -> () {
208208
bb0(%arg0 : @owned $MyKlass):
209209
%0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned _ContiguousArrayStorage<MyKlass>
210210
%1 = integer_literal $Builtin.Word, 1

utils/build_swift/tests/build_swift/test_driver_arguments.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def test(self):
278278
[option.option_string])
279279
# The argument should never show up in the namespace
280280
self.assertFalse(hasattr(namespace, option.dest))
281-
# It should instead be forwareded to unkown_args
281+
# It should instead be forwareded to unknown_args
282282
self.assertEqual(unknown_args, [option.option_string])
283283

284284
return test

0 commit comments

Comments
 (0)