diff options
-rw-r--r-- | include/clang/AST/DeclObjC.h | 2 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 140 | ||||
-rw-r--r-- | test/SemaObjC/duplicate-property-class-extension.m | 13 |
4 files changed, 110 insertions, 59 deletions
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<ObjCCategoryDecl>(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<ObjCCategoryDecl*>(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); + + /// 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); + 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<ObjCCategoryDecl>(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<ObjCCategoryDecl>(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<ObjCContainerDecl>(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<ObjCImplementationDecl>(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<ObjCCategoryDecl>(ClassDecl)) - if (!CDecl->getIdentifier()) { + if (CDecl->IsClassExtension()) { + // Diagnose if this property is already in continuation class. + DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier()); + if (Found.first != Found.second && isa<ObjCPropertyDecl>(*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<ObjCCategoryDecl>(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 |