}
/// objc-selector-expression
-/// @selector '(' objc-keyword-selector ')'
+/// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'
ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
SourceLocation SelectorLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
-
+ bool HasOptionalParen = Tok.is(tok::l_paren);
+ if (HasOptionalParen)
+ ConsumeParen();
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
KeyIdents.push_back(SelIdent);
+
unsigned nColons = 0;
if (Tok.isNot(tok::r_paren)) {
while (1) {
break;
}
}
+ if (HasOptionalParen && Tok.is(tok::r_paren))
+ ConsumeParen(); // ')'
T.consumeClose();
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
T.getOpenLocation(),
- T.getCloseLocation());
+ T.getCloseLocation(),
+ !HasOptionalParen);
}
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
SourceLocation AtLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc,
ObjCMethodDecl *Method,
ObjCMethodList &MethList) {
ObjCMethodList *M = &MethList;
if (!Warned) {
Warned = true;
S.Diag(AtLoc, diag::warning_multiple_selectors)
- << Method->getSelector();
+ << Method->getSelector() << FixItHint::CreateInsertion(LParenLoc, "(")
+ << FixItHint::CreateInsertion(RParenLoc, ")");
S.Diag(Method->getLocation(), diag::note_method_declared_at)
<< Method->getDeclName();
}
}
static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc,
- ObjCMethodDecl *Method) {
- if (S.Diags.isIgnored(diag::warning_multiple_selectors, SourceLocation()))
+ ObjCMethodDecl *Method,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc,
+ bool WarnMultipleSelectors) {
+ if (!WarnMultipleSelectors ||
+ S.Diags.isIgnored(diag::warning_multiple_selectors, SourceLocation()))
return;
bool Warned = false;
for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
e = S.MethodPool.end(); b != e; b++) {
// first, instance methods
ObjCMethodList &InstMethList = b->second.first;
- if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc,
+ if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
Method, InstMethList))
Warned = true;
// second, class methods
ObjCMethodList &ClsMethList = b->second.second;
- if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc,
- Method, ClsMethList) ||
- Warned)
+ if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
+ Method, ClsMethList) || Warned)
return;
}
}
SourceLocation AtLoc,
SourceLocation SelLoc,
SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool WarnMultipleSelectors) {
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc), false, false);
if (!Method)
} else
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
} else
- DiagnoseMismatchedSelectors(*this, AtLoc, Method);
+ DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
+ WarnMultipleSelectors);
if (Method &&
Method->getImplementationControl() != ObjCMethodDecl::Optional &&
return @selector(compare:); // expected-warning {{several methods with selector 'compare:' of mismatched types are found for the @selector expression}}
}
+// rdar://16458579
+void Test16458579() {
+ SEL s = @selector((retain));
+ SEL s1 = @selector((meth1:));
+ SEL s2 = @selector((retainArgument::));
+ SEL s3 = @selector((retainArgument:::::));
+ SEL s4 = @selector((retainArgument:with:));
+ SEL s5 = @selector((meth1:with:with:));
+ SEL s6 = @selector((getEnum:enum:bool:));
+ SEL s7 = @selector((char:float:double:unsigned:short:long:));
+ SEL s9 = @selector((:enum:bool:));
+}
int main() {
SEL s = @selector(retain);
SEL s1 = @selector(meth1:);