]> granicus.if.org Git - clang/commitdiff
[Objective-C Sema]This patch fixes the warning when clang issues
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 15 Apr 2015 17:26:21 +0000 (17:26 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 15 Apr 2015 17:26:21 +0000 (17:26 +0000)
"multiple methods named '<selector>' found" warning by noting
the method that is actualy used. It also cleans up and refactors
code in this area and selects a method that matches actual arguments
in case of receiver being a forward class object.
rdar://19265430

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@235023 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaPseudoObject.cpp
test/SemaObjC/warn-strict-selector-match.m

index 3f310717902a1370033699abf9e9a2c79d9374f3..84302fa669869af8dcd08ee0dd4d8a1994089a05 100644 (file)
@@ -2908,7 +2908,7 @@ private:
   /// optionally warns if there are multiple signatures.
   ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R,
                                            bool receiverIdOrClass,
-                                           bool warn, bool instance);
+                                           bool instance);
 
 public:
   /// \brief - Returns instance or factory methods in global method pool for
@@ -2918,8 +2918,13 @@ public:
                                           SmallVectorImpl<ObjCMethodDecl*>& Methods,
                                           bool instance);
     
-  bool AreMultipleMethodsInGlobalPool(Selector Sel,
-                                      bool instance);
+  bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
+                                      SourceRange R,
+                                      bool receiverIdOrClass);
+      
+  void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods,
+                                          Selector Sel, SourceRange R,
+                                          bool receiverIdOrClass);
 
 private:
   /// \brief - Returns a selector which best matches given argument list or
@@ -2957,19 +2962,17 @@ public:
   /// LookupInstanceMethodInGlobalPool - Returns the method and warns if
   /// there are multiple signatures.
   ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R,
-                                                   bool receiverIdOrClass=false,
-                                                   bool warn=true) {
+                                                   bool receiverIdOrClass=false) {
     return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass,
-                                    warn, /*instance*/true);
+                                    /*instance*/true);
   }
 
   /// LookupFactoryMethodInGlobalPool - Returns the method and warns if
   /// there are multiple signatures.
   ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R,
-                                                  bool receiverIdOrClass=false,
-                                                  bool warn=true) {
+                                                  bool receiverIdOrClass=false) {
     return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass,
-                                    warn, /*instance*/false);
+                                    /*instance*/false);
   }
 
   const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel,
index 800abd13e083979bac7c62ee3f449116af2be30a..256419353c852718e415a865cff5a7e05c3e1fb3 100644 (file)
@@ -2346,19 +2346,33 @@ bool Sema::CollectMultipleMethodsInGlobalPool(
   return Methods.size() > 1;
 }
 
-bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, bool instance) {
+bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
+                                          SourceRange R,
+                                          bool receiverIdOrClass) {
   GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
   // Test for no method in the pool which should not trigger any warning by
   // caller.
   if (Pos == MethodPool.end())
     return true;
-  ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+  ObjCMethodList &MethList =
+    BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second;
+  
+  // Diagnose finding more than one method in global pool
+  SmallVector<ObjCMethodDecl *, 4> Methods;
+  Methods.push_back(BestMethod);
+  for (ObjCMethodList *M = &MethList; M; M = M->getNext())
+    if (M->getMethod() && !M->getMethod()->isHidden() &&
+        M->getMethod() != BestMethod)
+      Methods.push_back(M->getMethod());
+  if (Methods.size() > 1)
+    DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass);
+
   return MethList.hasMoreThanOneDecl();
 }
 
 ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
                                                bool receiverIdOrClass,
-                                               bool warn, bool instance) {
+                                               bool instance) {
   if (ExternalSource)
     ReadMethodPool(Sel);
     
@@ -2370,31 +2384,23 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
   ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
   SmallVector<ObjCMethodDecl *, 4> Methods;
   for (ObjCMethodList *M = &MethList; M; M = M->getNext()) {
-    if (M->getMethod() && !M->getMethod()->isHidden()) {
-      // If we're not supposed to warn about mismatches, we're done.
-      if (!warn)
-        return M->getMethod();
-
-      Methods.push_back(M->getMethod());
-    }
+    if (M->getMethod() && !M->getMethod()->isHidden())
+      return M->getMethod();
   }
+  return nullptr;
+}
 
-  // If there aren't any visible methods, we're done.
-  // FIXME: Recover if there are any known-but-hidden methods?
-  if (Methods.empty())
-    return nullptr;
-
-  if (Methods.size() == 1)
-    return Methods[0];
-
+void Sema::DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods,
+                                              Selector Sel, SourceRange R,
+                                              bool receiverIdOrClass) {
   // We found multiple methods, so we may have to complain.
   bool issueDiagnostic = false, issueError = false;
-
+  
   // We support a warning which complains about *any* difference in
   // method signature.
   bool strictSelectorMatch =
-      receiverIdOrClass && warn &&
-      !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin());
+  receiverIdOrClass &&
+  !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin());
   if (strictSelectorMatch) {
     for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
       if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) {
@@ -2403,7 +2409,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
       }
     }
   }
-
+  
   // If we didn't see any strict differences, we won't see any loose
   // differences.  In ARC, however, we also need to check for loose
   // mismatches, because most of them are errors.
@@ -2419,7 +2425,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
         break;
       }
     }
-
+  
   if (issueDiagnostic) {
     if (issueError)
       Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
@@ -2427,16 +2433,15 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
       Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
     else
       Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
-
+    
     Diag(Methods[0]->getLocStart(),
          issueError ? diag::note_possibility : diag::note_using)
-      << Methods[0]->getSourceRange();
+    << Methods[0]->getSourceRange();
     for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
       Diag(Methods[I]->getLocStart(), diag::note_also_found)
-        << Methods[I]->getSourceRange();
-  }
+      << Methods[I]->getSourceRange();
+    }
   }
-  return Methods[0];
 }
 
 ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
index e095ee71582a7462d217c03ff71ad9ec64c21066..d18aeab57a0af875b777eb9842ae289cba4e4e0c 100644 (file)
@@ -8175,8 +8175,7 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
     if (Type->isObjCIdType()) {
       // For 'id', just check the global pool.
       Method = S.LookupInstanceMethodInGlobalPool(IsEqualSel, SourceRange(),
-                                                  /*receiverId=*/true,
-                                                  /*warn=*/false);
+                                                  /*receiverId=*/true);
     } else {
       // Check protocols.
       Method = S.LookupMethodInQualifiedType(IsEqualSel, Type,
index 62c1b874d5acc095c09c2632394febc768efe441..63b7485c8764dd3ea9a41acabcffb56965fd5c08 100644 (file)
@@ -1043,7 +1043,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
                                              SourceLocation RParenLoc,
                                              bool WarnMultipleSelectors) {
   ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
-                             SourceRange(LParenLoc, RParenLoc), false, false);
+                             SourceRange(LParenLoc, RParenLoc));
   if (!Method)
     Method = LookupFactoryMethodInGlobalPool(Sel,
                                           SourceRange(LParenLoc, RParenLoc));
@@ -2393,8 +2393,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
         if (ObjCMethodDecl *BestMethod =
               SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
           Method = BestMethod;
-        if (!AreMultipleMethodsInGlobalPool(Sel, Method->isInstanceMethod()))
+        if (!AreMultipleMethodsInGlobalPool(Sel, Method,
+                                            SourceRange(LBracLoc, RBracLoc),
+                                            receiverIsId)) {
           DiagnoseUseOfDecl(Method, SelLoc);
+        }
       }
     } else if (ReceiverType->isObjCClassType() ||
                ReceiverType->isObjCQualifiedClassType()) {
@@ -2432,14 +2435,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
           // If not messaging 'self', look for any factory method named 'Sel'.
           if (!Receiver || !isSelfExpr(Receiver)) {
             Method = LookupFactoryMethodInGlobalPool(Sel, 
-                                                SourceRange(LBracLoc, RBracLoc),
-                                                     true);
+                                                SourceRange(LBracLoc, RBracLoc));
             if (!Method) {
               // If no class (factory) method was found, check if an _instance_
               // method of the same name exists in the root class only.
               Method = LookupInstanceMethodInGlobalPool(Sel,
-                                               SourceRange(LBracLoc, RBracLoc),
-                                                        true);
+                                               SourceRange(LBracLoc, RBracLoc));
               if (Method)
                   if (const ObjCInterfaceDecl *ID =
                       dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
@@ -2516,6 +2517,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
             if (OCIType->qual_empty()) {
               Method = LookupInstanceMethodInGlobalPool(Sel,
                                               SourceRange(LBracLoc, RBracLoc));
+              if (Method) {
+                if (auto BestMethod =
+                      SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+                  Method = BestMethod;
+                AreMultipleMethodsInGlobalPool(Sel, Method,
+                                               SourceRange(LBracLoc, RBracLoc),
+                                               true);
+              }
               if (Method && !forwardClass)
                 Diag(SelLoc, diag::warn_maynot_respond)
                   << OCIType->getInterfaceDecl()->getIdentifier()
index 935128b7ecd29308566584952d77493299b3ddce..3e465af9632c875746bdbb0de33fd1b5d8ee7019 100644 (file)
@@ -1192,7 +1192,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
     AtIndexGetter = 
       S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector, 
                                          RefExpr->getSourceRange(), 
-                                         true, false);
+                                         true);
   }
   
   if (AtIndexGetter) {
@@ -1314,7 +1314,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
     AtIndexSetter = 
       S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector, 
                                          RefExpr->getSourceRange(), 
-                                         true, false);
+                                         true);
   }
   
   bool err = false;
index 9f22e73edc6952624ce3c69018fe7d3e497c4aa0..13e9bac462fcbecf2b8238885baf5899a6593d52 100644 (file)
@@ -13,23 +13,24 @@ int main() { [(id)0 method]; } // expected-warning {{multiple methods named 'met
 @interface Object @end
 
 @interface Class1
-- (void)setWindow:(Object *)wdw;       // expected-note {{using}}
+- (void)setWindow:(Object *)wdw;       // expected-note {{using}}
 @end
 
 @interface Class2
-- (void)setWindow:(Class1 *)window;    // expected-note {{also found}}
+- (void)setWindow:(Class1 *)window;    // expected-note {{also found}}
 @end
 
 id foo(void) {
   Object *obj = 0;
   id obj2 = obj;
-  [obj setWindow:0];   // expected-warning {{Object' may not respond to 'setWindow:'}}
+  [obj setWindow:0];   // expected-warning {{Object' may not respond to 'setWindow:'}} \
+                       // expected-warning {{multiple methods named 'setWindow:' found}}
   [obj2 setWindow:0]; // expected-warning {{multiple methods named 'setWindow:' found}}
   return obj;
 }
 
 @protocol MyObject
-- (id)initWithData:(Object *)data;     // expected-note {{using}} 
+- (id)initWithData:(Object *)data;     // expected-note {{also found}} 
 @end
 
 @protocol SomeOther
@@ -37,7 +38,7 @@ id foo(void) {
 @end
 
 @protocol MyCoding
-- (id)initWithData:(id<MyObject, MyCoding>)data;       // expected-note {{also found}}
+- (id)initWithData:(id<MyObject, MyCoding>)data;       // expected-note {{using}}
 @end
 
 @interface NTGridDataObject: Object <MyCoding>
@@ -71,3 +72,29 @@ void foo1(void) {
   [(Class)0 port]; // OK - gcc issues warning but there is only one Class method so no ambiguity to warn
 }
 
+// rdar://19265430
+@interface NSObject 
+- (id)class;
+- (id) alloc;
+@end
+
+@class NSString;
+
+@interface A : NSObject
+- (instancetype)initWithType:(NSString *)whatever; // expected-note {{also found}}
+@end
+
+@interface Test : NSObject
+@end
+
+@implementation Test
++ (instancetype)foo
+{
+    return [[[self class] alloc] initWithType:3]; // expected-warning {{multiple methods named 'initWithType:'}}
+}
+
+- (instancetype)initWithType:(unsigned int)whatever // expected-note {{using}}
+{
+    return 0;
+}
+@end