Skip to content

Commit 6cbffa7

Browse files
committed
[Sema] Make it possible to suppress warnings about Selector("foo").
When the selector named by Selector("foo") does not map to a known Objective-C method, allow one to suppress the warning by wrapping the string literal in an extra set of parentheses, e.g., Selector(("foo")) Suggest this via a Fix-It on a note so it's discoverable. Addresses rdar://problem/24791200.
1 parent 187bc9f commit 6cbffa7

File tree

3 files changed

+50
-11
lines changed

3 files changed

+50
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ WARNING(selector_literal_deprecated_suggest,none,
392392
"use '#selector' instead", ())
393393
WARNING(selector_construction_suggest,none,
394394
"use '#selector' instead of explicitly constructing a 'Selector'", ())
395+
NOTE(selector_construction_suppress_warning,none,
396+
"wrap the selector name in parentheses to suppress this warning", ())
395397

396398
ERROR(cannot_return_value_from_void_func,none,
397399
"unexpected non-void return value in void function", ())

lib/Sema/MiscDiagnostics.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,12 +2056,31 @@ class ObjCSelectorWalker : public ASTWalker {
20562056
else if (!argNames[0].empty())
20572057
return { true, expr };
20582058

2059+
// Track whether we had parentheses around the string literal.
2060+
bool hadParens = false;
2061+
auto lookThroughParens = [&](Expr *arg, bool outermost) -> Expr * {
2062+
if (auto parenExpr = dyn_cast<ParenExpr>(arg)) {
2063+
if (!outermost) {
2064+
hadParens = true;
2065+
return parenExpr->getSubExpr()->getSemanticsProvidingExpr();
2066+
}
2067+
2068+
arg = parenExpr->getSubExpr();
2069+
if (auto innerParenExpr = dyn_cast<ParenExpr>(arg)) {
2070+
hadParens = true;
2071+
arg = innerParenExpr->getSubExpr();
2072+
}
2073+
}
2074+
2075+
return arg->getSemanticsProvidingExpr();
2076+
};
2077+
20592078
// Dig out the argument.
2060-
Expr *arg = call->getArg()->getSemanticsProvidingExpr();
2079+
Expr *arg = lookThroughParens(call->getArg(), /*outermost=*/true);
20612080
if (auto tupleExpr = dyn_cast<TupleExpr>(arg)) {
20622081
if (tupleExpr->getNumElements() == 1 &&
20632082
tupleExpr->getElementName(0) == TC.Context.Id_stringLiteral)
2064-
arg = tupleExpr->getElement(0)->getSemanticsProvidingExpr();
2083+
arg = lookThroughParens(tupleExpr->getElement(0), /*outermost=*/false);
20652084
}
20662085

20672086
// If the argument is a call, it might be to
@@ -2074,9 +2093,8 @@ class ObjCSelectorWalker : public ASTWalker {
20742093
dyn_cast_or_null<ConstructorDecl>(ctorRefCall->getCalledValue())){
20752094
auto argArgumentNames = argCtor->getFullName().getArgumentNames();
20762095
if (argArgumentNames.size() == 3 &&
2077-
argArgumentNames[0] == TC.Context.Id_builtinStringLiteral) {
2078-
arg = argCall->getArg()->getSemanticsProvidingExpr();
2079-
}
2096+
argArgumentNames[0] == TC.Context.Id_builtinStringLiteral)
2097+
arg = lookThroughParens(argCall->getArg(), /*outermost=*/false);
20802098
}
20812099
}
20822100
}
@@ -2137,10 +2155,28 @@ class ObjCSelectorWalker : public ASTWalker {
21372155

21382156
// If we didn't find any methods, complain.
21392157
if (allMethods.empty()) {
2140-
auto diag =
2141-
TC.diagnose(stringLiteral->getLoc(), diag::selector_literal_undeclared,
2142-
*selector);
2143-
addSelectorConstruction(diag);
2158+
// If this was Selector(("selector-name")), suppress, the
2159+
// diagnostic.
2160+
if (!fromStringLiteral && hadParens)
2161+
return { true, expr };
2162+
2163+
{
2164+
auto diag = TC.diagnose(stringLiteral->getLoc(),
2165+
diag::selector_literal_undeclared,
2166+
*selector);
2167+
addSelectorConstruction(diag);
2168+
}
2169+
2170+
// If the result was from a Selector("selector-name"), add a
2171+
// separate note that suggests wrapping the selector in
2172+
// parentheses to silence the warning.
2173+
if (!fromStringLiteral) {
2174+
TC.diagnose(stringLiteral->getLoc(),
2175+
diag::selector_construction_suppress_warning)
2176+
.fixItInsert(stringLiteral->getStartLoc(), "(")
2177+
.fixItInsertAfter(stringLiteral->getEndLoc(), ")");
2178+
}
2179+
21442180
return { true, expr };
21452181
}
21462182

test/expr/unary/selector/fixits.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@
2424
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t.overlays) -parse %t.sources/fixits.swift 2> %t.result
2525

2626
// RUN: FileCheck %s < %t.result
27-
// RUN: grep -c "warning:" %t.result | grep 4
27+
// RUN: grep -c "warning:" %t.result | grep 3
2828

2929
// CHECK: warning: no method declared with Objective-C selector 'unknownMethodWithValue:label:'
3030
// CHECK: warning: string literal is not a valid Objective-C selector
31-
// CHECK: warning: no method declared with Objective-C selector 'unknownMethodWithValue:label:'
3231
// CHECK: warning: string literal is not a valid Objective-C selector
3332

3433
import Foundation
@@ -98,6 +97,8 @@ func testDeprecatedStringLiteralSelector() {
9897
func testSelectorConstruction() {
9998
_ = Selector("methodWithValue:label:") // expected-warning{{use '#selector' instead of explicitly constructing a 'Selector'}}{{7-41=#selector(Foo.method(_:label:))}}
10099
_ = Selector("unknownMethodWithValue:label:") // expected-warning{{no method declared with Objective-C selector 'unknownMethodWithValue:label:'}}
100+
// expected-note@-1{{wrap the selector name in parentheses to suppress this warning}}{{16-16=(}}{{47-47=)}}
101+
_ = Selector(("unknownMethodWithValue:label:"))
101102
_ = Selector("badSelector:label") // expected-warning{{string literal is not a valid Objective-C selector}}
102103
_ = Selector("method2WithValue:") // expected-warning{{use '#selector' instead of explicitly constructing a 'Selector'}}{{7-36=#selector(Foo.method2(_:))}}
103104
_ = Selector("method3") // expected-warning{{use '#selector' instead of explicitly constructing a 'Selector'}}{{7-26=#selector(Foo.method3)}}

0 commit comments

Comments
 (0)