From 3f88afad2f5de0fc78c9670d1779f3851573f331 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 24 May 2012 22:48:38 +0000 Subject: [PATCH] objective-c: warn on use of property setters backing two propeties because proprty names match except for first letter being of different case. // rdar://11528439, [PR12936]. llvm-svn: 157435 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/Sema/SemaExprObjC.cpp | 11 +++++------ clang/lib/Sema/SemaPseudoObject.cpp | 24 +++++++++++++++++++++--- clang/test/SemaObjC/property-user-setter.m | 14 ++++++++++---- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 845de19..e9f6dec 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -626,6 +626,10 @@ def warn_missing_explicit_synthesis : Warning < def warn_property_getter_owning_mismatch : Warning< "property declared as returning non-retained objects" "; getter returning retained objects">; +def warn_property_setter_ambiguous_use : Warning< + "synthesized properties '%0' and '%1' both claim setter %2 -" + " use of this setter may cause unexpected behavior">, + InGroup>; def err_ownin_getter_rule : Error< "property's synthesized getter follows Cocoa naming" " convention for returning 'owned' objects">; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 52e093c..9ce0faf 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1415,8 +1415,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, return ExprError(); // Search for a declared property first. - ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member); - if (PD) { + if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); @@ -1484,11 +1483,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, SelectorTable::constructSetterName(PP.getIdentifierTable(), PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); - // Check for corner case of: @property int p; ... self.P = 0; - // setter name is synthesized "setP" but there is no property name 'P'. - if (Setter && Setter->isSynthesized() && !PD) + if (Setter && Setter->isSynthesized()) + // Check for corner case of: @property int p; ... self.P = 0; + // setter name is synthesized "setP" but there is no property name 'P'. Setter = 0; - + // May be founf in property's qualified list. if (!Setter) Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 5e44c9bb..82bf79b 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -34,6 +34,7 @@ #include "clang/Sema/Initialization.h" #include "clang/AST/ExprObjC.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" using namespace clang; using namespace sema; @@ -232,7 +233,7 @@ namespace { Expr *op); bool tryBuildGetOfReference(Expr *op, ExprResult &result); - bool findSetter(); + bool findSetter(bool warn=true); bool findGetter(); Expr *rebuildAndCaptureObject(Expr *syntacticBase); @@ -505,7 +506,7 @@ bool ObjCPropertyOpBuilder::findGetter() { /// reference. /// /// \return true if a setter was found, in which case Setter -bool ObjCPropertyOpBuilder::findSetter() { +bool ObjCPropertyOpBuilder::findSetter(bool warn) { // For implicit properties, just trust the lookup we already did. if (RefExpr->isImplicitProperty()) { if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) { @@ -531,6 +532,23 @@ bool ObjCPropertyOpBuilder::findSetter() { // Do a normal method lookup first. if (ObjCMethodDecl *setter = LookupMethodInReceiverType(S, SetterSelector, RefExpr)) { + if (setter->isSynthesized() && warn) + if (const ObjCInterfaceDecl *IFace = + dyn_cast(setter->getDeclContext())) { + const StringRef thisPropertyName(prop->getName()); + char front = thisPropertyName.front(); + front = islower(front) ? toupper(front) : tolower(front); + SmallString<100> PropertyName = thisPropertyName; + PropertyName[0] = front; + IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName); + if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember)) + if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) { + S.Diag(RefExpr->getExprLoc(), diag::warn_property_setter_ambiguous_use) + << prop->getName() << prop1->getName() << setter->getSelector(); + S.Diag(prop->getLocation(), diag::note_property_declare); + S.Diag(prop1->getLocation(), diag::note_property_declare); + } + } Setter = setter; return true; } @@ -603,7 +621,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { /// value being set as the value of the property operation. ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, bool captureSetValueAsResult) { - bool hasSetter = findSetter(); + bool hasSetter = findSetter(false); assert(hasSetter); (void) hasSetter; if (SyntacticRefExpr) diff --git a/clang/test/SemaObjC/property-user-setter.m b/clang/test/SemaObjC/property-user-setter.m index d977d15..736f2ad 100644 --- a/clang/test/SemaObjC/property-user-setter.m +++ b/clang/test/SemaObjC/property-user-setter.m @@ -111,8 +111,10 @@ int main (void) { @property (copy) id p; @property (copy) id r; @property (copy) id Q; -@property (copy) id t; -@property (copy) id T; +@property (copy) id t; // expected-note 2 {{property declared here}} +@property (copy) id T; // expected-note 2 {{property declared here}} +@property (copy) id Pxyz; // expected-note 2 {{property declared here}} +@property (copy) id pxyz; // expected-note 2 {{property declared here}} @end @implementation rdar11363363 @@ -120,11 +122,15 @@ int main (void) { @synthesize r; @synthesize Q; @synthesize t, T; +@synthesize Pxyz, pxyz; - (id) Meth { self.P = 0; // expected-error {{property 'P' not found on object of type 'rdar11363363 *'}} self.q = 0; // expected-error {{property 'q' not found on object of type 'rdar11363363 *'}} - self.t = 0; // OK - self.T = 0; // OK +// rdar://11528439 + self.t = 0; // expected-warning {{synthesized properties 't' and 'T' both claim setter 'setT:'}} + self.T = 0; // expected-warning {{synthesized properties 'T' and 't' both claim setter 'setT:'}} + self.Pxyz = 0; // expected-warning {{synthesized properties 'Pxyz' and 'pxyz' both claim setter 'setPxyz:'}} + self.pxyz = 0; // expected-warning {{synthesized properties 'pxyz' and 'Pxyz' both claim setter 'setPxyz:'}} self.R = 0; // expected-error {{property 'R' not found on object of type 'rdar11363363 *'; did you mean to access ivar 'R'?}} return self.R; // expected-error {{property 'R' not found on object of type 'rdar11363363 *'; did you mean to access ivar 'R'?}} } -- 2.7.4