Rework the traversal of Objective-C categories and extensions to
consider (sub)module visibility.
The bulk of this change replaces myriad hand-rolled loops over the
linked list of Objective-C categories/extensions attached to an
interface declaration with loops using one of the four new category
iterator kinds:
visible_categories_iterator: Iterates over all visible categories
and extensions, hiding any that have their "hidden" bit set. This is
by far the most commonly used iterator.
known_categories_iterator: Iterates over all categories and
extensions, ignoring the "hidden" bit. This tends to be used for
redeclaration-like traversals.
visible_extensions_iterator: Iterates over all visible extensions,
hiding any that have their "hidden" bit set.
known_extensions_iterator: Iterates over all extensions, whether
they are visible to normal name lookup or not.
The effect of this change is that any uses of the visible_ iterators
will respect module-import visibility. See the new tests for examples.
Note that the old accessors for categories and extensions are gone;
there are *Raw() forms for some of them, for those (few) areas of the
compiler that have to manipulate the linked list of categories
directly. This is generally discouraged.
Part two of <rdar://problem/10634711>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172665 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 5d5226d..5cbba23 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -3433,9 +3433,11 @@
} else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
if (AllowCategories) {
// Look through categories.
- for (ObjCCategoryDecl *Category = IFace->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- AddObjCProperties(Category, AllowCategories, AllowNullaryMethods,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = IFace->known_categories_begin(),
+ CatEnd = IFace->known_categories_end();
+ Cat != CatEnd; ++Cat)
+ AddObjCProperties(*Cat, AllowCategories, AllowNullaryMethods,
CurContext, AddedProperties, Results);
}
@@ -4806,9 +4808,13 @@
CurContext, Selectors, AllowSameLength, Results, false);
// Add methods in categories.
- for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl;
- CatDecl = CatDecl->getNextClassCategory()) {
- AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = IFace->known_categories_begin(),
+ CatEnd = IFace->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ ObjCCategoryDecl *CatDecl = *Cat;
+
+ AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
NumSelIdents, CurContext, Selectors, AllowSameLength,
Results, InOriginalClass);
@@ -5076,11 +5082,14 @@
// Check in categories or class extensions.
if (!SuperMethod) {
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- if ((SuperMethod = Category->getMethod(CurMethod->getSelector(),
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((SuperMethod = Cat->getMethod(CurMethod->getSelector(),
CurMethod->isInstanceMethod())))
break;
+ }
}
}
@@ -5807,11 +5816,15 @@
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
NamedDecl *CurClass
= LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
- if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass))
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- CategoryNames.insert(Category->getIdentifier());
-
+ if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass)){
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = Class->visible_categories_begin(),
+ CatEnd = Class->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CategoryNames.insert(Cat->getIdentifier());
+ }
+ }
+
// Add all of the categories we know about.
Results.EnterNewScope();
TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
@@ -5853,11 +5866,14 @@
Results.EnterNewScope();
bool IgnoreImplemented = true;
while (Class) {
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- if ((!IgnoreImplemented || !Category->getImplementation()) &&
- CategoryNames.insert(Category->getIdentifier()))
- Results.AddResult(Result(Category, 0), CurContext, 0, false);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = Class->visible_categories_begin(),
+ CatEnd = Class->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((!IgnoreImplemented || !Cat->getImplementation()) &&
+ CategoryNames.insert(Cat->getIdentifier()))
+ Results.AddResult(Result(*Cat, 0), CurContext, 0, false);
+ }
Class = Class->getSuperClass();
IgnoreImplemented = false;
@@ -6033,12 +6049,14 @@
KnownMethods, InOriginalClass);
// Add methods from any class extensions and categories.
- for (const ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat;
- Cat = Cat->getNextClassCategory())
- FindImplementableMethods(Context, const_cast<ObjCCategoryDecl*>(Cat),
- WantInstanceMethods, ReturnType,
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ FindImplementableMethods(Context, *Cat, WantInstanceMethods, ReturnType,
KnownMethods, false);
-
+ }
+
// Visit the superclass.
if (IFace->getSuperClass())
FindImplementableMethods(Context, IFace->getSuperClass(),
@@ -6898,9 +6916,12 @@
IFace = Category->getClassInterface();
if (IFace) {
- for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- Containers.push_back(Category);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ Containers.push_back(*Cat);
+ }
}
for (unsigned I = 0, N = Containers.size(); I != N; ++I) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 5d655e2..994b212 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -10472,11 +10472,12 @@
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
- for (const ObjCCategoryDecl *ClsExtDecl =
- IDecl->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- if (const ObjCIvarDecl *ClsExtIvar =
- ClsExtDecl->getIvarDecl(ClsFields[i]->getIdentifier())) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = IDecl->known_extensions_begin(),
+ ExtEnd = IDecl->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (const ObjCIvarDecl *ClsExtIvar
+ = Ext->getIvarDecl(ClsFields[i]->getIdentifier())) {
Diag(ClsFields[i]->getLocation(),
diag::err_duplicate_ivar_declaration);
Diag(ClsExtIvar->getLocation(), diag::note_previous_definition);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index e6c5d92..54cf1c2 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -849,16 +849,12 @@
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 (ObjCCategoryDecl *Previous
+ = IDecl->FindCategoryDeclaration(CategoryName)) {
+ // Class extensions can be declared multiple times, categories cannot.
+ Diag(CategoryLoc, diag::warn_dup_category_def)
+ << ClassName << CategoryName;
+ Diag(Previous->getLocation(), diag::note_previous_definition);
}
}
@@ -1738,24 +1734,27 @@
// when checking that methods in implementation match their declaration,
// i.e. when WarnCategoryMethodImpl is false, check declarations in class
// extension; as well as those in categories.
- if (!WarnCategoryMethodImpl)
- for (const ObjCCategoryDecl *CDeclChain = I->getCategoryList();
- CDeclChain; CDeclChain = CDeclChain->getNextClassCategory())
+ if (!WarnCategoryMethodImpl) {
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = I->visible_categories_begin(),
+ CatEnd = I->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(CDeclChain),
- IncompleteImpl, false,
+ IMPDecl, *Cat, IncompleteImpl, false,
WarnCategoryMethodImpl);
- else
+ }
+ } else {
// Also methods in class extensions need be looked at next.
- for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = I->visible_extensions_begin(),
+ ExtEnd = I->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- IncompleteImpl, false,
+ IMPDecl, *Ext, IncompleteImpl, false,
WarnCategoryMethodImpl);
-
+ }
+ }
+
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::all_protocol_iterator
PI = I->all_referenced_protocol_begin(),
@@ -1858,11 +1857,12 @@
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, I);
// Check class extensions (unnamed categories)
- for (const ObjCCategoryDecl *Categories = I->getFirstClassExtension();
- Categories; Categories = Categories->getNextClassExtension())
- ImplMethodsVsClassMethods(S, IMPDecl,
- const_cast<ObjCCategoryDecl*>(Categories),
- IncompleteImpl);
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = I->visible_extensions_begin(),
+ ExtEnd = I->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ ImplMethodsVsClassMethods(S, IMPDecl, *Ext, IncompleteImpl);
+ }
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For extended class, unimplemented methods in its protocols will
// be reported in the primary class.
@@ -2414,11 +2414,12 @@
// of the other class extensions. Mark them as synthesized as
// property will be synthesized when property with same name is
// seen in the @implementation.
- for (const ObjCCategoryDecl *ClsExtDecl =
- IDecl->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- for (ObjCContainerDecl::prop_iterator I = ClsExtDecl->prop_begin(),
- E = ClsExtDecl->prop_end(); I != E; ++I) {
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = IDecl->visible_extensions_begin(),
+ ExtEnd = IDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ for (ObjCContainerDecl::prop_iterator I = Ext->prop_begin(),
+ E = Ext->prop_end(); I != E; ++I) {
ObjCPropertyDecl *Property = *I;
// Skip over properties declared @dynamic
if (const ObjCPropertyImplDecl *PIDecl
@@ -2426,18 +2427,19 @@
if (PIDecl->getPropertyImplementation()
== ObjCPropertyImplDecl::Dynamic)
continue;
-
- for (const ObjCCategoryDecl *CExtDecl =
- IDecl->getFirstClassExtension();
- CExtDecl; CExtDecl = CExtDecl->getNextClassExtension()) {
- if (ObjCMethodDecl *GetterMethod =
- CExtDecl->getInstanceMethod(Property->getGetterName()))
+
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = IDecl->visible_extensions_begin(),
+ ExtEnd = IDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCMethodDecl *GetterMethod
+ = Ext->getInstanceMethod(Property->getGetterName()))
GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly())
- if (ObjCMethodDecl *SetterMethod =
- CExtDecl->getInstanceMethod(Property->getSetterName()))
+ if (ObjCMethodDecl *SetterMethod
+ = Ext->getInstanceMethod(Property->getSetterName()))
SetterMethod->setPropertyAccessor(true);
- }
+ }
}
}
ImplMethodsVsClassMethods(S, IC, IDecl);
@@ -2486,12 +2488,9 @@
// Find category interface decl and then check that all methods declared
// in this interface are implemented in the category @implementation.
if (ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface()) {
- for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
- Categories; Categories = Categories->getNextClassCategory()) {
- if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
- ImplMethodsVsClassMethods(S, CatImplClass, Categories);
- break;
- }
+ if (ObjCCategoryDecl *Cat
+ = IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier())) {
+ ImplMethodsVsClassMethods(S, CatImplClass, Cat);
}
}
}
@@ -2726,9 +2725,12 @@
return;
// - categories,
- for (ObjCCategoryDecl *category = iface->getCategoryList();
- category; category = category->getNextClassCategory())
- search(category);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ cat = iface->visible_categories_begin(),
+ catEnd = iface->visible_categories_end();
+ cat != catEnd; ++cat) {
+ search(*cat);
+ }
// - the super class, and
if (ObjCInterfaceDecl *super = iface->getSuperClass())
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 4ae27a4..4bdc1dc 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -2913,10 +2913,12 @@
// Traverse the contexts of Objective-C classes.
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
// Traverse categories.
- for (ObjCCategoryDecl *Category = IFace->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Category, Result, QualifiedNameLookup, false,
+ LookupVisibleDecls(*Cat, Result, QualifiedNameLookup, false,
Consumer, Visited);
}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index a605ed5..2bdb54b 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -270,20 +270,22 @@
IdentifierInfo *PropertyId = FD.D.getIdentifier();
ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
- if (CCPrimary)
+ if (CCPrimary) {
// Check for duplicate declaration of this property in current and
// other class extensions.
- for (const ObjCCategoryDecl *ClsExtDecl =
- CCPrimary->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- if (ObjCPropertyDecl *prevDecl =
- ObjCPropertyDecl::findPropertyDecl(ClsExtDecl, PropertyId)) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = CCPrimary->known_extensions_begin(),
+ ExtEnd = CCPrimary->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCPropertyDecl *prevDecl
+ = ObjCPropertyDecl::findPropertyDecl(*Ext, PropertyId)) {
Diag(AtLoc, diag::err_duplicate_property);
Diag(prevDecl->getLocation(), diag::note_property_declare);
return 0;
}
}
-
+ }
+
// Create a new ObjCPropertyDecl with the DeclContext being
// the class extension.
// FIXME. We should really be using CreatePropertyDecl for this.
@@ -646,11 +648,14 @@
ObjCPropertyDecl *property) {
unsigned Attributes = property->getPropertyAttributesAsWritten();
bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly);
- for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
- CDecl; CDecl = CDecl->getNextClassExtension()) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = ClassDecl->known_extensions_begin(),
+ ExtEnd = ClassDecl->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
ObjCPropertyDecl *ClassExtProperty = 0;
- for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(),
- E = CDecl->prop_end(); P != E; ++P) {
+ for (ObjCContainerDecl::prop_iterator P = Ext->prop_begin(),
+ E = Ext->prop_end();
+ P != E; ++P) {
if ((*P)->getIdentifier() == property->getIdentifier()) {
ClassExtProperty = *P;
break;
@@ -1404,14 +1409,14 @@
// Main class has the property as 'readonly'. Must search
// through the category list to see if the property's
// attribute has been over-ridden to 'readwrite'.
- for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
- // Even if property is ready only, if a category has a user defined setter,
- // it is not considered read only.
- if (Category->getInstanceMethod(PDecl->getSetterName()))
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IDecl->visible_categories_begin(),
+ CatEnd = IDecl->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (Cat->getInstanceMethod(PDecl->getSetterName()))
return false;
ObjCPropertyDecl *P =
- Category->FindPropertyDeclaration(PDecl->getIdentifier());
+ Cat->FindPropertyDeclaration(PDecl->getIdentifier());
if (P && !P->isReadOnly())
return false;
}