summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2014-06-24 17:02:19 +0000
committerFariborz Jahanian <fjahanian@apple.com>2014-06-24 17:02:19 +0000
commita36053be37f9f3e3fff6aadb90d81d4e06d61d1f (patch)
tree20cfa405e317c267738f38f12924760c9097f274
parente8e398049c5cb9d8ee10a8fcee11cb5df2f8999f (diff)
downloadclang-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.h3
-rw-r--r--lib/Parse/ParseObjc.cpp13
-rw-r--r--lib/Sema/SemaExprObjC.cpp26
-rw-r--r--test/FixIt/fixit-multiple-selector-warnings.m26
-rw-r--r--test/SemaObjC/selector-1.m12
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:);