Skip to content

Commit 3d9d0a3

Browse files
committed
Allow nested names in @available(*, renamed:"..."). (#2722)
This can be used as QoI for things like 'NSASCIIStringEncoding', which is going to canonically be `String.Encoding.ascii` if/when SE-0086 is accepted. We can't actually handle this in NS_SWIFT_NAME (that is, we can't /import/ something onto a nested type), but that's okay: we already have stricter limitations on NS_SWIFT_NAME enforced by Clang. rdar://problem/26352374
1 parent a752b44 commit 3d9d0a3

File tree

5 files changed

+37
-9
lines changed

5 files changed

+37
-9
lines changed

lib/Parse/Parser.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -834,22 +834,34 @@ ParsedDeclName swift::parseDeclName(StringRef name) {
834834
auto parseBaseName = [&](StringRef text) -> bool {
835835
// Split the text into context name and base name.
836836
StringRef contextName, baseName;
837-
std::tie(contextName, baseName) = text.split('.');
837+
std::tie(contextName, baseName) = text.rsplit('.');
838838
if (baseName.empty()) {
839839
baseName = contextName;
840840
contextName = StringRef();
841841
} else if (contextName.empty()) {
842842
return true;
843843
}
844844

845+
auto isValidIdentifier = [](StringRef text) -> bool {
846+
return Lexer::isIdentifier(text) && text != "_";
847+
};
848+
845849
// Make sure we have an identifier for the base name.
846-
if (!Lexer::isIdentifier(baseName) || baseName == "_")
850+
if (!isValidIdentifier(baseName))
847851
return true;
848852

849-
// If we have a context, make sure it is an identifier.
850-
if (!contextName.empty() &&
851-
(!Lexer::isIdentifier(contextName) || contextName == "_"))
852-
return true;
853+
// If we have a context, make sure it is an identifier, or a series of
854+
// dot-separated identifiers.
855+
// FIXME: What about generic parameters?
856+
if (!contextName.empty()) {
857+
StringRef first;
858+
StringRef rest = contextName;
859+
do {
860+
std::tie(first, rest) = rest.split('.');
861+
if (!isValidIdentifier(first))
862+
return true;
863+
} while (!rest.empty());
864+
}
853865

854866
// Record the results.
855867
result.ContextName = contextName;

test/APINotes/Inputs/broken-modules/BrokenAPINotes.apinotes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ Functions:
1212
SwiftName: 'getter:ZXSpectrum.misnamedRegister(self:)'
1313
- Name: ZXSpectrumSetMisnamedRegister
1414
SwiftName: 'setter:ZXSpectrum.misnamedRegister(self:newValue:)'
15+
- Name: ZXSpectrumHelperReset
16+
SwiftName: 'ZXSpectrum.Helper.reset()'

test/APINotes/Inputs/broken-modules/BrokenAPINotes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ void ZXSpectrumSetRegister(ZXSpectrum *self, int which, unsigned char newValue);
99
unsigned char ZXSpectrumGetMisnamedRegister(const ZXSpectrum *self, int which);
1010
void ZXSpectrumSetMisnamedRegister(ZXSpectrum *self, int which, unsigned char newValue);
1111

12+
void ZXSpectrumHelperReset(void);

test/APINotes/broken-swift-name.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ func testBrokenSwiftName(x: inout ZXSpectrum) {
2121
ZXSpectrumGetMisnamedRegister(&x, 0)
2222
// TODO: Conservative validation in Clang doesn't reject the API name here
2323
// ZXSpectrumSetMisnamedRegister(&x, 0, 1)
24+
25+
ZXSpectrumHelperReset()
2426
}

test/attr/attr_availability.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,6 @@ let _: Int
127127
@available(*, renamed: "bad name") // expected-error{{'renamed' argument of 'available' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name}}
128128
let _: Int
129129

130-
@available(*, renamed: "Overly.Nested.Name") // expected-error{{'renamed' argument of 'available' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name}}
131-
let _: Int
132-
133130
@available(*, renamed: "_") // expected-error{{'renamed' argument of 'available' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name}}
134131
let _: Int
135132

@@ -249,6 +246,8 @@ func testOperators(x: DummyType, y: DummyType) {
249246
func unavailableMember() {} // expected-note {{here}}
250247
@available(*, deprecated, renamed: "DummyType.bar")
251248
func deprecatedMember() {}
249+
@available(*, unavailable, renamed: "DummyType.Inner.foo")
250+
func unavailableNestedMember() {} // expected-note {{here}}
252251
253252
@available(*, unavailable, renamed: "DummyType.Foo")
254253
struct UnavailableType {} // expected-note {{here}}
@@ -258,6 +257,7 @@ typealias DeprecatedType = Int
258257
func testGlobalToMembers() {
259258
unavailableMember() // expected-error {{'unavailableMember()' has been renamed to 'DummyType.foo'}} {{3-20=DummyType.foo}}
260259
deprecatedMember() // expected-warning {{'deprecatedMember()' is deprecated: renamed to 'DummyType.bar'}} expected-note {{use 'DummyType.bar' instead}} {{3-19=DummyType.bar}}
260+
unavailableNestedMember() // expected-error {{'unavailableNestedMember()' has been renamed to 'DummyType.Inner.foo'}} {{3-26=DummyType.Inner.foo}}
261261
let x: UnavailableType? = nil // expected-error {{'UnavailableType' has been renamed to 'DummyType.Foo'}} {{10-25=DummyType.Foo}}
262262
_ = x
263263
let y: DeprecatedType? = nil // expected-warning {{'DeprecatedType' is deprecated: renamed to 'DummyType.Bar'}} expected-note {{use 'DummyType.Bar' instead}} {{10-24=DummyType.Bar}}
@@ -303,6 +303,8 @@ func unavailableMultiNewlyUnnamed(a: Int, b: Int) {} // expected-note {{here}}
303303
304304
@available(*, unavailable, renamed: "Int.init(other:)")
305305
func unavailableInit(a: Int) {} // expected-note 2 {{here}}
306+
@available(*, unavailable, renamed: "Foo.Bar.init(other:)")
307+
func unavailableNestedInit(a: Int) {} // expected-note 2 {{here}}
306308
307309
308310
func testArgNames() {
@@ -329,6 +331,10 @@ func testArgNames() {
329331
unavailableInit(a: 0) // expected-error {{'unavailableInit(a:)' has been replaced by 'Int.init(other:)'}} {{3-18=Int}} {{19-20=other}}
330332
let fn = unavailableInit // expected-error {{'unavailableInit(a:)' has been replaced by 'Int.init(other:)'}} {{12-27=Int.init}}
331333
fn(a: 1)
334+
335+
unavailableNestedInit(a: 0) // expected-error {{'unavailableNestedInit(a:)' has been replaced by 'Foo.Bar.init(other:)'}} {{3-24=Foo.Bar}} {{25-26=other}}
336+
let fn2 = unavailableNestedInit // expected-error {{'unavailableNestedInit(a:)' has been replaced by 'Foo.Bar.init(other:)'}} {{13-34=Foo.Bar.init}}
337+
fn2(a: 1)
332338
}
333339
334340
@available(*, unavailable, renamed: "shinyLabeledArguments()")
@@ -368,6 +374,9 @@ func deprecatedInstance(a: Int) {}
368374
@available(*, deprecated, renamed: "Int.foo(self:)", message: "blah")
369375
func deprecatedInstanceMessage(a: Int) {}
370376
377+
@available(*, unavailable, renamed: "Foo.Bar.foo(self:)")
378+
func unavailableNestedInstance(a: Int) {} // expected-note {{here}}
379+
371380
func testRenameInstance() {
372381
unavailableInstance(a: 0) // expected-error{{'unavailableInstance(a:)' has been replaced by instance method 'Int.foo()'}} {{3-22=0.foo}} {{23-27=}}
373382
unavailableInstanceUnlabeled(0) // expected-error{{'unavailableInstanceUnlabeled' has been replaced by instance method 'Int.foo()'}} {{3-31=0.foo}} {{32-33=}}
@@ -380,6 +389,8 @@ func testRenameInstance() {
380389
unavailableInstanceMessage(a: 0) // expected-error{{'unavailableInstanceMessage(a:)' has been replaced by instance method 'Int.foo()': blah}} {{3-29=0.foo}} {{30-34=}}
381390
deprecatedInstance(a: 0) // expected-warning{{'deprecatedInstance(a:)' is deprecated: replaced by instance method 'Int.foo()'}} expected-note{{use 'Int.foo()' instead}} {{3-21=0.foo}} {{22-26=}}
382391
deprecatedInstanceMessage(a: 0) // expected-warning{{'deprecatedInstanceMessage(a:)' is deprecated: blah}} expected-note{{use 'Int.foo()' instead}} {{3-28=0.foo}} {{29-33=}}
392+
393+
unavailableNestedInstance(a: 0) // expected-error{{'unavailableNestedInstance(a:)' has been replaced by instance method 'Foo.Bar.foo()'}} {{3-28=0.foo}} {{29-33=}}
383394
}
384395
385396
@available(*, unavailable, renamed: "Int.shinyLabeledArguments(self:)")

0 commit comments

Comments
 (0)