From 2fb325091a8e9d790e17bdab8db240262b3ebfd9 Mon Sep 17 00:00:00 2001 From: Manman Ren <manman.ren@gmail.com> Date: Wed, 18 May 2016 18:12:34 +0000 Subject: [PATCH] ObjectiveC Class Properties: warn if a class property accessor is mistakenly an instance method. When diagnosing unimplemented class property, make sure we emit a warning when we only see an instance method with the right selector. Also warn when we only see a class method for an instance property. rdar://26141719 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@269968 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaObjCProperty.cpp | 28 ++++++++++++++++------------ test/SemaObjC/objc-class-property.m | 13 +++++++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 1bf88f4e939..f9c495d6419 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1763,19 +1763,23 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { DefaultSynthesizeProperties(S, IC, IDecl); } -static void DiagnoseUnimplementedAccessor(Sema &S, - ObjCInterfaceDecl *PrimaryClass, - Selector Method, - ObjCImplDecl* IMPDecl, - ObjCContainerDecl *CDecl, - ObjCCategoryDecl *C, - ObjCPropertyDecl *Prop, - Sema::SelectorSet &SMap) { +static void DiagnoseUnimplementedAccessor( + Sema &S, ObjCInterfaceDecl *PrimaryClass, Selector Method, + ObjCImplDecl *IMPDecl, ObjCContainerDecl *CDecl, ObjCCategoryDecl *C, + ObjCPropertyDecl *Prop, + llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) { + // Check to see if we have a corresponding selector in SMap and with the + // right method type. + auto I = std::find_if(SMap.begin(), SMap.end(), + [&](const ObjCMethodDecl *x) { + return x->getSelector() == Method && + x->isClassMethod() == Prop->isClassProperty(); + }); // When reporting on missing property setter/getter implementation in // categories, do not report when they are declared in primary class, // class's protocol, or one of it super classes. This is because, // the class is going to implement them. - if (!SMap.count(Method) && + if (I == SMap.end() && (PrimaryClass == nullptr || !PrimaryClass->lookupPropertyAccessor(Method, C, Prop->isClassProperty()))) { @@ -1867,10 +1871,10 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, for (const auto *I : IMPDecl->property_impls()) PropImplMap.insert(I->getPropertyDecl()); - SelectorSet InsMap; + llvm::SmallPtrSet<const ObjCMethodDecl *, 8> InsMap; // Collect property accessors implemented in current implementation. for (const auto *I : IMPDecl->methods()) - InsMap.insert(I->getSelector()); + InsMap.insert(I); ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl); ObjCInterfaceDecl *PrimaryClass = nullptr; @@ -1882,7 +1886,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, // setter/getter is implemented in category's primary class // implementation. for (const auto *I : IMP->methods()) - InsMap.insert(I->getSelector()); + InsMap.insert(I); } for (ObjCContainerDecl::PropertyMap::iterator diff --git a/test/SemaObjC/objc-class-property.m b/test/SemaObjC/objc-class-property.m index 5e1b866cbc8..f6733574c09 100644 --- a/test/SemaObjC/objc-class-property.m +++ b/test/SemaObjC/objc-class-property.m @@ -43,3 +43,16 @@ void message_id(id me) { void message_class(Class me) { [me c2]; } + +@interface NSObject +@end + +@interface MyClass : NSObject +@property(class, readonly) int classProp; // expected-note {{property declared here}} +@end + +@implementation MyClass // expected-warning {{class property 'classProp' requires method 'classProp' to be defined}} +- (int)classProp { // Oops, mistakenly made this an instance method. + return 8; +} +@end -- GitLab