From: Fariborz Jahanian Date: Wed, 29 Feb 2012 22:18:55 +0000 (+0000) Subject: objective-c: provide fixit hint when atomic property does not X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=77bfb8b43ec3f7dee3a71f6e854b03ad29dab84f;p=clang objective-c: provide fixit hint when atomic property does not have matching user defined setter/getter and a warning is issued. In this case, a fixit note is displayed. // rdar://10267155 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151766 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 3158ef992f..cf46fa4226 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -1737,6 +1737,7 @@ public: enum PropertyControl { None, Required, Optional }; private: SourceLocation AtLoc; // location of @property + SourceLocation LParenLoc; // location of '(' starting attribute list or null. TypeSourceInfo *DeclType; unsigned PropertyAttributes : NumPropertyAttrsBits; unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits; @@ -1751,8 +1752,10 @@ private: ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - SourceLocation AtLocation, TypeSourceInfo *T) - : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), DeclType(T), + SourceLocation AtLocation, SourceLocation LParenLocation, + TypeSourceInfo *T) + : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), + LParenLoc(LParenLocation), DeclType(T), PropertyAttributes(OBJC_PR_noattr), PropertyAttributesAsWritten(OBJC_PR_noattr), PropertyImplementation(None), @@ -1763,6 +1766,7 @@ public: static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation AtLocation, + SourceLocation LParenLocation, TypeSourceInfo *T, PropertyControl propControl = None); @@ -1770,6 +1774,9 @@ public: SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } TypeSourceInfo *getTypeSourceInfo() const { return DeclType; } QualType getType() const { return DeclType->getType(); } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d7ff5491f8..0130bb945c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1957,6 +1957,7 @@ public: //// class extensions. Decl *HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, + SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, @@ -1973,6 +1974,7 @@ public: ObjCPropertyDecl *CreatePropertyDecl(Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc, + SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, @@ -5564,6 +5566,7 @@ public: DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, + SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, bool *OverridingProperty, diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index a7766255d0..0bc50c5f30 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -3544,6 +3544,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { = ObjCPropertyDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), Importer.Import(D->getAtLoc()), + Importer.Import(D->getLParenLoc()), T, D->getPropertyImplementation()); Importer.Imported(D, ToProperty); diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index aa3ac4096c..996e93a8f9 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -1278,15 +1278,17 @@ ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation AtLoc, + SourceLocation LParenLoc, TypeSourceInfo *T, PropertyControl propControl) { - return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T); + return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T); } ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void * Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCPropertyDecl)); return new (Mem) ObjCPropertyDecl(0, SourceLocation(), 0, SourceLocation(), + SourceLocation(), 0); } diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 27bdd0beb1..b135bba488 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -295,13 +295,15 @@ public: SmallVectorImpl &Props; ObjCDeclSpec &OCDS; SourceLocation AtLoc; + SourceLocation LParenLoc; tok::ObjCKeywordKind MethodImplKind; ObjCPropertyCallback(Parser &P, SmallVectorImpl &Props, ObjCDeclSpec &OCDS, SourceLocation AtLoc, + SourceLocation LParenLoc, tok::ObjCKeywordKind MethodImplKind) : - P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), LParenLoc(LParenLoc), MethodImplKind(MethodImplKind) { } @@ -333,7 +335,8 @@ public: FD.D.getIdentifier()); bool isOverridingProperty = false; Decl *Property = - P.Actions.ActOnProperty(P.getCurScope(), AtLoc, FD, OCDS, + P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc, + FD, OCDS, GetterSel, SetterSel, &isOverridingProperty, MethodImplKind); @@ -478,12 +481,15 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, Diag(AtLoc, diag::err_objc_properties_require_objc2); ObjCDeclSpec OCDS; + SourceLocation LParenLoc; // Parse property attribute list, if any. - if (Tok.is(tok::l_paren)) + if (Tok.is(tok::l_paren)) { + LParenLoc = Tok.getLocation(); ParseObjCPropertyAttribute(OCDS); + } ObjCPropertyCallback Callback(*this, allProperties, - OCDS, AtLoc, MethodImplKind); + OCDS, AtLoc, LParenLoc, MethodImplKind); // Parse all the comma separated declarators. DeclSpec DS(AttrFactory); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 8e632b32c0..77458e0cbe 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -101,6 +101,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { } Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, + SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, @@ -135,7 +136,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (ObjCCategoryDecl *CDecl = dyn_cast(ClassDecl)) if (CDecl->IsClassExtension()) { - Decl *Res = HandlePropertyInClassExtension(S, AtLoc, + Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, @@ -150,7 +151,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, return Res; } - ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, @@ -201,7 +202,9 @@ makePropertyAttributesAsWritten(unsigned Attributes) { Decl * Sema::HandlePropertyInClassExtension(Scope *S, - SourceLocation AtLoc, FieldDeclarator &FD, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isAssign, const bool isReadWrite, @@ -235,7 +238,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, // FIXME. We should really be using CreatePropertyDecl for this. ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, T); + PropertyId, AtLoc, LParenLoc, T); PDecl->setPropertyAttributesAsWritten( makePropertyAttributesAsWritten(AttributesAsWritten)); if (Attributes & ObjCDeclSpec::DQ_PR_readonly) @@ -264,7 +267,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, // No matching property found in the primary class. Just fall thru // and add property to continuation class's primary class. ObjCPropertyDecl *PrimaryPDecl = - CreatePropertyDecl(S, CCPrimary, AtLoc, + CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes,AttributesAsWritten, T, MethodImplKind, DC); @@ -329,7 +332,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ContextRAII SavedContext(*this, CCPrimary); Decl *ProtocolPtrTy = - ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, + ActOnProperty(S, AtLoc, LParenLoc, FD, ProtocolPropertyODS, PIDecl->getGetterName(), PIDecl->getSetterName(), isOverridingProperty, @@ -372,6 +375,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc, + SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, @@ -404,7 +408,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, DeclContext *DC = cast(CDecl); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, TInfo); + PropertyId, AtLoc, LParenLoc, TInfo); if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { @@ -1530,7 +1534,34 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, Diag(MethodLoc, diag::warn_atomic_property_rule) << Property->getIdentifier() << (GetterMethod != 0) << (SetterMethod != 0); - Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); + // fixit stuff. + if (!AttributesAsWritten) { + if (Property->getLParenLoc().isValid()) { + // @property () ... case. + SourceRange PropSourceRange(Property->getAtLoc(), + Property->getLParenLoc()); + Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) << + FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic"); + } + else { + //@property id etc. + SourceLocation endLoc = + Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); + endLoc = endLoc.getLocWithOffset(-1); + SourceRange PropSourceRange(Property->getAtLoc(), endLoc); + Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) << + FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic) "); + } + } + else if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) { + // @property () ... case. + SourceLocation endLoc = Property->getLParenLoc(); + SourceRange PropSourceRange(Property->getAtLoc(), endLoc); + Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) << + FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic, "); + } + else + Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); Diag(Property->getLocation(), diag::note_property_declare); } } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index f79c2f51b7..bf22bc89d8 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -801,6 +801,7 @@ void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); D->setAtLoc(ReadSourceLocation(Record, Idx)); + D->setLParenLoc(ReadSourceLocation(Record, Idx)); D->setType(GetTypeSourceInfo(Record, Idx)); // FIXME: stable encoding D->setPropertyAttributes( diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 26ee8b5f2a..1b576aa4d8 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -565,6 +565,7 @@ void ASTDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getAtLoc(), Record); + Writer.AddSourceLocation(D->getLParenLoc(), Record); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyAttributes()); diff --git a/test/SemaObjC/atomoic-property-synnthesis-rules.m b/test/SemaObjC/atomoic-property-synnthesis-rules.m index 2061a779dc..77e2e1a3d0 100644 --- a/test/SemaObjC/atomoic-property-synnthesis-rules.m +++ b/test/SemaObjC/atomoic-property-synnthesis-rules.m @@ -107,8 +107,10 @@ // read-write - might warn @property int GetSet; -@property int Get; // expected-note {{property declared here}} -@property int Set; // expected-note {{property declared here}} +@property int Get; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} +@property int Set; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} @property int None; @property(nonatomic) int GetSet_Nonatomic; @property(nonatomic) int Get_Nonatomic; @@ -127,8 +129,10 @@ // read-only in class, read-write in class extension - might warn @property(readonly) int GetSet_ReadWriteInExt; -@property(readonly) int Get_ReadWriteInExt; // expected-note {{property declared here}} -@property(readonly) int Set_ReadWriteInExt; // expected-note {{property declared here}} +@property(readonly) int Get_ReadWriteInExt; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} +@property(readonly) int Set_ReadWriteInExt; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} @property(readonly) int None_ReadWriteInExt; @property(nonatomic,readonly) int GetSet_Nonatomic_ReadWriteInExt; @property(nonatomic,readonly) int Get_Nonatomic_ReadWriteInExt; @@ -138,8 +142,10 @@ // same as above, but @synthesize follows the hand-written methods - might warn @property int GetSet_LateSynthesize; -@property int Get_LateSynthesize; // expected-note {{property declared here}} -@property int Set_LateSynthesize; // expected-note {{property declared here}} +@property int Get_LateSynthesize; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} +@property int Set_LateSynthesize; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} @property int None_LateSynthesize; @property(nonatomic) int GetSet_Nonatomic_LateSynthesize; @property(nonatomic) int Get_Nonatomic_LateSynthesize; @@ -156,8 +162,10 @@ @property(nonatomic,readonly) int None_Nonatomic_ReadOnly_LateSynthesize; @property(readonly) int GetSet_ReadWriteInExt_LateSynthesize; -@property(readonly) int Get_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} -@property(readonly) int Set_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} +@property(readonly) int Get_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} +@property(readonly) int Set_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \ + // expected-note {{setter and getter must both be synthesized}} @property(readonly) int None_ReadWriteInExt_LateSynthesize; @property(nonatomic,readonly) int GetSet_Nonatomic_ReadWriteInExt_LateSynthesize; @property(nonatomic,readonly) int Get_Nonatomic_ReadWriteInExt_LateSynthesize; @@ -240,10 +248,8 @@ GET(GetSet) SET(GetSet) -GET(Get) // expected-warning {{writable atomic property 'Get' cannot pair a synthesized setter with a user defined getter}} \ - // expected-note {{setter and getter must both be synthesized}} -SET(Set) // expected-warning {{writable atomic property 'Set' cannot pair a synthesized getter with a user defined setter}} \ - // expected-note {{setter and getter must both be synthesized}} +GET(Get) // expected-warning {{writable atomic property 'Get' cannot pair a synthesized setter with a user defined getter}} +SET(Set) // expected-warning {{writable atomic property 'Set' cannot pair a synthesized getter with a user defined setter}} GET(GetSet_Nonatomic) SET(GetSet_Nonatomic) GET(Get_Nonatomic) @@ -260,10 +266,8 @@ SET(Set_Nonatomic_ReadOnly) GET(GetSet_ReadWriteInExt) SET(GetSet_ReadWriteInExt) -GET(Get_ReadWriteInExt) // expected-warning {{writable atomic property 'Get_ReadWriteInExt' cannot pair a synthesized setter with a user defined getter}} \ - // expected-note {{setter and getter must both be synthesized}} -SET(Set_ReadWriteInExt) // expected-warning {{writable atomic property 'Set_ReadWriteInExt' cannot pair a synthesized getter with a user defined setter}} \ - // expected-note {{setter and getter must both be synthesized}} +GET(Get_ReadWriteInExt) // expected-warning {{writable atomic property 'Get_ReadWriteInExt' cannot pair a synthesized setter with a user defined getter}} +SET(Set_ReadWriteInExt) // expected-warning {{writable atomic property 'Set_ReadWriteInExt' cannot pair a synthesized getter with a user defined setter}} GET(GetSet_Nonatomic_ReadWriteInExt) SET(GetSet_Nonatomic_ReadWriteInExt) GET(Get_Nonatomic_ReadWriteInExt) @@ -272,10 +276,8 @@ SET(Set_Nonatomic_ReadWriteInExt) GET(GetSet_LateSynthesize) SET(GetSet_LateSynthesize) -GET(Get_LateSynthesize) // expected-warning {{writable atomic property 'Get_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} \ - // expected-note {{setter and getter must both be synthesized}} -SET(Set_LateSynthesize) // expected-warning {{writable atomic property 'Set_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} \ - // expected-note {{setter and getter must both be synthesized}} +GET(Get_LateSynthesize) // expected-warning {{writable atomic property 'Get_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} +SET(Set_LateSynthesize) // expected-warning {{writable atomic property 'Set_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} GET(GetSet_Nonatomic_LateSynthesize) SET(GetSet_Nonatomic_LateSynthesize) GET(Get_Nonatomic_LateSynthesize) @@ -292,10 +294,8 @@ SET(Set_Nonatomic_ReadOnly_LateSynthesize) GET(GetSet_ReadWriteInExt_LateSynthesize) SET(GetSet_ReadWriteInExt_LateSynthesize) -GET(Get_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Get_ReadWriteInExt_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} \ - // expected-note {{setter and getter must both be synthesized}} -SET(Set_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Set_ReadWriteInExt_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} \ - // expected-note {{setter and getter must both be synthesized}} +GET(Get_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Get_ReadWriteInExt_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} +SET(Set_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Set_ReadWriteInExt_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} GET(GetSet_Nonatomic_ReadWriteInExt_LateSynthesize) SET(GetSet_Nonatomic_ReadWriteInExt_LateSynthesize) GET(Get_Nonatomic_ReadWriteInExt_LateSynthesize)