diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 0bb745a2a33c..3158ef992f33 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -1283,12 +1283,19 @@ class ObjCCategoryDecl : public ObjCContainerDecl { /// \brief The location of the category name in this declaration. SourceLocation CategoryNameLoc; + /// class extension may have private ivars. + SourceLocation IvarLBraceLoc; + SourceLocation IvarRBraceLoc; + ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, - IdentifierInfo *Id, ObjCInterfaceDecl *IDecl) + IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()) : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), ClassInterface(IDecl), NextClassCategory(0), HasSynthBitfield(false), - CategoryNameLoc(CategoryNameLoc) { + CategoryNameLoc(CategoryNameLoc), + IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) { } public: @@ -1297,7 +1304,9 @@ public: SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, IdentifierInfo *Id, - ObjCInterfaceDecl *IDecl); + ObjCInterfaceDecl *IDecl, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()); static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID); ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } @@ -1353,6 +1362,11 @@ public: SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; } void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; } + + void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; } + SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; } + void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; } + SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCCategoryDecl *D) { return true; } @@ -1521,6 +1535,10 @@ class ObjCImplementationDecl : public ObjCImplDecl { virtual void anchor(); /// Implementation Class's super class. ObjCInterfaceDecl *SuperClass; + /// @implementation may have private ivars. + SourceLocation IvarLBraceLoc; + SourceLocation IvarRBraceLoc; + /// Support for ivar initialization. /// IvarInitializers - The arguments used to initialize the ivars CXXCtorInitializer **IvarInitializers; @@ -1535,16 +1553,22 @@ class ObjCImplementationDecl : public ObjCImplDecl { ObjCImplementationDecl(DeclContext *DC, ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *superDecl, - SourceLocation nameLoc, SourceLocation atStartLoc) + SourceLocation nameLoc, SourceLocation atStartLoc, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()) : ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc), - SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0), - HasCXXStructors(false), HasSynthBitfield(false) {} + SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc), + IvarRBraceLoc(IvarRBraceLoc), + IvarInitializers(0), NumIvarInitializers(0), + HasCXXStructors(false), HasSynthBitfield(false){} public: static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *superDecl, SourceLocation nameLoc, - SourceLocation atStartLoc); + SourceLocation atStartLoc, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()); static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -1623,6 +1647,11 @@ public: void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } + void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; } + SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; } + void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; } + SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; } + typedef specific_decl_iterator ivar_iterator; ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index e15bac0b4476..d7e979526d60 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3088,7 +3088,9 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { Loc, Importer.Import(D->getCategoryNameLoc()), Name.getAsIdentifierInfo(), - ToInterface); + ToInterface, + Importer.Import(D->getIvarLBraceLoc()), + Importer.Import(D->getIvarRBraceLoc())); ToCategory->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToCategory); Importer.Imported(D, ToCategory); @@ -3434,7 +3436,9 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { Importer.ImportContext(D->getDeclContext()), Iface, Super, Importer.Import(D->getLocation()), - Importer.Import(D->getAtStartLoc())); + Importer.Import(D->getAtStartLoc()), + Importer.Import(D->getIvarLBraceLoc()), + Importer.Import(D->getIvarRBraceLoc())); if (D->getDeclContext() != D->getLexicalDeclContext()) { DeclContext *LexicalDC diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 6617dc7ac8e6..aa3ac4096cff 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -1070,10 +1070,13 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, IdentifierInfo *Id, - ObjCInterfaceDecl *IDecl) { + ObjCInterfaceDecl *IDecl, + SourceLocation IvarLBraceLoc, + SourceLocation IvarRBraceLoc) { ObjCCategoryDecl *CatDecl = new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id, - IDecl); + IDecl, + IvarLBraceLoc, IvarRBraceLoc); if (IDecl) { // Link this category into its class's category list. CatDecl->NextClassCategory = IDecl->getCategoryList(); @@ -1209,11 +1212,14 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, ObjCInterfaceDecl *ClassInterface, ObjCInterfaceDecl *SuperDecl, SourceLocation nameLoc, - SourceLocation atStartLoc) { + SourceLocation atStartLoc, + SourceLocation IvarLBraceLoc, + SourceLocation IvarRBraceLoc) { if (ClassInterface && ClassInterface->hasDefinition()) ClassInterface = ClassInterface->getDefinition(); return new (C) ObjCImplementationDecl(DC, ClassInterface, SuperDecl, - nameLoc, atStartLoc); + nameLoc, atStartLoc, + IvarLBraceLoc, IvarRBraceLoc); } ObjCImplementationDecl * diff --git a/clang/lib/Rewrite/RewriteModernObjC.cpp b/clang/lib/Rewrite/RewriteModernObjC.cpp index abdb09b2790f..4ba55403cb8e 100644 --- a/clang/lib/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Rewrite/RewriteModernObjC.cpp @@ -934,14 +934,17 @@ void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { // FIXME: handle category headers that are declared across multiple lines. ReplaceText(LocStart, 0, "// "); - + if (CatDecl->getIvarLBraceLoc().isValid()) + InsertText(CatDecl->getIvarLBraceLoc(), "// "); for (ObjCCategoryDecl::ivar_iterator I = CatDecl->ivar_begin(), E = CatDecl->ivar_end(); I != E; ++I) { ObjCIvarDecl *Ivar = (*I); SourceLocation LocStart = Ivar->getLocStart(); ReplaceText(LocStart, 0, "// "); } - + if (CatDecl->getIvarRBraceLoc().isValid()) + InsertText(CatDecl->getIvarRBraceLoc(), "// "); + for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), E = CatDecl->prop_end(); I != E; ++I) RewriteProperty(*I); @@ -1153,12 +1156,16 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { if (IMD) { InsertText(IMD->getLocStart(), "// "); - for (ObjCImplementationDecl::ivar_iterator - I = IMD->ivar_begin(), E = IMD->ivar_end(); I != E; ++I) { - ObjCIvarDecl *Ivar = (*I); - SourceLocation LocStart = Ivar->getLocStart(); - ReplaceText(LocStart, 0, "// "); + if (IMD->getIvarLBraceLoc().isValid()) + InsertText(IMD->getIvarLBraceLoc(), "// "); + for (ObjCImplementationDecl::ivar_iterator + I = IMD->ivar_begin(), E = IMD->ivar_end(); I != E; ++I) { + ObjCIvarDecl *Ivar = (*I); + SourceLocation LocStart = Ivar->getLocStart(); + ReplaceText(LocStart, 0, "// "); } + if (IMD->getIvarRBraceLoc().isValid()) + InsertText(IMD->getIvarRBraceLoc(), "// "); } else InsertText(CID->getLocStart(), "// "); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6c54424c9765..94d8f62ba6dd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9585,6 +9585,8 @@ void Sema::ActOnFields(Scope* S, // Only it is in implementation's lexical context. ClsFields[I]->setLexicalDeclContext(IMPDecl); CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); + IMPDecl->setIvarLBraceLoc(LBrac); + IMPDecl->setIvarRBraceLoc(RBrac); } else if (ObjCCategoryDecl *CDecl = dyn_cast(EnclosingDecl)) { // case of ivars in class extension; all other cases have been @@ -9618,6 +9620,8 @@ void Sema::ActOnFields(Scope* S, ClsFields[i]->setLexicalDeclContext(CDecl); CDecl->addDecl(ClsFields[i]); } + CDecl->setIvarLBraceLoc(LBrac); + CDecl->setIvarRBraceLoc(RBrac); } } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index b7d6a91dfee8..b5e9c3d17940 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -770,6 +770,8 @@ void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { VisitObjCContainerDecl(CD); CD->setCategoryNameLoc(ReadSourceLocation(Record, Idx)); + CD->setIvarLBraceLoc(ReadSourceLocation(Record, Idx)); + CD->setIvarRBraceLoc(ReadSourceLocation(Record, Idx)); // Note that this category has been deserialized. We do this before // deserializing the interface declaration, so that it will consider this @@ -829,6 +831,8 @@ void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); D->setSuperClass(ReadDeclAs(Record, Idx)); + D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx)); + D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx)); llvm::tie(D->IvarInitializers, D->NumIvarInitializers) = Reader.ReadCXXCtorInitializers(F, Record, Idx); D->setHasSynthBitfield(Record[Idx++]); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 584ff1c1442a..f57a166d7ca8 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -541,6 +541,8 @@ void ASTDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { VisitObjCContainerDecl(D); Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); + Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); + Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Writer.AddDeclRef(D->getClassInterface(), Record); Record.push_back(D->protocol_size()); for (ObjCCategoryDecl::protocol_iterator @@ -593,6 +595,8 @@ void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); Writer.AddDeclRef(D->getSuperClass(), Record); + Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); + Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers, Record); Record.push_back(D->hasSynthBitfield()); diff --git a/clang/test/Rewriter/rewrite-modern-class.mm b/clang/test/Rewriter/rewrite-modern-class.mm new file mode 100644 index 000000000000..fd95ab49017c --- /dev/null +++ b/clang/test/Rewriter/rewrite-modern-class.mm @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp + +@protocol PROTO @end + +@interface empty_root @end + +@interface root_with_ivars +{ + id ROOT_IVAR; + id ROOT1_IVAR; +} +@end + +@interface MAXIMAL : root_with_ivars +{ + double D_IVAR; + double D_PROPERTY; +} +- (void) V_METH; +@end + +@implementation MAXIMAL +- (void) V_METH {} +@end +//========================================= +@interface empty_class @end + +@implementation empty_class @end +//========================================= +@interface class_empty_root : empty_root @end + +@implementation class_empty_root @end +//========================================= +@interface class_with_ivars : empty_root +{ + int class_with_ivars_IVAR; +} +@end + +@implementation class_with_ivars @end +//========================================= +@interface class_has_no_ivar : root_with_ivars @end + +@implementation class_has_no_ivar @end + +//============================class needs to be synthesized here===================== +@interface SUPER { +@public + double divar; + SUPER *p_super; +} +@end + +@interface INTF @end + +@implementation INTF +- (SUPER *) Meth : (SUPER *)arg { + return arg->p_super; +} +@end diff --git a/clang/test/Rewriter/rewrite-modern-ivars.mm b/clang/test/Rewriter/rewrite-modern-ivars.mm new file mode 100644 index 000000000000..5e01a44e9574 --- /dev/null +++ b/clang/test/Rewriter/rewrite-modern-ivars.mm @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp + +@protocol P @end +@protocol P1 @end +@interface INTF +{ + id CLASS_IVAR; + id Q_IVAR; + + void (^_block)(id

); + void (*_fptr)(void (^_block)(id

)); + char CLASS_EXT_IVAR; + id (^ext_block)(id

, INTF*, INTF*); + id IMPL_IVAR; + double D_IMPL_IVAR; + INTF

*(*imp_fptr)(void (^_block)(id

, INTF*)); + id arr[100]; +} +@end + +@implementation INTF @end + +@interface MISC_INTF +{ + id CLASS_IVAR; + id Q_IVAR; + + void (^_block)(id

); + void (*_fptr)(void (^_block)(id

)); + unsigned int BF : 8; +} +@end + +@interface MISC_INTF() +{ + char CLASS_EXT_IVAR; + id (^ext_block)(id

, MISC_INTF*, MISC_INTF*); +} +@end + +@interface MISC_INTF() { + int II1; + double DD1; } +@end + +@interface MISC_INTF() { int II2; double DD2; } +@end + +@interface MISC_INTF() { int II3; + double DD3; } +@end + +@interface MISC_INTF() { int II4; double DD4; +} +@end + +@implementation MISC_INTF +{ + id IMPL_IVAR; + double D_IMPL_IVAR; + MISC_INTF

*(*imp_fptr)(void (^_block)(id

, MISC_INTF*)); +} +@end diff --git a/clang/test/Rewriter/rewrite-modern-protocol.mm b/clang/test/Rewriter/rewrite-modern-protocol.mm new file mode 100644 index 000000000000..a4bd617ba6fd --- /dev/null +++ b/clang/test/Rewriter/rewrite-modern-protocol.mm @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp + +@protocol ROOT @end + +@protocol P1 @end + +@protocol P2 @end + +@class NSObject; + +@protocol PROTO +- (id) INST_METHOD; ++ (id) CLASS_METHOD : (id)ARG; +@property id Prop_in_PROTO; +@optional +- (id) opt_instance_method; ++ (id) opt_class_method; +@property (readonly, retain) NSObject *AnotherProperty; +@required +- (id) req; +@optional +- (id) X_opt_instance_method; ++ (id) X_opt_class_method; +@end + +@interface INTF +@end + +@implementation INTF +@end