From 974c9480498680866e19a10dfb09fd2b96b864f3 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 21 Sep 2012 20:46:37 +0000 Subject: [PATCH] objective-C: when diagnosing deprecated/unavailable usage of setter or getter backing a deprecated/unavailable property, also not location of the property. // rdar://12324295 llvm-svn: 164412 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 + clang/include/clang/Sema/DelayedDiagnostic.h | 6 +++ clang/include/clang/Sema/Sema.h | 7 ++- clang/lib/Sema/DelayedDiagnostic.cpp | 2 + clang/lib/Sema/SemaDeclAttr.cpp | 18 ++++++-- clang/lib/Sema/SemaExpr.cpp | 24 +++++++--- clang/lib/Sema/SemaObjCProperty.cpp | 53 +++++++++++++++++++++++ clang/test/SemaObjC/arc-system-header.m | 2 +- clang/test/SemaObjC/attr-deprecated.m | 3 +- clang/test/SemaObjC/property-deprecated-warning.m | 38 ++++++++++++++++ 10 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 clang/test/SemaObjC/property-deprecated-warning.m diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 1f5804f0..86d00c2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -588,6 +588,8 @@ def warn_accessor_property_type_mismatch : Warning< "type of property %0 does not match type of accessor %1">; def not_conv_function_declared_at : Note<"type conversion function declared here">; def note_method_declared_at : Note<"method %0 declared here">; +def note_property_attribute : Note<"property %0 is declared " + "%select{deprecated|unavailable}1 here">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; def warn_duplicate_method_decl : diff --git a/clang/include/clang/Sema/DelayedDiagnostic.h b/clang/include/clang/Sema/DelayedDiagnostic.h index 1ee8a0d..a20480c 100644 --- a/clang/include/clang/Sema/DelayedDiagnostic.h +++ b/clang/include/clang/Sema/DelayedDiagnostic.h @@ -124,6 +124,7 @@ public: static DelayedDiagnostic makeDeprecation(SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, StringRef Msg); static DelayedDiagnostic makeAccess(SourceLocation Loc, @@ -193,12 +194,17 @@ public: return DeprecationData.UnknownObjCClass; } + const ObjCPropertyDecl *getObjCProperty() const { + return DeprecationData.ObjCProperty; + } + private: union { /// Deprecation. struct { const NamedDecl *Decl; const ObjCInterfaceDecl *UnknownObjCClass; + const ObjCPropertyDecl *ObjCProperty; const char *Message; size_t MessageLen; } DeprecationData; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 25e8b45..74114a8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2295,6 +2295,10 @@ public: /// its protocols. ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, IdentifierInfo *II); + + /// PropertyIfSetterOrGetter - Looks up the property if named declaration + /// is a setter or getter method backing a property. + ObjCPropertyDecl *PropertyIfSetterOrGetter(NamedDecl *D); /// Called by ActOnProperty to handle \@property declarations in /// class extensions. @@ -2686,7 +2690,8 @@ public: void EmitDeprecationWarning(NamedDecl *D, StringRef Message, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass=0); + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty); void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); diff --git a/clang/lib/Sema/DelayedDiagnostic.cpp b/clang/lib/Sema/DelayedDiagnostic.cpp index 876f9d7..3100432 100644 --- a/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/clang/lib/Sema/DelayedDiagnostic.cpp @@ -22,6 +22,7 @@ using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, StringRef Msg) { DelayedDiagnostic DD; DD.Kind = Deprecation; @@ -29,6 +30,7 @@ DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc, DD.Loc = Loc; DD.DeprecationData.Decl = D; DD.DeprecationData.UnknownObjCClass = UnknownObjCClass; + DD.DeprecationData.ObjCProperty = ObjCProperty; char *MessageData = 0; if (Msg.size()) { MessageData = new char [Msg.size()]; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ae394d7..b09ec08 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4803,18 +4803,25 @@ static bool isDeclDeprecated(Decl *D) { static void DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass) { + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCPropery) { DeclarationName Name = D->getDeclName(); if (!Message.empty()) { S.Diag(Loc, diag::warn_deprecated_message) << Name << Message; S.Diag(D->getLocation(), isa(D) ? diag::note_method_declared_at : diag::note_previous_decl) << Name; + if (ObjCPropery) + S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute) + << ObjCPropery->getDeclName() << 0; } else if (!UnknownObjCClass) { S.Diag(Loc, diag::warn_deprecated) << D->getDeclName(); S.Diag(D->getLocation(), isa(D) ? diag::note_method_declared_at : diag::note_previous_decl) << Name; + if (ObjCPropery) + S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute) + << ObjCPropery->getDeclName() << 0; } else { S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); @@ -4829,16 +4836,19 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, DD.Triggered = true; DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, - DD.getUnknownObjCClass()); + DD.getUnknownObjCClass(), + DD.getObjCProperty()); } void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass) { + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty) { // Delay if we're currently parsing a declaration. if (DelayedDiagnostics.shouldDelayDiagnostics()) { DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, UnknownObjCClass, + ObjCProperty, Message)); return; } @@ -4846,5 +4856,5 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, // Otherwise, don't warn if our current context is deprecated. if (isDeclDeprecated(cast(getCurLexicalContext()))) return; - DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass); + DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass, ObjCProperty); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 97591be..ff7e910 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -87,6 +87,13 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, if (const EnumDecl *TheEnumDecl = dyn_cast(DC)) Result = TheEnumDecl->getAvailability(&Message); } + const ObjCPropertyDecl *ObjCPDecl = 0; + if (Result == AR_Deprecated || Result == AR_Unavailable) + if (ObjCPropertyDecl *ND = S.PropertyIfSetterOrGetter(D)) { + AvailabilityResult PDeclResult = ND->getAvailability(0); + if (PDeclResult == Result) + ObjCPDecl = ND; + } switch (Result) { case AR_Available: @@ -94,23 +101,30 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, break; case AR_Deprecated: - S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); + S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass, ObjCPDecl); break; case AR_Unavailable: if (S.getCurContextAvailability() != AR_Unavailable) { if (Message.empty()) { - if (!UnknownObjCClass) + if (!UnknownObjCClass) { S.Diag(Loc, diag::err_unavailable) << D->getDeclName(); + if (ObjCPDecl) + S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute) + << ObjCPDecl->getDeclName() << 1; + } else S.Diag(Loc, diag::warn_unavailable_fwdclass_message) << D->getDeclName(); } - else + else S.Diag(Loc, diag::err_unavailable_message) << D->getDeclName() << Message; - S.Diag(D->getLocation(), diag::note_unavailable_here) - << isa(D) << false; + S.Diag(D->getLocation(), diag::note_unavailable_here) + << isa(D) << false; + if (ObjCPDecl) + S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute) + << ObjCPDecl->getDeclName() << 1; } break; } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 0f6ae4c..82b8094 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -22,6 +22,7 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" +#include "clang/Lex/Preprocessor.h" using namespace clang; @@ -1560,6 +1561,58 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, return Prop; } } + else if (const ObjCCategoryDecl *CatDecl = + dyn_cast(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = CatDecl->prop_begin(), + E = CatDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + if (Prop->getIdentifier() == II) + return Prop; + } + } + return 0; +} + +/// 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)) { + 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; + } + } return 0; } diff --git a/clang/test/SemaObjC/arc-system-header.m b/clang/test/SemaObjC/arc-system-header.m index 1a7c39d..3443bda 100644 --- a/clang/test/SemaObjC/arc-system-header.m +++ b/clang/test/SemaObjC/arc-system-header.m @@ -38,7 +38,7 @@ id test6() { x = (id) (test6_helper(), kMagicConstant); } -// workaround expected-note 4 {{marked unavailable here}} +// workaround expected-note 4 {{marked unavailable here}} expected-note 2 {{property 'prop' is declared unavailable here}} void test7(Test7 *p) { *p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}} p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}} diff --git a/clang/test/SemaObjC/attr-deprecated.m b/clang/test/SemaObjC/attr-deprecated.m index 260462a..c0aa9fc 100644 --- a/clang/test/SemaObjC/attr-deprecated.m +++ b/clang/test/SemaObjC/attr-deprecated.m @@ -107,7 +107,8 @@ __attribute ((deprecated)) @interface Test2 -@property int test2 __attribute__((deprecated)); // expected-note 4 {{declared here}} +@property int test2 __attribute__((deprecated)); // expected-note 4 {{declared here}} \ + // expected-note 2 {{property 'test2' is declared deprecated here}} @end void test(Test2 *foo) { diff --git a/clang/test/SemaObjC/property-deprecated-warning.m b/clang/test/SemaObjC/property-deprecated-warning.m new file mode 100644 index 0000000..b3c6620 --- /dev/null +++ b/clang/test/SemaObjC/property-deprecated-warning.m @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s +// rdar://12324295 + +@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 + +@protocol P1

+- (void)setPtarget:(id)arg; // expected-note {{method 'setPtarget:' declared here}} +@end + + +@interface UITableViewCell +@property(nonatomic,assign) id target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'target' is declared deprecated here}} +@end + +@interface PSTableCell : UITableViewCell + - (void)setTarget:(id)target; // expected-note {{method 'setTarget:' declared here}} +@end + +@interface UITableViewCell(UIDeprecated) +@property(nonatomic,assign) id dep_target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{method 'dep_target' declared here}} \ + // expected-note 2 {{property 'dep_target' is declared deprecated here}} \ + // expected-note {{method 'setDep_target:' declared here}} +@end + +@implementation PSTableCell +- (void)setTarget:(id)target {}; +- (void)setPtarget:(id)val {}; +- (void) Meth { + [self setTarget: (id)0]; // expected-warning {{'setTarget:' is deprecated: first deprecated in iOS 3.0}} + [self setDep_target: [self dep_target]]; // expected-warning {{'dep_target' is deprecated: first deprecated in iOS 3.0}} \ + // expected-warning {{'setDep_target:' is deprecated: first deprecated in iOS 3.0}} + + [self setPtarget: (id)0]; // expected-warning {{setPtarget:' is deprecated: first deprecated in iOS 3.0}} +} +@end -- 2.7.4