]> granicus.if.org Git - clang/commitdiff
[ObjC][Sema] Avoid warning about a call to an instance method on an
authorAlex Lorenz <arphaman@gmail.com>
Wed, 15 Mar 2017 17:16:41 +0000 (17:16 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Wed, 15 Mar 2017 17:16:41 +0000 (17:16 +0000)
instance of a qualified Class object when that instance method comes from
a protocol that's implemented by NSObject

Instance methods from a root class like NSObject are also class methods because
the metaclass of root class derives from that root class. Therefore, we can
avoid the warning for instances of qualified Class objects that point to classes
that derive from NSObject. Note that we actually don't know if a Class instance
points to a class that derives from NSObject at compile-time, so we have to
make a reasonable assumption that the majority of instances will do so.

rdar://22812517

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

lib/Sema/SemaExprObjC.cpp
test/SemaObjC/class-message-protocol-lookup.m

index 67876c261d0b27dcd590f259d48029768b9be7d9..99b31bc7553ff6a787524025bcb9f3fa73fea0e1 100644 (file)
@@ -2556,6 +2556,24 @@ ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
                               /*isImplicit=*/true);
 }
 
+static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) {
+  if (!S.NSAPIObj)
+    return false;
+  const auto *Protocol = dyn_cast<ObjCProtocolDecl>(M->getDeclContext());
+  if (!Protocol)
+    return false;
+  const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject);
+  if (const auto *RootClass = dyn_cast_or_null<ObjCInterfaceDecl>(
+          S.LookupSingleName(S.TUScope, II, Protocol->getLocStart(),
+                             Sema::LookupOrdinaryName))) {
+    for (const ObjCProtocolDecl *P : RootClass->all_referenced_protocols()) {
+      if (P->getCanonicalDecl() == Protocol->getCanonicalDecl())
+        return true;
+    }
+  }
+  return false;
+}
+
 /// \brief Build an Objective-C instance message expression.
 ///
 /// This routine takes care of both normal instance messages and
@@ -2731,7 +2749,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
         if (!Method) {
           Method = LookupMethodInQualifiedType(Sel, QClassTy, true);
           // warn if instance method found for a Class message.
-          if (Method) {
+          if (Method && !isMethodDeclaredInRootProtocol(*this, Method)) {
             Diag(SelLoc, diag::warn_instance_method_on_class_found)
               << Method->getSelector() << Sel;
             Diag(Method->getLocation(), diag::note_method_declared_at)
index 37df7a641673241a9b0ab6925bb9946d160edebd..d9f954dc473d4e80852b4385d0963cadf3049f1c 100644 (file)
@@ -32,3 +32,30 @@ int main ()
     Class<Test2Protocol> c2 = [c2 alloc]; //  ok
     return 0;
 }
+
+// rdar://22812517
+
+@protocol NSObject
+
+- (int)respondsToSelector:(SEL)aSelector;
+
+@end
+
+__attribute__((objc_root_class))
+@interface NSObject <NSObject>
+
+@end
+
+@protocol OtherProto
+
+- (void)otherInstanceMethod; // expected-note {{method 'otherInstanceMethod' declared here}}
+
+@end
+
+@protocol MyProto <NSObject, OtherProto>
+@end
+
+void allowInstanceMethodsFromRootProtocols(Class<MyProto> c) {
+  [c respondsToSelector: @selector(instanceMethod)]; // no warning
+  [c otherInstanceMethod]; //  expected-warning {{instance method 'otherInstanceMethod' found instead of class method 'otherInstanceMethod'}}
+}