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
This commit is contained in:
Fariborz Jahanian 2010-02-15 21:55:26 +00:00
Родитель aad49232a7
Коммит 2576061136
4 изменённых файлов: 110 добавлений и 59 удалений

Просмотреть файл

@ -949,6 +949,8 @@ public:
ClassInterface->setCategoryList(this); ClassInterface->setCategoryList(this);
} }
bool IsClassExtension() const { return getIdentifier() == 0; }
SourceLocation getAtLoc() const { return AtLoc; } SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation At) { AtLoc = At; } void setAtLoc(SourceLocation At) { AtLoc = At; }

Просмотреть файл

@ -111,8 +111,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
// Look through categories. // Look through categories.
for (ObjCCategoryDecl *Category = OID->getCategoryList(); for (ObjCCategoryDecl *Category = OID->getCategoryList();
Category; Category = Category->getNextClassCategory()) { Category; Category = Category->getNextClassCategory()) {
if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) if (!Category->IsClassExtension())
return P; if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
return P;
} }
// Look through protocols. // Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
@ -124,10 +125,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
return OID->getSuperClass()->FindPropertyDeclaration(PropertyId); return OID->getSuperClass()->FindPropertyDeclaration(PropertyId);
} else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) { } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) {
// Look through protocols. // Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), if (!OCD->IsClassExtension())
E = OCD->protocol_end(); I != E; ++I) { for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) E = OCD->protocol_end(); I != E; ++I) {
return P; if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
} }
} }
return 0; return 0;

Просмотреть файл

@ -446,18 +446,19 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
// Category // Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
assert (CatDecl && "MatchOneProtocolPropertiesInClass"); assert (CatDecl && "MatchOneProtocolPropertiesInClass");
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), if (!CatDecl->IsClassExtension())
E = PDecl->prop_end(); P != E; ++P) { for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
ObjCPropertyDecl *Pr = (*P); E = PDecl->prop_end(); P != E; ++P) {
ObjCCategoryDecl::prop_iterator CP, CE; ObjCPropertyDecl *Pr = (*P);
// Is this property already in category's list of properties? ObjCCategoryDecl::prop_iterator CP, CE;
for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP) // Is this property already in category's list of properties?
if ((*CP)->getIdentifier() == Pr->getIdentifier()) for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
break; if ((*CP)->getIdentifier() == Pr->getIdentifier())
if (CP != CE) break;
// Property protocol already exist in class. Diagnose any mismatch. if (CP != CE)
DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); // Property protocol already exist in class. Diagnose any mismatch.
} DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
}
return; return;
} }
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
@ -596,44 +597,59 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
unsigned NumProtoRefs, unsigned NumProtoRefs,
const SourceLocation *ProtoLocs, const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc) { SourceLocation EndProtoLoc) {
ObjCCategoryDecl *CDecl = ObjCCategoryDecl *CDecl = 0;
ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
CategoryLoc, CategoryName);
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
/// Check that class of this category is already completely declared. if (!CategoryName) {
if (!IDecl || IDecl->isForwardDecl()) { // Class extensions require a special treatment. Use an existing one.
CDecl->setInvalidDecl(); for (CDecl = IDecl->getCategoryList(); CDecl;
Diag(ClassLoc, diag::err_undef_interface) << ClassName; CDecl = CDecl->getNextClassCategory())
return DeclPtrTy::make(CDecl); 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. // If the interface is deprecated, warn about it.
(void)DiagnoseUseOfDecl(IDecl, ClassLoc); (void)DiagnoseUseOfDecl(IDecl, ClassLoc);
/// Check for duplicate interface declaration for this category if (CategoryName) {
ObjCCategoryDecl *CDeclChain; /// Check for duplicate interface declaration for this category
for (CDeclChain = IDecl->getCategoryList(); CDeclChain; ObjCCategoryDecl *CDeclChain;
CDeclChain = CDeclChain->getNextClassCategory()) { for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
if (CategoryName && CDeclChain->getIdentifier() == CategoryName) { CDeclChain = CDeclChain->getNextClassCategory()) {
Diag(CategoryLoc, diag::warn_dup_category_def) if (CDeclChain->getIdentifier() == CategoryName) {
<< ClassName << CategoryName; // Class extensions can be declared multiple times.
Diag(CDeclChain->getLocation(), diag::note_previous_definition); Diag(CategoryLoc, diag::warn_dup_category_def)
break; << ClassName << CategoryName;
Diag(CDeclChain->getLocation(), diag::note_previous_definition);
break;
}
} }
if (!CDeclChain)
CDecl->insertNextClassCategory();
} }
if (!CDeclChain)
CDecl->insertNextClassCategory();
if (NumProtoRefs) { if (NumProtoRefs) {
CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context); ProtoLocs, Context);
// Protocols in the class extension belong to the class. // Protocols in the class extension belong to the class.
if (!CDecl->getIdentifier()) if (CDecl->IsClassExtension())
IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
NumProtoRefs, ProtoLocs, NumProtoRefs, ProtoLocs,
Context); Context);
@ -1102,11 +1118,12 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
CollectImmediateProperties((*PI), PropMap); CollectImmediateProperties((*PI), PropMap);
} }
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), if (!CATDecl->IsClassExtension())
E = CATDecl->prop_end(); P != E; ++P) { for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
ObjCPropertyDecl *Prop = (*P); E = CATDecl->prop_end(); P != E; ++P) {
PropMap[Prop->getIdentifier()] = Prop; ObjCPropertyDecl *Prop = (*P);
} PropMap[Prop->getIdentifier()] = Prop;
}
// scan through class's protocols. // scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
E = CATDecl->protocol_end(); PI != E; ++PI) E = CATDecl->protocol_end(); PI != E; ++PI)
@ -1261,7 +1278,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
// Check class extensions (unnamed categories) // Check class extensions (unnamed categories)
for (ObjCCategoryDecl *Categories = I->getCategoryList(); for (ObjCCategoryDecl *Categories = I->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) { Categories; Categories = Categories->getNextClassCategory()) {
if (!Categories->getIdentifier()) { if (Categories->IsClassExtension()) {
ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
break; break;
} }
@ -1269,7 +1286,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For extended class, unimplemented methods in its protocols will // For extended class, unimplemented methods in its protocols will
// be reported in the primary class. // be reported in the primary class.
if (C->getIdentifier()) { if (!C->IsClassExtension()) {
for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
E = C->protocol_end(); PI != E; ++PI) E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
@ -1826,17 +1843,18 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
// Compare protocol properties with those in category // Compare protocol properties with those in category
CompareProperties(C, DeclPtrTy::make(C)); CompareProperties(C, DeclPtrTy::make(C));
if (C->getIdentifier() == 0) if (C->IsClassExtension())
DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); DiagnoseClassExtensionDupMethods(C, C->getClassInterface());
} }
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) { if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) {
// ProcessPropertyDecl is responsible for diagnosing conflicts with any if (CDecl->getIdentifier())
// user-defined setter/getter. It also synthesizes setter/getter methods // ProcessPropertyDecl is responsible for diagnosing conflicts with any
// and adds them to the DeclContext and global method pools. // user-defined setter/getter. It also synthesizes setter/getter methods
for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), // and adds them to the DeclContext and global method pools.
E = CDecl->prop_end(); for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
I != E; ++I) E = CDecl->prop_end();
ProcessPropertyDecl(*I, CDecl); I != E; ++I)
ProcessPropertyDecl(*I, CDecl);
CDecl->setAtEndRange(AtEnd); CDecl->setAtEndRange(AtEnd);
} }
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
@ -2137,7 +2155,22 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// May modify Attributes. // May modify Attributes.
CheckObjCPropertyAttributes(T, AtLoc, Attributes); CheckObjCPropertyAttributes(T, AtLoc, Attributes);
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) 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 // This is a continuation class. property requires special
// handling. // handling.
if ((CCPrimary = CDecl->getClassInterface())) { if ((CCPrimary = CDecl->getClassInterface())) {
@ -2201,6 +2234,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
ProcessPropertyDecl(PIDecl, CCPrimary); ProcessPropertyDecl(PIDecl, CCPrimary);
return DeclPtrTy(); return DeclPtrTy();
} }
// No matching property found in the primary class. Just fall thru // No matching property found in the primary class. Just fall thru
// and add property to continuation class's primary class. // and add property to continuation class's primary class.
ClassDecl = CCPrimary; ClassDecl = CCPrimary;
@ -2354,7 +2388,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
} }
if (const ObjCCategoryDecl *CD = if (const ObjCCategoryDecl *CD =
dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
if (CD->getIdentifier()) { if (!CD->IsClassExtension()) {
Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
Diag(property->getLocation(), diag::note_property_declare); Diag(property->getLocation(), diag::note_property_declare);
return DeclPtrTy(); return DeclPtrTy();

Просмотреть файл

@ -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