From 80aa1cd7973561889e51c1c152c8990a8de9c953 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 22 Jun 2010 23:20:40 +0000 Subject: [PATCH] Patch to provide separate ASTs for multiple ObjC class extension declarations (implements radar 7928731). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106597 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclObjC.h | 19 ++++++-- lib/AST/ASTContext.cpp | 6 ++- lib/AST/ASTImporter.cpp | 2 + lib/AST/DeclObjC.cpp | 21 +++++--- lib/Frontend/PCHReaderDecl.cpp | 2 + lib/Frontend/PCHWriterDecl.cpp | 1 + lib/Sema/SemaCodeComplete.cpp | 11 ++--- lib/Sema/SemaDeclObjC.cpp | 48 ++++++++----------- lib/Sema/SemaObjCProperty.cpp | 8 +++- .../duplicate-property-class-extension.m | 14 ++++-- 10 files changed, 81 insertions(+), 51 deletions(-) diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 95cab68d12..b0fd4cc96f 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -550,8 +550,8 @@ public: void setCategoryList(ObjCCategoryDecl *category) { CategoryList = category; } - - ObjCCategoryDecl* getClassExtension() const; + + ObjCCategoryDecl* getFirstClassExtension() const; ObjCPropertyDecl *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const; @@ -983,6 +983,7 @@ public: } bool IsClassExtension() const { return getIdentifier() == 0; } + const ObjCCategoryDecl *getNextClassExtension() const; typedef specific_decl_iterator ivar_iterator; ivar_iterator ivar_begin() const { @@ -1308,7 +1309,7 @@ private: SourceLocation AtLoc; // location of @property TypeSourceInfo *DeclType; unsigned PropertyAttributes : 8; - + unsigned PropertyAttributesAsWritten : 8; // @required/@optional unsigned PropertyImplementation : 2; @@ -1322,7 +1323,9 @@ private: ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation AtLocation, TypeSourceInfo *T) : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), DeclType(T), - PropertyAttributes(OBJC_PR_noattr), PropertyImplementation(None), + PropertyAttributes(OBJC_PR_noattr), + PropertyAttributesAsWritten(OBJC_PR_noattr), + PropertyImplementation(None), GetterName(Selector()), SetterName(Selector()), GetterMethodDecl(0), SetterMethodDecl(0) , PropertyIvarDecl(0) {} @@ -1346,6 +1349,14 @@ public: PropertyAttributes |= PRVal; } + PropertyAttributeKind getPropertyAttributesAsWritten() const { + return PropertyAttributeKind(PropertyAttributesAsWritten); + } + + void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) { + PropertyAttributesAsWritten = PRVal; + } + void makeitReadWriteAttribute(void) { PropertyAttributes &= ~OBJC_PR_readonly; PropertyAttributes |= OBJC_PR_readwrite; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index bb62e9efd5..80bda841fe 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -868,7 +868,8 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Ivars) { // Find ivars declared in class extension. - if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { + for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; + CDecl = CDecl->getNextClassExtension()) { for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), E = CDecl->ivar_end(); I != E; ++I) { Ivars.push_back(*I); @@ -933,7 +934,8 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) { unsigned count = 0; // Count ivars declared in class extension. - if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) + for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; + CDecl = CDecl->getNextClassExtension()) count += CDecl->ivar_size(); // Count ivar defined in this class's implementation. This diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 370dbc54a2..e1c2abd251 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2636,6 +2636,8 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { LexicalDC->addDecl(ToProperty); ToProperty->setPropertyAttributes(D->getPropertyAttributes()); + ToProperty->setPropertyAttributesAsWritten( + D->getPropertyAttributesAsWritten()); ToProperty->setGetterName(Importer.Import(D->getGetterName())); ToProperty->setSetterName(Importer.Import(D->getSetterName())); ToProperty->setGetterMethodDecl( diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 335e89bada..adb0e7d083 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -223,17 +223,24 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C); } -/// getClassExtension - Find class extension of the given class. -// FIXME. can speed it up, if need be. -ObjCCategoryDecl* ObjCInterfaceDecl::getClassExtension() const { - const ObjCInterfaceDecl* ClassDecl = this; - for (ObjCCategoryDecl *CDecl = ClassDecl->getCategoryList(); CDecl; +/// getFirstClassExtension - Find first class extension of the given class. +ObjCCategoryDecl* ObjCInterfaceDecl::getFirstClassExtension() const { + for (ObjCCategoryDecl *CDecl = getCategoryList(); CDecl; CDecl = CDecl->getNextClassCategory()) if (CDecl->IsClassExtension()) return CDecl; return 0; } +/// getNextClassCategory - Find next class extension in list of categories. +const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const { + for (const ObjCCategoryDecl *CDecl = getNextClassCategory(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->IsClassExtension()) + return CDecl; + return 0; +} + ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { ObjCInterfaceDecl* ClassDecl = this; @@ -242,11 +249,13 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, clsDeclared = ClassDecl; return I; } - if (const ObjCCategoryDecl *CDecl = ClassDecl->getClassExtension()) + for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); + CDecl; CDecl = CDecl->getNextClassExtension()) { if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) { clsDeclared = ClassDecl; return I; } + } ClassDecl = ClassDecl->getSuperClass(); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index b8046578ae..f723baefef 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -444,6 +444,8 @@ void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // FIXME: stable encoding D->setPropertyAttributes( (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]); + D->setPropertyAttributesAsWritten( + (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]); // FIXME: stable encoding D->setPropertyImplementation( (ObjCPropertyDecl::PropertyControl)Record[Idx++]); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 05414d5fc7..9cc7b4833d 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -425,6 +425,7 @@ void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyAttributes()); + Record.push_back((unsigned)D->getPropertyAttributesAsWritten()); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyImplementation()); Writer.AddDeclarationName(D->getGetterName(), Record); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index f730a3a9ea..2877d52b08 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3929,14 +3929,11 @@ static void FindImplementableMethods(ASTContext &Context, // Add methods from any class extensions (but not from categories; // those should go into category implementations). - for (ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat; - Cat = Cat->getNextClassCategory()) { - if (!Cat->IsClassExtension()) - continue; - - FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType, + for (const ObjCCategoryDecl *Cat = IFace->getFirstClassExtension(); Cat; + Cat = Cat->getNextClassExtension()) + FindImplementableMethods(Context, const_cast(Cat), + WantInstanceMethods, ReturnType, IsInImplementation, KnownMethods); - } } if (ObjCCategoryDecl *Category = dyn_cast(Container)) { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 5a2765c25b..21aeb59a08 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -414,7 +414,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { - ObjCCategoryDecl *CDecl = 0; + ObjCCategoryDecl *CDecl; ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); /// Check that class of this category is already completely declared. @@ -429,28 +429,21 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, return DeclPtrTy::make(CDecl); } - if (!CategoryName) { - // Class extensions require a special treatment. Use an existing one. - // Note that 'getClassExtension()' can return NULL. - CDecl = IDecl->getClassExtension(); - if (IDecl->getImplementation()) { - Diag(ClassLoc, diag::err_class_extension_after_impl) << ClassName; - Diag(IDecl->getImplementation()->getLocation(), - diag::note_implementation_declared); - } + if (!CategoryName && IDecl->getImplementation()) { + Diag(ClassLoc, diag::err_class_extension_after_impl) << ClassName; + Diag(IDecl->getImplementation()->getLocation(), + diag::note_implementation_declared); } - if (!CDecl) { - CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName); - // FIXME: PushOnScopeChains? - CurContext->addDecl(CDecl); + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassLoc, CategoryLoc, CategoryName); + // FIXME: PushOnScopeChains? + CurContext->addDecl(CDecl); - CDecl->setClassInterface(IDecl); - // Insert first use of class extension to the list of class's categories. - if (!CategoryName) - CDecl->insertNextClassCategory(); - } + CDecl->setClassInterface(IDecl); + // Insert class extension to the list of class's categories. + if (!CategoryName) + CDecl->insertNextClassCategory(); // If the interface is deprecated, warn about it. (void)DiagnoseUseOfDecl(IDecl, ClassLoc); @@ -969,13 +962,11 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, I); // Check class extensions (unnamed categories) - for (ObjCCategoryDecl *Categories = I->getCategoryList(); - Categories; Categories = Categories->getNextClassCategory()) { - if (Categories->IsClassExtension()) { - ImplMethodsVsClassMethods(S, IMPDecl, Categories, IncompleteImpl); - break; - } - } + for (const ObjCCategoryDecl *Categories = I->getFirstClassExtension(); + Categories; Categories = Categories->getNextClassExtension()) + ImplMethodsVsClassMethods(S, IMPDecl, + const_cast(Categories), + IncompleteImpl); } else if (ObjCCategoryDecl *C = dyn_cast(CDecl)) { // For extended class, unimplemented methods in its protocols will // be reported in the primary class. @@ -1821,7 +1812,8 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, } // Find ivars to construct/destruct in class extension. - if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { + for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; + CDecl = CDecl->getNextClassExtension()) { for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), E = CDecl->ivar_end(); I != E; ++I) { ObjCIvarDecl *Iv = (*I); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index f25ba640d6..a27d2a8a2f 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -123,6 +123,10 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, CreatePropertyDecl(S, CCPrimary, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, T, MethodImplKind, DC); + // Mark written attribute as having no attribute because + // this is not a user-written property declaration in primary + // class. + PDecl->setPropertyAttributesAsWritten(ObjCPropertyDecl::OBJC_PR_noattr); // A case of continuation class adding a new property in the class. This // is not what it was meant for. However, gcc supports it and so should we. @@ -134,7 +138,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, // The property 'PIDecl's readonly attribute will be over-ridden // with continuation class's readwrite property attribute! - unsigned PIkind = PIDecl->getPropertyAttributes(); + unsigned PIkind = PIDecl->getPropertyAttributesAsWritten(); if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { unsigned retainCopyNonatomic = (ObjCPropertyDecl::OBJC_PR_retain | @@ -266,6 +270,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); + PDecl->setPropertyAttributesAsWritten(PDecl->getPropertyAttributes()); + if (MethodImplKind == tok::objc_required) PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); else if (MethodImplKind == tok::objc_optional) diff --git a/test/SemaObjC/duplicate-property-class-extension.m b/test/SemaObjC/duplicate-property-class-extension.m index bdf4786c76..a84f83f81f 100644 --- a/test/SemaObjC/duplicate-property-class-extension.m +++ b/test/SemaObjC/duplicate-property-class-extension.m @@ -1,13 +1,21 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s @interface Foo -@property (readonly) char foo; +@property (readonly) char foo; // expected-note {{property declared here}} @end @interface Foo () -@property (readwrite) char foo; // expected-note {{property declared here}} +@property (readwrite) char foo; // OK +@property (readwrite) char NewProperty; // expected-note 2 {{property declared here}} @end @interface Foo () -@property (readwrite) char foo; // expected-error {{property has a previous declaration}} +@property (readwrite) char foo; // OK again, make primary property readwrite for 2nd time! +@property (readwrite) char NewProperty; // expected-error {{illegal declaration of property in continuation class 'Foo': attribute must be readwrite, while its primary must be readonly}} @end + +@interface Foo () +@property (readonly) char foo; // expected-error {{illegal declaration of property in continuation class 'Foo': attribute must be readwrite, while its primary must be readonly}} +@property (readwrite) char NewProperty; // expected-error {{illegal declaration of property in continuation class 'Foo': attribute must be readwrite, while its primary must be readonly}} +@end + -- 2.40.0