diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2014-06-24 17:02:19 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2014-06-24 17:02:19 +0000 |
commit | a36053be37f9f3e3fff6aadb90d81d4e06d61d1f (patch) | |
tree | 20cfa405e317c267738f38f12924760c9097f274 | |
parent | e8e398049c5cb9d8ee10a8fcee11cb5df2f8999f (diff) | |
download | clang-a36053be37f9f3e3fff6aadb90d81d4e06d61d1f.tar.gz clang-a36053be37f9f3e3fff6aadb90d81d4e06d61d1f.tar.bz2 clang-a36053be37f9f3e3fff6aadb90d81d4e06d61d1f.tar.xz |
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
-rw-r--r-- | include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 26 | ||||
-rw-r--r-- | test/FixIt/fixit-multiple-selector-warnings.m | 26 | ||||
-rw-r--r-- | test/SemaObjC/selector-1.m | 12 |
5 files changed, 67 insertions, 13 deletions
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:); |