diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 67 | ||||
-rw-r--r-- | test/SemaObjC/iboutlet.m | 15 |
3 files changed, 88 insertions, 0 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8b76ccb134..b3ae3aa4cf 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -711,6 +711,12 @@ def warn_undeclared_selector : Warning< "undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore; def warn_implicit_atomic_property : Warning< "property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore; +def note_auto_readonly_iboutlet_fixup_suggest : Note< + "readonly IBOutlet property should be changed to be readwrite">; +def warn_auto_readonly_iboutlet_property : Warning< + "readonly IBOutlet property when auto-synthesized may " + "not work correctly with 'nib' loader">, + InGroup<DiagGroup<"readonly-iboutlet-property">>; def warn_auto_implicit_atomic_property : Warning< "property is assumed atomic when auto-synthesizing the property">, InGroup<ImplicitAtomic>, DefaultIgnore; diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index f42259c686..44e50852a5 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -200,6 +200,53 @@ makePropertyAttributesAsWritten(unsigned Attributes) { return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten; } +static std::string getPropertyAttributeString(const ObjCPropertyDecl *property, + unsigned Attributes) { + std::string attr; + if (!Attributes) + return attr; + attr = "("; + bool first = true; + if (Attributes & ObjCPropertyDecl::OBJC_PR_readonly) + {attr += !first ? ", readonly" : "readonly"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_readwrite) + {attr += !first ? ", readwrite" : "readwrite"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_getter) + { + if (!first) + attr += ", "; + attr += "getter="; + attr += property->getGetterName().getAsString(); + first = false; + } + if (Attributes & ObjCPropertyDecl::OBJC_PR_setter) + { + if (!first) + attr += ", "; + attr += "setter="; + attr += property->getSetterName().getAsString(); + first = false; + } + if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) + {attr += !first ? ", assign" : "assign"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_retain) + {attr += !first ? ", retain" : "retain"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_strong) + {attr += !first ? ", strong" : "strong"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) + {attr += !first ? ", weak" : "weak"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) + {attr += !first ? ", copy" : "copy"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) + {attr += !first ? ", unsafe_unretained" : "unsafe_unretained"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) + {attr += !first ? ", nonatomic" : "nonatomic"; first = false; } + if (Attributes & ObjCPropertyDecl::OBJC_PR_atomic) + {attr += !first ? ", atomic" : "atomic"; first = false; } + attr += ")"; + return attr; +} + Decl * Sema::HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, @@ -628,6 +675,26 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, return 0; } } + + if (Synthesize&& + (PIkind & ObjCPropertyDecl::OBJC_PR_readonly) && + property->hasAttr<IBOutletAttr>() && + !AtLoc.isValid()) { + unsigned rwPIKind = (PIkind | ObjCPropertyDecl::OBJC_PR_readwrite); + rwPIKind &= (~ObjCPropertyDecl::OBJC_PR_readonly); + Diag(IC->getLocation(), diag::warn_auto_readonly_iboutlet_property); + Diag(property->getLocation(), diag::note_property_declare); + // FIXME. End location must be that of closing ')' which is currently + // unavailable. Need to add it. + SourceLocation endLoc = + property->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); + SourceRange PropSourceRange(property->getLParenLoc(), endLoc); + Diag(property->getLocation(), + diag::note_auto_readonly_iboutlet_fixup_suggest) << + FixItHint::CreateReplacement(PropSourceRange, getPropertyAttributeString(property, + rwPIKind)); + } + } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { if (Synthesize) { Diag(AtLoc, diag::error_synthesize_category_decl); diff --git a/test/SemaObjC/iboutlet.m b/test/SemaObjC/iboutlet.m new file mode 100644 index 0000000000..13e5d53bb0 --- /dev/null +++ b/test/SemaObjC/iboutlet.m @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s +// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify %s +// rdar://11448209 + +@class NSView; + +#define IBOutlet __attribute__((iboutlet)) + +@interface I +@property (getter = MyGetter, readonly, assign) IBOutlet NSView *myView; // expected-note {{property declared here}} \ + // expected-note {{readonly IBOutlet property should be changed to be readwrite}} +@end + +@implementation I // expected-warning {{readonly IBOutlet property when auto-synthesized may not work correctly with 'nib' loader}} +@end |