]> granicus.if.org Git - clang/commitdiff
ObjC kindof: order the methods in global pool relative to availability.
authorManman Ren <manman.ren@gmail.com>
Wed, 13 Apr 2016 23:43:56 +0000 (23:43 +0000)
committerManman Ren <manman.ren@gmail.com>
Wed, 13 Apr 2016 23:43:56 +0000 (23:43 +0000)
r265877 tries to put methods that are deprecated or unavailable to the
front of the global pool to emit diagnostics, but it breaks some of
our existing codes that depend on choosing a certain method for id
lookup.

This commit orders the methods with the same declaration with respect
to the availability, but do not order methods with different declaration.

rdar://25707511

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

lib/Sema/SemaDeclObjC.cpp
test/SemaObjC/kindof.m
test/SemaObjC/multiple-method-names.m

index 58ee123688dc08f1a28e3bd205ff0529bb0dc920..8090bec4fab211cbdb4850db19b5c177c788d414 100644 (file)
@@ -3213,22 +3213,43 @@ 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;
+  ObjCMethodList *ListWithSameDeclaration = nullptr;
   for (; List; Previous = List, List = List->getNext()) {
     // If we are building a module, keep all of the methods.
     if (getLangOpts().CompilingModule)
       continue;
 
+    bool SameDeclaration = 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()) ||
+    // We need to insert a method into the list if the context is different.
+    // If the method's declaration matches the list
+    // a> the method belongs to a different context: we need to insert it, in
+    //    order to emit the availability message, we need to prioritize over
+    //    availability among the methods with the same declaration.
+    // b> the method belongs to the same context: there is no need to insert a
+    //    new entry.
+    // If the method's declaration does not match the list, we insert it to the
+    // end.
+    if (!SameDeclaration ||
         !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.
       if (!Method->isDefined())
         List->setHasMoreThanOneDecl(true);
+
+      // For methods with the same declaration, the one that is deprecated
+      // should be put in the front for better diagnostics.
+      if (Method->isDeprecated() && SameDeclaration &&
+          !ListWithSameDeclaration && !List->getMethod()->isDeprecated())
+        ListWithSameDeclaration = List;
+
+      if (Method->isUnavailable() && SameDeclaration &&
+          !ListWithSameDeclaration &&
+          List->getMethod()->getAvailability() < AR_Deprecated)
+        ListWithSameDeclaration = List;
       continue;
     }
 
@@ -3265,15 +3286,12 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List,
   // 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);
+  // We insert it right before ListWithSameDeclaration.
+  if (ListWithSameDeclaration) {
+    auto *List = new (Mem) ObjCMethodList(*ListWithSameDeclaration);
+    // FIXME: should we clear the other bits in ListWithSameDeclaration?
+    ListWithSameDeclaration->setMethod(Method);
+    ListWithSameDeclaration->setNext(List);
     return;
   }
 
index 95c7f993d17b284039878d80c11b1e3705d19248..919ca960a9d50cfae57f9252940681efc2fb9e57 100644 (file)
@@ -25,6 +25,7 @@ __attribute__((objc_root_class))
 @end
 
 @interface NSString : NSObject <NSCopying> // expected-note{{receiver is instance of class declared here}}
+- (void)compare:(NSString *)string;
 - (NSString *)stringByAppendingString:(NSString *)string;
 + (instancetype)string;
 @end
@@ -289,6 +290,18 @@ void foo() {
   }
 }
 
+typedef const struct CGPath *CGPathRef;
+@interface C : NSObject
+@property (copy) NSString *path;
+@end
+@interface D : NSObject
+@property CGPathRef path __attribute__((availability(macosx,unavailable)));
+@end
+// Make sure we choose "NSString *path" for [s1 path].
+void bar(id s1, id s2) {
+  return [[s1 path] compare:[s2 path]];
+}
+
 // ---------------------------------------------------------------------------
 // __kindof within specialized types
 // ---------------------------------------------------------------------------
index a8707904b5694da25d9cf9250cd80a2cb9f5141b..9fd83b208ab7971bcc4a1f09b996d2522572e09b 100644 (file)
@@ -2,11 +2,11 @@
 // PR22047
 
 @interface Face0
-- (void)foo:(float)i; // expected-note {{also found}}
+- (void)foo:(float)i; // expected-note {{using}}
 @end
 
 @interface Face1
-- (void)foo:(int)i __attribute__((unavailable)); // expected-note {{using}}
+- (void)foo:(int)i __attribute__((unavailable));
 @end
 
 @interface Face2