From 79af985badfd591841abe0be09c02ffb683e1df0 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 10 Oct 2012 16:42:38 +0000 Subject: [PATCH] Change Sema::PropertyIfSetterOrGetter to make use of isPropertyAccessor. Old algorithm: 1. See if the name looks like a getter or setter. 2. Use the name to look up a property in the current ObjCContainer and all its protocols. 3. If the current container is an interface, also look in all categories and superclasses (and superclass categories, and so on). New algorithm: 1. See if the method is marked as a property accessor. If so, look through all properties in the current container and find one that has a matching selector. 2. Find all overrides of the method using ObjCMethodDecl's getOverriddenMethods. This collects methods in superclasses and protocols (as well as superclass categories, which isn't really necessary), and checks if THEY are accessors. This part is not done recursively, since getOverriddenMethods is already recursive. This lets us handle getters and setters that do not match the property names. llvm-svn: 165627 --- clang/include/clang/Sema/Sema.h | 3 +- clang/lib/Sema/SemaObjCProperty.cpp | 69 +++++++++++------------ clang/test/SemaObjC/property-deprecated-warning.m | 14 +++++ 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 2a6d4bb..6823e45 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2317,7 +2317,8 @@ public: /// PropertyIfSetterOrGetter - Looks up the property if named declaration /// is a setter or getter method backing a property. - ObjCPropertyDecl *PropertyIfSetterOrGetter(NamedDecl *D); + ObjCPropertyDecl *PropertyIfSetterOrGetter(const NamedDecl *D, + bool CheckOverrides = true); /// Called by ActOnProperty to handle \@property declarations in /// class extensions. diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 8364c07..64dfa56 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1576,44 +1576,43 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, /// PropertyIfSetterOrGetter - Looks up the property if named declaration /// is a setter or getter method backing a property. -ObjCPropertyDecl *Sema::PropertyIfSetterOrGetter(NamedDecl *D) { - if (const ObjCMethodDecl *Method = dyn_cast(D)) { +ObjCPropertyDecl *Sema::PropertyIfSetterOrGetter(const NamedDecl *D, + bool CheckOverrides) { + const ObjCMethodDecl *Method = dyn_cast(D); + if (!Method) + return 0; + + if (Method->isPropertyAccessor()) { + const ObjCContainerDecl *Container = + cast(Method->getParent()); + Selector Sel = Method->getSelector(); - IdentifierInfo *Id = 0; - if (Sel.getNumArgs() == 0) - Id = Sel.getIdentifierInfoForSlot(0); - else if (Sel.getNumArgs() == 1) { - StringRef str = Sel.getNameForSlot(0); - if (str.startswith("set")) { - str = str.substr(3); - char front = str.front(); - front = islower(front) ? toupper(front) : tolower(front); - SmallString<100> PropertyName = str; - PropertyName[0] = front; - Id = &PP.getIdentifierTable().get(PropertyName); - } - } - if (Id) { - if (isa(Method->getDeclContext())) { - const ObjCInterfaceDecl *IDecl = Method->getClassInterface(); - while (IDecl) { - ObjCPropertyDecl *PDecl = - LookupPropertyDecl(cast(IDecl), Id); - if (PDecl) - return PDecl; - for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if ((PDecl = - LookupPropertyDecl(cast(Category), Id))) - return PDecl; - IDecl = IDecl->getSuperClass(); - } - } else if (ObjCPropertyDecl *PDecl = - LookupPropertyDecl( - cast(Method->getDeclContext()), Id)) - return PDecl; + bool IsGetter = (Sel.isUnarySelector()); + + for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(), + E = Container->prop_end(); + I != E; ++I) { + Selector NextSel = IsGetter ? (*I)->getGetterName() + : (*I)->getSetterName(); + if (NextSel == Sel) + return *I; } + + return 0; } + + if (!CheckOverrides) + return 0; + + typedef SmallVector OverridesTy; + OverridesTy Overrides; + Method->getOverriddenMethods(Overrides); + for (OverridesTy::const_iterator I = Overrides.begin(), E = Overrides.end(); + I != E; ++I) { + if (ObjCPropertyDecl *Prop = PropertyIfSetterOrGetter(*I, false)) + return Prop; + } + return 0; } diff --git a/clang/test/SemaObjC/property-deprecated-warning.m b/clang/test/SemaObjC/property-deprecated-warning.m index b3c6620..3e6ffe0 100644 --- a/clang/test/SemaObjC/property-deprecated-warning.m +++ b/clang/test/SemaObjC/property-deprecated-warning.m @@ -2,6 +2,8 @@ // RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s // rdar://12324295 +typedef signed char BOOL; + @protocol P @property(nonatomic,assign) id ptarget __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'ptarget' is declared deprecated here}} @end @@ -36,3 +38,15 @@ [self setPtarget: (id)0]; // expected-warning {{setPtarget:' is deprecated: first deprecated in iOS 3.0}} } @end + + +@interface CustomAccessorNames +@property(getter=isEnabled,assign) BOOL enabled __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{method 'isEnabled' declared here}} expected-note {{property 'enabled' is declared deprecated here}} + +@property(setter=setNewDelegate:,assign) id delegate __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{method 'setNewDelegate:' declared here}} expected-note {{property 'delegate' is declared deprecated here}} +@end + +void testCustomAccessorNames(CustomAccessorNames *obj) { + if ([obj isEnabled]) // expected-warning {{'isEnabled' is deprecated: first deprecated in iOS 3.0}} + [obj setNewDelegate:0]; // expected-warning {{'setNewDelegate:' is deprecated: first deprecated in iOS 3.0}} +} -- 2.7.4