From bd0f432820aba8666db2a736d7fc719e2b803b9f Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Wed, 15 Mar 2017 17:16:41 +0000 Subject: [PATCH] [ObjC][Sema] Avoid warning about a call to an instance method on an 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 | 20 +++++++++++++- test/SemaObjC/class-message-protocol-lookup.m | 27 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 67876c261d..99b31bc755 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -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(M->getDeclContext()); + if (!Protocol) + return false; + const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); + if (const auto *RootClass = dyn_cast_or_null( + 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) diff --git a/test/SemaObjC/class-message-protocol-lookup.m b/test/SemaObjC/class-message-protocol-lookup.m index 37df7a6416..d9f954dc47 100644 --- a/test/SemaObjC/class-message-protocol-lookup.m +++ b/test/SemaObjC/class-message-protocol-lookup.m @@ -32,3 +32,30 @@ int main () Class c2 = [c2 alloc]; // ok return 0; } + +// rdar://22812517 + +@protocol NSObject + +- (int)respondsToSelector:(SEL)aSelector; + +@end + +__attribute__((objc_root_class)) +@interface NSObject + +@end + +@protocol OtherProto + +- (void)otherInstanceMethod; // expected-note {{method 'otherInstanceMethod' declared here}} + +@end + +@protocol MyProto +@end + +void allowInstanceMethodsFromRootProtocols(Class c) { + [c respondsToSelector: @selector(instanceMethod)]; // no warning + [c otherInstanceMethod]; // expected-warning {{instance method 'otherInstanceMethod' found instead of class method 'otherInstanceMethod'}} +} -- 2.40.0