diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2013-03-21 20:50:53 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2013-03-21 20:50:53 +0000 |
commit | 5bdaef55d486f20346fe16f3d41324694d3ff0d5 (patch) | |
tree | 42f23dd26e4435d342050b93736733695df10001 | |
parent | cf4bd50c56ece266060bb759351a62251abd16ee (diff) |
Objective-C: Tighten the rules when warning
is issused for on overriding 'readwrite'
property which is not auto-synthesized.
Buttom line is that if hueristics determine
that there will be a user implemented setter,
no warning will be issued. // rdar://13388503
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177662 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclObjC.h | 1 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 66 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 3 | ||||
-rw-r--r-- | test/SemaObjC/default-synthesize-3.m | 31 |
4 files changed, 100 insertions, 1 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 43f255fd04..b6ece31ff0 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -544,6 +544,7 @@ public: ObjCMethodDecl *getClassMethod(Selector Sel) const { return getMethod(Sel, false/*isInstance*/); } + bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const; ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const; diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 97d0870c4b..50bf121af3 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -92,6 +92,72 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { return 0; } +/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter +/// method was found in the class, its protocols, its super classes or categories. +/// It also returns 'true' if one of its categories has declared a 'readwrite' property. +/// This is because, user must provide a setter method for the category's 'readwrite' +/// property. +bool +ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const { + Selector Sel = Property->getSetterName(); + lookup_const_result R = lookup(Sel); + for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end(); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod() && !MD->isImplicit()) + return true; + } + + if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(this)) { + // Also look into categories, including class extensions, looking + // for a user declared instance method. + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = ID->visible_categories_begin(), + CatEnd = ID->visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel)) + if (!MD->isImplicit()) + return true; + if (Cat->IsClassExtension()) + continue; + // Also search through the categories looking for a 'readwrite' declaration + // of this property. If one found, presumably a setter will be provided + // (properties declared in categories will not get auto-synthesized). + for (ObjCContainerDecl::prop_iterator P = Cat->prop_begin(), + E = Cat->prop_end(); P != E; ++P) + if (P->getIdentifier() == Property->getIdentifier()) { + if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) + return true; + break; + } + } + + // Also look into protocols, for a user declared instance method. + for (ObjCInterfaceDecl::all_protocol_iterator P = + ID->all_referenced_protocol_begin(), + PE = ID->all_referenced_protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + if (Proto->HasUserDeclaredSetterMethod(Property)) + return true; + } + // And in its super class. + ObjCInterfaceDecl *OSC = ID->getSuperClass(); + while (OSC) { + if (OSC->HasUserDeclaredSetterMethod(Property)) + return true; + OSC = OSC->getSuperClass(); + } + } + if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(this)) + for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(), + E = PD->protocol_end(); PI != E; ++PI) { + if ((*PI)->HasUserDeclaredSetterMethod(Property)) + return true; + } + return false; +} + ObjCPropertyDecl * ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, IdentifierInfo *propertyID) { diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index aae8ae6e33..121ed8cbb5 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1590,7 +1590,8 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) && (PropInSuperClass->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) && - !IMPDecl->getInstanceMethod(Prop->getSetterName())) { + !IMPDecl->getInstanceMethod(Prop->getSetterName()) && + !IDecl->HasUserDeclaredSetterMethod(Prop)) { Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property) << Prop->getIdentifier()->getName(); Diag(PropInSuperClass->getLocation(), diag::note_property_declare); diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m index 09de765373..82f968da00 100644 --- a/test/SemaObjC/default-synthesize-3.m +++ b/test/SemaObjC/default-synthesize-3.m @@ -80,3 +80,34 @@ __attribute ((objc_requires_property_definitions)) // expected-error {{objc_requ } @end + +// More test where such warnings should not be issued. +@protocol MyProtocol +-(void)setProp1:(id)x; +@end + +@protocol P1 <MyProtocol> +@end + +@interface B +@property (readonly) id prop; +@property (readonly) id prop1; +@property (readonly) id prop2; +@end + +@interface B() +-(void)setProp:(id)x; +@end + +@interface B(cat) +@property (readwrite) id prop2; +@end + +@interface S : B<P1> +@property (assign,readwrite) id prop; +@property (assign,readwrite) id prop1; +@property (assign,readwrite) id prop2; +@end + +@implementation S +@end |