From a36053be37f9f3e3fff6aadb90d81d4e06d61d1f Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 24 Jun 2014 17:02:19 +0000 Subject: [PATCH] Objective-C. When we use @selector(save:), etc. there may be more than one method with mismatched type of same selector name. clang issues a warning to point this out since it may cause undefined behavior. There are cases though that some APIs don't care about user methods and such warnings are perceived as noise. This patch allows users to add paren delimiters around selector name to turn off such warnings. So, @selector((save:)) will turn off the warning. It also provides 'fixit' so user knows what to do. // rdar://16458579 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211611 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 3 ++- lib/Parse/ParseObjc.cpp | 13 +++++++--- lib/Sema/SemaExprObjC.cpp | 26 ++++++++++++------- test/FixIt/fixit-multiple-selector-warnings.m | 26 +++++++++++++++++++ test/SemaObjC/selector-1.m | 12 +++++++++ 5 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 test/FixIt/fixit-multiple-selector-warnings.m diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b8d31c32a4..fb1fe36304 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4748,7 +4748,8 @@ public: SourceLocation AtLoc, SourceLocation SelLoc, SourceLocation LParenLoc, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + bool WarnMultipleSelectors); /// ParseObjCProtocolExpression - Build protocol expression for \@protocol ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index e3fd7adfdf..7fe72ec0c3 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -2839,7 +2839,7 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { } /// objc-selector-expression -/// @selector '(' objc-keyword-selector ')' +/// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')' ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { SourceLocation SelectorLoc = ConsumeToken(); @@ -2851,7 +2851,10 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { 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(); @@ -2864,6 +2867,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { return ExprError(Diag(Tok, diag::err_expected) << tok::identifier); KeyIdents.push_back(SelIdent); + unsigned nColons = 0; if (Tok.isNot(tok::r_paren)) { while (1) { @@ -2891,11 +2895,14 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { 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) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 9fbf656b55..299dd5d379 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -976,6 +976,8 @@ ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, SourceLocation AtLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc, ObjCMethodDecl *Method, ObjCMethodList &MethList) { ObjCMethodList *M = &MethList; @@ -991,7 +993,8 @@ static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, 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(); } @@ -1003,23 +1006,26 @@ static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, } 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; } } @@ -1028,7 +1034,8 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, SourceLocation LParenLoc, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool WarnMultipleSelectors) { ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LParenLoc, RParenLoc), false, false); if (!Method) @@ -1046,7 +1053,8 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, } 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 && diff --git a/test/FixIt/fixit-multiple-selector-warnings.m b/test/FixIt/fixit-multiple-selector-warnings.m new file mode 100644 index 0000000000..391728d0a9 --- /dev/null +++ b/test/FixIt/fixit-multiple-selector-warnings.m @@ -0,0 +1,26 @@ +/* RUN: cp %s %t + RUN: %clang_cc1 -x objective-c -Wselector-type-mismatch -fixit %t + RUN: %clang_cc1 -x objective-c -Wselector-type-mismatch -Werror %t +*/ +// rdar://16458579 + +@interface I +- (id) compare: (char) arg1; +- length; +@end + +@interface J +- (id) compare: (id) arg1; +@end + +SEL func() +{ + (void)@selector( compare: ); + (void)@selector (compare:); + (void)@selector( compare:); + (void)@selector(compare: ); + (void)@selector ( compare: ); + return @selector(compare:); +} + + diff --git a/test/SemaObjC/selector-1.m b/test/SemaObjC/selector-1.m index 0d83d47eb4..4efa0d7117 100644 --- a/test/SemaObjC/selector-1.m +++ b/test/SemaObjC/selector-1.m @@ -14,6 +14,18 @@ SEL func() 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:); -- 2.50.1