@@ -2056,12 +2056,31 @@ class ObjCSelectorWalker : public ASTWalker {
2056
2056
else if (!argNames[0 ].empty ())
2057
2057
return { true , expr };
2058
2058
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
+
2059
2078
// Dig out the argument.
2060
- Expr *arg = call->getArg ()-> getSemanticsProvidingExpr ( );
2079
+ Expr *arg = lookThroughParens ( call->getArg (), /* outermost= */ true );
2061
2080
if (auto tupleExpr = dyn_cast<TupleExpr>(arg)) {
2062
2081
if (tupleExpr->getNumElements () == 1 &&
2063
2082
tupleExpr->getElementName (0 ) == TC.Context .Id_stringLiteral )
2064
- arg = tupleExpr->getElement (0 )-> getSemanticsProvidingExpr ( );
2083
+ arg = lookThroughParens ( tupleExpr->getElement (0 ), /* outermost= */ false );
2065
2084
}
2066
2085
2067
2086
// If the argument is a call, it might be to
@@ -2074,9 +2093,8 @@ class ObjCSelectorWalker : public ASTWalker {
2074
2093
dyn_cast_or_null<ConstructorDecl>(ctorRefCall->getCalledValue ())){
2075
2094
auto argArgumentNames = argCtor->getFullName ().getArgumentNames ();
2076
2095
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 );
2080
2098
}
2081
2099
}
2082
2100
}
@@ -2137,10 +2155,28 @@ class ObjCSelectorWalker : public ASTWalker {
2137
2155
2138
2156
// If we didn't find any methods, complain.
2139
2157
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
+
2144
2180
return { true , expr };
2145
2181
}
2146
2182
0 commit comments