]> granicus.if.org Git - clang/commitdiff
ObjC kindof: check the context when inserting methods to global pool.
authorManman Ren <manman.ren@gmail.com>
Sat, 9 Apr 2016 18:59:48 +0000 (18:59 +0000)
committerManman Ren <manman.ren@gmail.com>
Sat, 9 Apr 2016 18:59:48 +0000 (18:59 +0000)
To make kindof lookup work, we need to insert methods with different
context into the global pool, even though they have the same siganture.

Since diagnosis of availability is performed on the best candidate,
which is often the first candidate from the global pool, we prioritize
the methods that are unavaible or deprecated to the head of the list.

Since we now have more methods in the global pool, we need to watch
out for performance impact.

rdar://25635831

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

include/clang/Sema/ObjCMethodList.h
lib/Sema/SemaDeclObjC.cpp
test/FixIt/typo.m
test/SemaObjC/kindof.m
test/SemaObjC/multiple-method-names.m
test/SemaObjC/warn-strict-selector-match.m

index 2c9350df7426dfef05218d10144781582895fd0c..80ccd363d2725b2705b93b6abf3bef1b77ce69ef 100644 (file)
@@ -33,6 +33,9 @@ struct ObjCMethodList {
   ObjCMethodList() { }
   ObjCMethodList(ObjCMethodDecl *M)
       : MethodAndHasMoreThanOneDecl(M, 0) {}
+  ObjCMethodList(const ObjCMethodList &L)
+      : MethodAndHasMoreThanOneDecl(L.MethodAndHasMoreThanOneDecl),
+        NextAndExtraBits(L.NextAndExtraBits) {}
 
   ObjCMethodList *getNext() const { return NextAndExtraBits.getPointer(); }
   unsigned getBits() const { return NextAndExtraBits.getInt(); }
index 32244e9e1956c8472ed6a9faa3e36b705fae29e1..a9cc0d61be9e432d8063fd004199fb05b4ae845d 100644 (file)
@@ -3167,6 +3167,26 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
   return true;
 }
 
+static bool isMethodContextSameForKindofLookup(ObjCMethodDecl *Method,
+                                               ObjCMethodDecl *MethodInList) {
+  auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext());
+  auto *MethodInListProtocol =
+      dyn_cast<ObjCProtocolDecl>(MethodInList->getDeclContext());
+  // If this method belongs to a protocol but the method in list does not, or
+  // vice versa, we say the context is not the same.
+  if ((MethodProtocol && !MethodInListProtocol) ||
+      (!MethodProtocol && MethodInListProtocol))
+    return false;
+
+  if (MethodProtocol && MethodInListProtocol)
+    return true;
+
+  ObjCInterfaceDecl *MethodInterface = Method->getClassInterface();
+  ObjCInterfaceDecl *MethodInListInterface =
+      MethodInList->getClassInterface();
+  return MethodInterface == MethodInListInterface;
+}
+
 void Sema::addMethodToGlobalList(ObjCMethodList *List,
                                  ObjCMethodDecl *Method) {
   // Record at the head of the list whether there were 0, 1, or >= 2 methods
@@ -3185,13 +3205,17 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List,
 
   // We've seen a method with this name, see if we have already seen this type
   // signature.
+  ObjCMethodList *Head = List;
   ObjCMethodList *Previous = List;
   for (; List; Previous = List, List = List->getNext()) {
     // If we are building a module, keep all of the methods.
     if (getLangOpts().CompilingModule)
       continue;
 
-    if (!MatchTwoMethodDeclarations(Method, List->getMethod())) {
+    // Looking for method with a type bound requires the correct context exists.
+    // We need to insert this method into the list if the context is different.
+    if (!MatchTwoMethodDeclarations(Method, List->getMethod()) ||
+        !isMethodContextSameForKindofLookup(Method, List->getMethod())) {
       // Even if two method types do not match, we would like to say
       // there is more than one declaration so unavailability/deprecated
       // warning is not too noisy.
@@ -3232,6 +3256,19 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List,
   // We have a new signature for an existing method - add it.
   // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
   ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+
+  // We tried to prioritize the list by putting deprecated and unavailable
+  // methods in the front.
+  if ((Method->isDeprecated() && !Head->getMethod()->isDeprecated()) ||
+      (Method->isUnavailable() &&
+       Head->getMethod()->getAvailability() < AR_Deprecated)) {
+    auto *List = new (Mem) ObjCMethodList(*Head);
+    // FIXME: should we clear the other bits in Head?
+    Head->setMethod(Method);
+    Head->setNext(List);
+    return;
+  }
+
   Previous->setNext(new (Mem) ObjCMethodList(Method));
 }
 
index 381233f95c29a4187417e46e69a56aaee69b5dc8..143d026b2becbd25de7cd0366ff530ec1f03ec9e 100644 (file)
@@ -103,7 +103,7 @@ void test2(Collide *a) {
 @end
 
 @interface Sub : Super
-- (int)method;
+- (int)method; // expected-note{{also found}}
 @end
 
 @implementation Sub
index 36c9b8f0a2b92d619a90bd559c040a51018239d6..95c7f993d17b284039878d80c11b1e3705d19248 100644 (file)
@@ -275,6 +275,20 @@ void test(__kindof Bar *kBar) {
     [kBar test];
 }
 
+// Make sure we don't emit warning about no method found.
+typedef signed char BOOL;
+@interface A : NSObject
+@property (readonly, getter=isActive) BOOL active;
+@end
+@interface B : NSObject
+@property (getter=isActive, readonly) BOOL active;
+@end
+void foo() {
+  __kindof B *NSApp;
+  if ([NSApp isActive]) {
+  }
+}
+
 // ---------------------------------------------------------------------------
 // __kindof within specialized types
 // ---------------------------------------------------------------------------
index 9fd83b208ab7971bcc4a1f09b996d2522572e09b..a8707904b5694da25d9cf9250cd80a2cb9f5141b 100644 (file)
@@ -2,11 +2,11 @@
 // PR22047
 
 @interface Face0
-- (void)foo:(float)i; // expected-note {{using}}
+- (void)foo:(float)i; // expected-note {{also found}}
 @end
 
 @interface Face1
-- (void)foo:(int)i __attribute__((unavailable));
+- (void)foo:(int)i __attribute__((unavailable)); // expected-note {{using}}
 @end
 
 @interface Face2
index 13e9bac462fcbecf2b8238885baf5899a6593d52..6b92cb805df176fb7b6e1242fe0d2bf33b3af2a2 100644 (file)
@@ -49,7 +49,7 @@ id foo(void) {
 @end
 
 @implementation NTGridDataObject
-- (id)initWithData:(id<MyObject, MyCoding>)data {
+- (id)initWithData:(id<MyObject, MyCoding>)data { // expected-note {{also found}}
   return data;
 }
 + (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data