]> granicus.if.org Git - clang/commitdiff
Objective-C. When we use @selector(save:), etc. there may be more
authorFariborz Jahanian <fjahanian@apple.com>
Tue, 24 Jun 2014 17:02:19 +0000 (17:02 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Tue, 24 Jun 2014 17:02:19 +0000 (17:02 +0000)
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
lib/Parse/ParseObjc.cpp
lib/Sema/SemaExprObjC.cpp
test/FixIt/fixit-multiple-selector-warnings.m [new file with mode: 0644]
test/SemaObjC/selector-1.m

index b8d31c32a449505362bdefb189ce7c98d466bd85..fb1fe36304d5442ceb4720feea4a18de9f5316e0 100644 (file)
@@ -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,
index e3fd7adfdf225b4a1b777f8ff8e977bc097f4f72..7fe72ec0c3b154d76be07ad06354dbbb8a7c8595 100644 (file)
@@ -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) {
index 9fbf656b55a036274d16aa2bf3f564af41cc7b05..299dd5d379e02322bbf350c79b477acfcac7c19c 100644 (file)
@@ -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 (file)
index 0000000..391728d
--- /dev/null
@@ -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:);
+}
+
+
index 0d83d47eb4e79ebf3cadb7df6e175eca0efd6d50..4efa0d71178793d895a705b9291a377eb8922778 100644 (file)
@@ -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:);