From 25760611365be23556b32332f8a66ae21ea93ecf Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Mon, 15 Feb 2010 21:55:26 +0000 Subject: [PATCH] Class continuation now has its own property ast for those declared in it. This is to allow duplicate property diagnostics for properties declared in class extensions multiple times (radar 7629420) and for future use. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96276 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclObjC.h | 2 + lib/AST/DeclObjC.cpp | 14 +- lib/Sema/SemaDeclObjC.cpp | 140 +++++++++++------- .../duplicate-property-class-extension.m | 13 ++ 4 files changed, 110 insertions(+), 59 deletions(-) create mode 100644 test/SemaObjC/duplicate-property-class-extension.m diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 994d68b445..e562d352e0 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -949,6 +949,8 @@ public: ClassInterface->setCategoryList(this); } + bool IsClassExtension() const { return getIdentifier() == 0; } + SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation At) { AtLoc = At; } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index ffda505aaa..131e098d04 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -111,8 +111,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { // Look through categories. for (ObjCCategoryDecl *Category = OID->getCategoryList(); Category; Category = Category->getNextClassCategory()) { - if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) - return P; + if (!Category->IsClassExtension()) + if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) + return P; } // Look through protocols. for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), @@ -124,10 +125,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return OID->getSuperClass()->FindPropertyDeclaration(PropertyId); } else if (const ObjCCategoryDecl *OCD = dyn_cast(this)) { // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), - E = OCD->protocol_end(); I != E; ++I) { - if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) - return P; + if (!OCD->IsClassExtension()) + for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), + E = OCD->protocol_end(); I != E; ++I) { + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; } } return 0; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index af51fb10c1..1e9b56a90e 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -446,18 +446,19 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, // Category ObjCCategoryDecl *CatDecl = static_cast(CDecl); assert (CatDecl && "MatchOneProtocolPropertiesInClass"); - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = (*P); - ObjCCategoryDecl::prop_iterator CP, CE; - // Is this property already in category's list of properties? - for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP) - if ((*CP)->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); - } + if (!CatDecl->IsClassExtension()) + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCCategoryDecl::prop_iterator CP, CE; + // Is this property already in category's list of properties? + for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } return; } for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), @@ -596,44 +597,59 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { - ObjCCategoryDecl *CDecl = - ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, - CategoryLoc, CategoryName); - // FIXME: PushOnScopeChains? - CurContext->addDecl(CDecl); - + ObjCCategoryDecl *CDecl = 0; ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) { - CDecl->setInvalidDecl(); - Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return DeclPtrTy::make(CDecl); + if (!CategoryName) { + // Class extensions require a special treatment. Use an existing one. + for (CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->IsClassExtension()) + break; } + if (!CDecl) { + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, + CategoryLoc, CategoryName); + // FIXME: PushOnScopeChains? + CurContext->addDecl(CDecl); - CDecl->setClassInterface(IDecl); + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) { + CDecl->setInvalidDecl(); + Diag(ClassLoc, diag::err_undef_interface) << ClassName; + return DeclPtrTy::make(CDecl); + } + + CDecl->setClassInterface(IDecl); + // Insert first use of 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); - /// Check for duplicate interface declaration for this category - ObjCCategoryDecl *CDeclChain; - for (CDeclChain = IDecl->getCategoryList(); CDeclChain; - CDeclChain = CDeclChain->getNextClassCategory()) { - if (CategoryName && CDeclChain->getIdentifier() == CategoryName) { - Diag(CategoryLoc, diag::warn_dup_category_def) - << ClassName << CategoryName; - Diag(CDeclChain->getLocation(), diag::note_previous_definition); - break; + if (CategoryName) { + /// Check for duplicate interface declaration for this category + ObjCCategoryDecl *CDeclChain; + for (CDeclChain = IDecl->getCategoryList(); CDeclChain; + CDeclChain = CDeclChain->getNextClassCategory()) { + if (CDeclChain->getIdentifier() == CategoryName) { + // Class extensions can be declared multiple times. + Diag(CategoryLoc, diag::warn_dup_category_def) + << ClassName << CategoryName; + Diag(CDeclChain->getLocation(), diag::note_previous_definition); + break; + } } + if (!CDeclChain) + CDecl->insertNextClassCategory(); } - if (!CDeclChain) - CDecl->insertNextClassCategory(); if (NumProtoRefs) { CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); // Protocols in the class extension belong to the class. - if (!CDecl->getIdentifier()) + if (CDecl->IsClassExtension()) IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); @@ -1102,11 +1118,12 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, CollectImmediateProperties((*PI), PropMap); } if (ObjCCategoryDecl *CATDecl = dyn_cast(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), - E = CATDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - PropMap[Prop->getIdentifier()] = Prop; - } + if (!CATDecl->IsClassExtension()) + for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), + E = CATDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } // scan through class's protocols. for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), E = CATDecl->protocol_end(); PI != E; ++PI) @@ -1261,7 +1278,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // Check class extensions (unnamed categories) for (ObjCCategoryDecl *Categories = I->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { - if (!Categories->getIdentifier()) { + if (Categories->IsClassExtension()) { ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); break; } @@ -1269,7 +1286,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, } else if (ObjCCategoryDecl *C = dyn_cast(CDecl)) { // For extended class, unimplemented methods in its protocols will // be reported in the primary class. - if (C->getIdentifier()) { + if (!C->IsClassExtension()) { for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, @@ -1826,17 +1843,18 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, // Compare protocol properties with those in category CompareProperties(C, DeclPtrTy::make(C)); - if (C->getIdentifier() == 0) + if (C->IsClassExtension()) DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); } if (ObjCContainerDecl *CDecl = dyn_cast(ClassDecl)) { - // ProcessPropertyDecl is responsible for diagnosing conflicts with any - // user-defined setter/getter. It also synthesizes setter/getter methods - // and adds them to the DeclContext and global method pools. - for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), - E = CDecl->prop_end(); - I != E; ++I) - ProcessPropertyDecl(*I, CDecl); + if (CDecl->getIdentifier()) + // ProcessPropertyDecl is responsible for diagnosing conflicts with any + // user-defined setter/getter. It also synthesizes setter/getter methods + // and adds them to the DeclContext and global method pools. + for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), + E = CDecl->prop_end(); + I != E; ++I) + ProcessPropertyDecl(*I, CDecl); CDecl->setAtEndRange(AtEnd); } if (ObjCImplementationDecl *IC=dyn_cast(ClassDecl)) { @@ -2137,7 +2155,22 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // May modify Attributes. CheckObjCPropertyAttributes(T, AtLoc, Attributes); if (ObjCCategoryDecl *CDecl = dyn_cast(ClassDecl)) - if (!CDecl->getIdentifier()) { + if (CDecl->IsClassExtension()) { + // Diagnose if this property is already in continuation class. + DeclContext *DC = dyn_cast(ClassDecl); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier()); + if (Found.first != Found.second && isa(*Found.first)) { + Diag(AtLoc, diag::err_duplicate_property); + Diag((*Found.first)->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, + FD.D.getIdentifierLoc(), + FD.D.getIdentifier(), + AtLoc, T); + DC->addDecl(PDecl); + // This is a continuation class. property requires special // handling. if ((CCPrimary = CDecl->getClassInterface())) { @@ -2201,6 +2234,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, ProcessPropertyDecl(PIDecl, CCPrimary); return DeclPtrTy(); } + // No matching property found in the primary class. Just fall thru // and add property to continuation class's primary class. ClassDecl = CCPrimary; @@ -2354,7 +2388,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, } if (const ObjCCategoryDecl *CD = dyn_cast(property->getDeclContext())) { - if (CD->getIdentifier()) { + if (!CD->IsClassExtension()) { Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); Diag(property->getLocation(), diag::note_property_declare); return DeclPtrTy(); diff --git a/test/SemaObjC/duplicate-property-class-extension.m b/test/SemaObjC/duplicate-property-class-extension.m new file mode 100644 index 0000000000..bdf4786c76 --- /dev/null +++ b/test/SemaObjC/duplicate-property-class-extension.m @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@interface Foo +@property (readonly) char foo; +@end + +@interface Foo () +@property (readwrite) char foo; // expected-note {{property declared here}} +@end + +@interface Foo () +@property (readwrite) char foo; // expected-error {{property has a previous declaration}} +@end