From: Douglas Gregor Date: Wed, 16 Jan 2013 23:00:23 +0000 (+0000) Subject: Rework the traversal of Objective-C categories and extensions to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d329724745b49f894b768d47275b7c2713106e89;p=clang 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172665 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index d1067432e3..e7fa5e7d2b 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -894,7 +894,166 @@ public: : superCls; } - ObjCCategoryDecl* getCategoryList() const { + /// \brief Iterator that walks over the list of categories, filtering out + /// those that do not meet specific criteria. + /// + /// This class template is used for the various permutations of category + /// and extension iterators. + template + class filtered_category_iterator { + ObjCCategoryDecl *Current; + + void findAcceptableCategory(); + + public: + typedef ObjCCategoryDecl * value_type; + typedef value_type reference; + typedef value_type pointer; + typedef std::ptrdiff_t difference_type; + typedef std::input_iterator_tag iterator_category; + + filtered_category_iterator() : Current(0) { } + explicit filtered_category_iterator(ObjCCategoryDecl *Current) + : Current(Current) + { + findAcceptableCategory(); + } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + filtered_category_iterator &operator++(); + + filtered_category_iterator operator++(int) { + filtered_category_iterator Tmp = *this; + ++(*this); + return Tmp; + } + + friend bool operator==(filtered_category_iterator X, + filtered_category_iterator Y) { + return X.Current = Y.Current; + } + + friend bool operator!=(filtered_category_iterator X, + filtered_category_iterator Y) { + return X.Current != Y.Current; + } + }; + +private: + /// \brief Test whether the given category is visible. + /// + /// Used in the \c visible_categories_iterator. + static bool isVisibleCategory(ObjCCategoryDecl *Cat); + +public: + /// \brief Iterator that walks over the list of categories and extensions + /// that are visible, i.e., not hidden in a non-imported submodule. + typedef filtered_category_iterator + visible_categories_iterator; + + /// \brief Retrieve an iterator to the beginning of the visible-categories + /// list. + visible_categories_iterator visible_categories_begin() const { + return visible_categories_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the visible-categories list. + visible_categories_iterator visible_categories_end() const { + return visible_categories_iterator(); + } + + /// \brief Determine whether the visible-categories list is empty. + bool visible_categories_empty() const { + return visible_categories_begin() == visible_categories_end(); + } + +private: + /// \brief Test whether the given category... is a category. + /// + /// Used in the \c known_categories_iterator. + static bool isKnownCategory(ObjCCategoryDecl *) { return true; } + +public: + /// \brief Iterator that walks over all of the known categories and + /// extensions, including those that are hidden. + typedef filtered_category_iterator known_categories_iterator; + + /// \brief Retrieve an iterator to the beginning of the known-categories + /// list. + known_categories_iterator known_categories_begin() const { + return known_categories_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the known-categories list. + known_categories_iterator known_categories_end() const { + return known_categories_iterator(); + } + + /// \brief Determine whether the known-categories list is empty. + bool known_categories_empty() const { + return known_categories_begin() == known_categories_end(); + } + +private: + /// \brief Test whether the given category is a visible extension. + /// + /// Used in the \c visible_extensions_iterator. + static bool isVisibleExtension(ObjCCategoryDecl *Cat); + +public: + /// \brief Iterator that walks over all of the visible extensions, skipping + /// any that are known but hidden. + typedef filtered_category_iterator + visible_extensions_iterator; + + /// \brief Retrieve an iterator to the beginning of the visible-extensions + /// list. + visible_extensions_iterator visible_extensions_begin() const { + return visible_extensions_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the visible-extensions list. + visible_extensions_iterator visible_extensions_end() const { + return visible_extensions_iterator(); + } + + /// \brief Determine whether the visible-extensions list is empty. + bool visible_extensions_empty() const { + return visible_extensions_begin() == visible_extensions_end(); + } + +private: + /// \brief Test whether the given category is an extension. + /// + /// Used in the \c known_extensions_iterator. + static bool isKnownExtension(ObjCCategoryDecl *Cat); + +public: + /// \brief Iterator that walks over all of the known extensions. + typedef filtered_category_iterator + known_extensions_iterator; + + /// \brief Retrieve an iterator to the beginning of the known-extensions + /// list. + known_extensions_iterator known_extensions_begin() const { + return known_extensions_iterator(getCategoryListRaw()); + } + + /// \brief Retrieve an iterator to the end of the known-extensions list. + known_extensions_iterator known_extensions_end() const { + return known_extensions_iterator(); + } + + /// \brief Determine whether the known-extensions list is empty. + bool known_extensions_empty() const { + return known_extensions_begin() == known_extensions_end(); + } + + /// \brief Retrieve the raw pointer to the start of the category/extension + /// list. + ObjCCategoryDecl* getCategoryListRaw() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return 0; @@ -905,12 +1064,12 @@ public: return data().CategoryList; } - void setCategoryList(ObjCCategoryDecl *category) { + /// \brief Set the raw pointer to the start of the category/extension + /// list. + void setCategoryListRaw(ObjCCategoryDecl *category) { data().CategoryList = category; } - ObjCCategoryDecl* getFirstClassExtension() const; - ObjCPropertyDecl *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const; @@ -1351,6 +1510,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl { CategoryNameLoc(CategoryNameLoc), IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) { } + public: static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, @@ -1394,8 +1554,13 @@ public: ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; } + /// \brief Retrieve the pointer to the next stored category (or extension), + /// which may be hidden. + ObjCCategoryDecl *getNextClassCategoryRaw() const { + return NextClassCategory; + } + bool IsClassExtension() const { return getIdentifier() == 0; } - const ObjCCategoryDecl *getNextClassExtension() const; typedef specific_decl_iterator ivar_iterator; ivar_iterator ivar_begin() const { @@ -2030,5 +2195,33 @@ public: friend class ASTDeclReader; }; +template +void +ObjCInterfaceDecl::filtered_category_iterator:: +findAcceptableCategory() { + while (Current && !Filter(Current)) + Current = Current->getNextClassCategoryRaw(); +} + +template +inline ObjCInterfaceDecl::filtered_category_iterator & +ObjCInterfaceDecl::filtered_category_iterator::operator++() { + Current = Current->getNextClassCategoryRaw(); + findAcceptableCategory(); + return *this; +} + +inline bool ObjCInterfaceDecl::isVisibleCategory(ObjCCategoryDecl *Cat) { + return !Cat->isHidden(); +} + +inline bool ObjCInterfaceDecl::isVisibleExtension(ObjCCategoryDecl *Cat) { + return Cat->IsClassExtension() && !Cat->isHidden(); +} + +inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) { + return Cat->IsClassExtension(); +} + } // end namespace clang #endif diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp index 7196a54efc..b6ddc43dd6 100644 --- a/lib/ARCMigrate/TransProperties.cpp +++ b/lib/ARCMigrate/TransProperties.cpp @@ -141,10 +141,12 @@ public: AtPropDeclsTy AtExtProps; // Look through extensions. - for (ObjCCategoryDecl *Cat = iface->getCategoryList(); - Cat; Cat = Cat->getNextClassCategory()) - if (Cat->IsClassExtension()) - collectProperties(Cat, AtExtProps, &AtProps); + for (ObjCInterfaceDecl::visible_extensions_iterator + ext = iface->visible_extensions_begin(), + extEnd = iface->visible_extensions_end(); + ext != extEnd; ++ext) { + collectProperties(*ext, AtExtProps, &AtProps); + } for (AtPropDeclsTy::iterator I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 83e6d6bd28..df64237f70 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -365,10 +365,12 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, if (!ID) return; // Add redeclared method here. - for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension(); - ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = ID->known_extensions_begin(), + ExtEnd = ID->known_extensions_end(); + Ext != ExtEnd; ++Ext) { if (ObjCMethodDecl *RedeclaredMethod = - ClsExtDecl->getMethod(ObjCMethod->getSelector(), + Ext->getMethod(ObjCMethod->getSelector(), ObjCMethod->isInstanceMethod())) Redeclared.push_back(RedeclaredMethod); } @@ -1689,9 +1691,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, } // Categories of this Interface. - for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList(); - CDeclChain; CDeclChain = CDeclChain->getNextClassCategory()) - CollectInheritedProtocols(CDeclChain, Protocols); + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = OI->visible_categories_begin(), + CatEnd = OI->visible_categories_end(); + Cat != CatEnd; ++Cat) { + CollectInheritedProtocols(*Cat, Protocols); + } + if (ObjCInterfaceDecl *SD = OI->getSuperClass()) while (SD) { CollectInheritedProtocols(SD, Protocols); @@ -1721,10 +1727,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const { unsigned count = 0; // Count ivars declared in class extension. - for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; - CDecl = CDecl->getNextClassExtension()) - count += CDecl->ivar_size(); - + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = OI->known_extensions_begin(), + ExtEnd = OI->known_extensions_end(); + Ext != ExtEnd; ++Ext) { + count += Ext->ivar_size(); + } + // Count ivar defined in this class's implementation. This // includes synthesized ivars. if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 9bfaa13ddd..305815ebeb 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -3514,10 +3514,13 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, // Import categories. When the categories themselves are imported, they'll // hook themselves into this interface. - for (ObjCCategoryDecl *FromCat = From->getCategoryList(); FromCat; - FromCat = FromCat->getNextClassCategory()) - Importer.Import(FromCat); - + for (ObjCInterfaceDecl::known_categories_iterator + Cat = From->known_categories_begin(), + CatEnd = From->known_categories_end(); + Cat != CatEnd; ++Cat) { + Importer.Import(*Cat); + } + // If we have an @implementation, import it as well. if (From->getImplementation()) { ObjCImplementationDecl *Impl = cast_or_null( diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 816c43200a..0b1a1ec456 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -129,12 +129,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { } case Decl::ObjCInterface: { const ObjCInterfaceDecl *OID = cast(this); - // Look through categories. - for (ObjCCategoryDecl *Cat = OID->getCategoryList(); - Cat; Cat = Cat->getNextClassCategory()) + // Look through categories (but not extensions). + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = OID->visible_categories_begin(), + CatEnd = OID->visible_categories_end(); + Cat != CatEnd; ++Cat) { if (!Cat->IsClassExtension()) if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId)) return P; + } // Look through protocols. for (ObjCInterfaceDecl::all_protocol_iterator @@ -296,24 +299,6 @@ void ObjCInterfaceDecl::startDefinition() { } } -/// 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) { // FIXME: Should make sure no callers ever do this. @@ -329,9 +314,12 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, clsDeclared = ClassDecl; return I; } - for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); - CDecl; CDecl = CDecl->getNextClassExtension()) { - if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) { + + for (ObjCInterfaceDecl::visible_extensions_iterator + Ext = ClassDecl->visible_extensions_begin(), + ExtEnd = ClassDecl->visible_extensions_end(); + Ext != ExtEnd; ++Ext) { + if (ObjCIvarDecl *I = Ext->getIvarDecl(ID)) { clsDeclared = ClassDecl; return I; } @@ -390,21 +378,22 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, return MethodDecl; // Didn't find one yet - now look through categories. - ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); - while (CatDecl) { - if ((MethodDecl = CatDecl->getMethod(Sel, isInstance))) + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = ClassDecl->visible_categories_begin(), + CatEnd = ClassDecl->visible_categories_end(); + Cat != CatEnd; ++Cat) { + if ((MethodDecl = Cat->getMethod(Sel, isInstance))) return MethodDecl; if (!shallowCategoryLookup) { // Didn't find one yet - look through protocols. const ObjCList &Protocols = - CatDecl->getReferencedProtocols(); + Cat->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; } - CatDecl = CatDecl->getNextClassCategory(); } ClassDecl = ClassDecl->getSuperClass(); @@ -816,10 +805,13 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, P != PEnd; ++P) CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); - for (const ObjCCategoryDecl *Category = Interface->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - CollectOverriddenMethodsRecurse(Category, Method, Methods, + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = Interface->visible_categories_begin(), + CatEnd = Interface->visible_categories_end(); + Cat != CatEnd; ++Cat) { + CollectOverriddenMethodsRecurse(*Cat, Method, Methods, MovedToSuper); + } if (const ObjCInterfaceDecl *Super = Interface->getSuperClass()) return CollectOverriddenMethodsRecurse(Super, Method, Methods, @@ -881,11 +873,14 @@ static void collectOnCategoriesAfterLocation(SourceLocation Loc, if (!Class) return; - for (const ObjCCategoryDecl *Category = Class->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation())) - CollectOverriddenMethodsRecurse(Category, Method, Methods, true); - + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = Class->visible_categories_begin(), + CatEnd = Class->visible_categories_end(); + Cat != CatEnd; ++Cat) { + if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation())) + CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true); + } + collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM, Method, Methods); } @@ -1072,12 +1067,13 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { for (curIvar = data().IvarList; I != E; curIvar = *I, ++I) curIvar->setNextIvar(*I); } - - for (const ObjCCategoryDecl *CDecl = getFirstClassExtension(); CDecl; - CDecl = CDecl->getNextClassExtension()) { - if (!CDecl->ivar_empty()) { - ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), - E = CDecl->ivar_end(); + + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = known_extensions_begin(), + ExtEnd = known_extensions_end(); + Ext != ExtEnd; ++Ext) { + if (!Ext->ivar_empty()) { + ObjCCategoryDecl::ivar_iterator I = Ext->ivar_begin(),E = Ext->ivar_end(); if (!data().IvarList) { data().IvarList = *I; ++I; curIvar = data().IvarList; @@ -1115,29 +1111,41 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { if (data().ExternallyCompleted) LoadExternalDefinition(); - for (ObjCCategoryDecl *Category = getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (Category->getIdentifier() == CategoryId) - return Category; + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (Cat->getIdentifier() == CategoryId) + return *Cat; + } + return 0; } ObjCMethodDecl * ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const { - for (ObjCCategoryDecl *Category = getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (ObjCCategoryImplDecl *Impl = Cat->getImplementation()) if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel)) return MD; + } + return 0; } ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const { - for (ObjCCategoryDecl *Category = getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (ObjCCategoryImplDecl *Impl = Cat->getImplementation()) if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel)) return MD; + } + return 0; } @@ -1169,10 +1177,13 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, // 2nd, look up the category. if (lookupCategory) - for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) { - for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), - E = CDecl->protocol_end(); PI != E; ++PI) + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + for (ObjCCategoryDecl::protocol_iterator PI = Cat->protocol_begin(), + E = Cat->protocol_end(); + PI != E; ++PI) if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) return true; } @@ -1393,9 +1404,9 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, IvarLBraceLoc, IvarRBraceLoc); if (IDecl) { // Link this category into its class's category list. - CatDecl->NextClassCategory = IDecl->getCategoryList(); + CatDecl->NextClassCategory = IDecl->getCategoryListRaw(); if (IDecl->hasDefinition()) { - IDecl->setCategoryList(CatDecl); + IDecl->setCategoryListRaw(CatDecl); if (ASTMutationListener *L = C.getASTMutationListener()) L->AddedObjCCategoryToInterface(CatDecl, IDecl); } diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index 1e7523f3b9..be22ae450b 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -748,14 +748,6 @@ struct XMLDumper : public XMLDeclVisitor, visitDeclContext(D); } - // ObjCInterfaceDecl - void visitCategoryList(ObjCCategoryDecl *D) { - if (!D) return; - - TemporaryContainer C(*this, "categories"); - for (; D; D = D->getNextClassCategory()) - visitDeclRef(D); - } void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { setPointer("typeptr", D->getTypeForDecl()); setFlag("forward_decl", !D->isThisDeclarationADefinition()); @@ -770,7 +762,17 @@ struct XMLDumper : public XMLDeclVisitor, I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) visitDeclRef(*I); } - visitCategoryList(D->getCategoryList()); + + if (!D->visible_categories_empty()) { + TemporaryContainer C(*this, "categories"); + + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = D->visible_categories_begin(), + CatEnd = D->visible_categories_end(); + Cat != CatEnd; ++Cat) { + visitDeclRef(*Cat); + } + } } void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) { visitDeclContext(D); diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp index d69106cfb0..53b5591ad4 100644 --- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp @@ -7298,11 +7298,8 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, WriteModernMetadataDeclarations(Context, Result); ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); // Find category declaration for this implementation. - ObjCCategoryDecl *CDecl=0; - for (CDecl = ClassDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->getIdentifier() == IDecl->getIdentifier()) - break; + ObjCCategoryDecl *CDecl + = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier()); std::string FullCategoryName = ClassDecl->getNameAsString(); FullCategoryName += "_$_"; diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp index 23719cb345..18b75758ab 100644 --- a/lib/Rewrite/Frontend/RewriteObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteObjC.cpp @@ -5744,11 +5744,8 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID std::string &Result) { ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); // Find category declaration for this implementation. - ObjCCategoryDecl *CDecl; - for (CDecl = ClassDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->getIdentifier() == IDecl->getIdentifier()) - break; + ObjCCategoryDecl *CDecl + = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier()); std::string FullCategoryName = ClassDecl->getNameAsString(); FullCategoryName += '_'; diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 5d5226dddd..5cbba239be 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3433,9 +3433,11 @@ static void AddObjCProperties(ObjCContainerDecl *Container, } else if (ObjCInterfaceDecl *IFace = dyn_cast(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 @@ static void AddObjCMethods(ObjCContainerDecl *Container, 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 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, // 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 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, llvm::SmallPtrSet CategoryNames; NamedDecl *CurClass = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); - if (ObjCInterfaceDecl *Class = dyn_cast_or_null(CurClass)) - for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category; - Category = Category->getNextClassCategory()) - CategoryNames.insert(Category->getIdentifier()); - + if (ObjCInterfaceDecl *Class = dyn_cast_or_null(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 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, 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 @@ static void FindImplementableMethods(ASTContext &Context, KnownMethods, InOriginalClass); // Add methods from any class extensions and categories. - for (const ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat; - Cat = Cat->getNextClassCategory()) - FindImplementableMethods(Context, const_cast(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 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, 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 5d655e24c0..994b212613 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -10472,11 +10472,12 @@ void Sema::ActOnFields(Scope* S, 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 e6c5d92f5e..54cf1c2626 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -849,16 +849,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, 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 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, // 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(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(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 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, 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(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(CDecl)) { // For extended class, unimplemented methods in its protocols will // be reported in the primary class. @@ -2414,11 +2414,12 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, // 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 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, 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 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, // 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 @@ private: 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 4ae27a4adc..4bdc1dc253 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2913,10 +2913,12 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast(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 a605ed52a6..2bdb54b1a5 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -270,20 +270,22 @@ Sema::HandlePropertyInClassExtension(Scope *S, 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 @@ DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl, 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 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, // 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; } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 32179798ea..9f8268adee 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -2404,7 +2404,7 @@ namespace { if (Tail) ASTDeclReader::setNextObjCCategory(Tail, Cat); else - Interface->setCategoryList(Cat); + Interface->setCategoryListRaw(Cat); Tail = Cat; } @@ -2419,13 +2419,15 @@ namespace { Tail(0) { // Populate the name -> category map with the set of known categories. - for (ObjCCategoryDecl *Cat = Interface->getCategoryList(); Cat; - Cat = Cat->getNextClassCategory()) { + for (ObjCInterfaceDecl::known_categories_iterator + Cat = Interface->known_categories_begin(), + CatEnd = Interface->known_categories_end(); + Cat != CatEnd; ++Cat) { if (Cat->getDeclName()) - NameCategoryMap[Cat->getDeclName()] = Cat; + NameCategoryMap[Cat->getDeclName()] = *Cat; // Keep track of the tail of the category list. - Tail = Cat; + Tail = *Cat; } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 67e03c2334..8c14b5f395 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -3238,10 +3238,12 @@ void ASTWriter::WriteObjCCategories() { Categories.push_back(0); // Add the categories. - for (ObjCCategoryDecl *Cat = Class->getCategoryList(); - Cat; Cat = Cat->getNextClassCategory(), ++Size) { - assert(getDeclID(Cat) != 0 && "Bogus category"); - AddDeclRef(Cat, Categories); + for (ObjCInterfaceDecl::known_categories_iterator + Cat = Class->known_categories_begin(), + CatEnd = Class->known_categories_end(); + Cat != CatEnd; ++Cat, ++Size) { + assert(getDeclID(*Cat) != 0 && "Bogus category"); + AddDeclRef(*Cat, Categories); } // Update the size. diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index bc92fb714a..7a57bad736 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -491,13 +491,14 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { PEnd = Data.AllReferencedProtocols.end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); + - if (ObjCCategoryDecl *Cat = D->getCategoryList()) { + if (ObjCCategoryDecl *Cat = D->getCategoryListRaw()) { // Ensure that we write out the set of categories for this class. Writer.ObjCClassesWithCategories.insert(D); // Make sure that the categories get serialized. - for (; Cat; Cat = Cat->getNextClassCategory()) + for (; Cat; Cat = Cat->getNextClassCategoryRaw()) (void)Writer.GetDeclRef(Cat); } } diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index b3bad61301..92e16f614d 100644 --- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -238,9 +238,11 @@ void IvarInvalidationChecker::containsInvalidationMethod( // Visit all categories in case the invalidation method is declared in // a category. - for (const ObjCCategoryDecl *I = InterfD->getFirstClassExtension(); I; - I = I->getNextClassExtension()) { - containsInvalidationMethod(I, OutInfo); + for (ObjCInterfaceDecl::visible_extensions_iterator + Ext = InterfD->visible_extensions_begin(), + ExtEnd = InterfD->visible_extensions_end(); + Ext != ExtEnd; ++Ext) { + containsInvalidationMethod(*Ext, OutInfo); } containsInvalidationMethod(InterfD->getSuperClass(), OutInfo); diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index b30c4e7b35..c66c7d0193 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp @@ -89,10 +89,11 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) { Scan(M, *I); // Scan the associated categories as well. - for (const ObjCCategoryDecl *CD = - ID->getClassInterface()->getCategoryList(); CD ; - CD = CD->getNextClassCategory()) { - if (const ObjCCategoryImplDecl *CID = CD->getImplementation()) + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = ID->getClassInterface()->visible_categories_begin(), + CatEnd = ID->getClassInterface()->visible_categories_end(); + Cat != CatEnd; ++Cat) { + if (const ObjCCategoryImplDecl *CID = Cat->getImplementation()) Scan(M, CID); } } diff --git a/test/Modules/Inputs/category_left_sub.h b/test/Modules/Inputs/category_left_sub.h new file mode 100644 index 0000000000..bee8617dc9 --- /dev/null +++ b/test/Modules/Inputs/category_left_sub.h @@ -0,0 +1,3 @@ +@interface Foo(LeftSub) +- (void)left_sub; +@end diff --git a/test/Modules/Inputs/category_right_sub.h b/test/Modules/Inputs/category_right_sub.h new file mode 100644 index 0000000000..696b6cabc0 --- /dev/null +++ b/test/Modules/Inputs/category_right_sub.h @@ -0,0 +1,9 @@ +@interface Foo(RightSub) +@property id right_sub_prop; +@end + +@interface Foo() { +@public + int right_sub_ivar; +} +@end diff --git a/test/Modules/Inputs/category_top.h b/test/Modules/Inputs/category_top.h index c9558b6c29..662ae574ec 100644 --- a/test/Modules/Inputs/category_top.h +++ b/test/Modules/Inputs/category_top.h @@ -12,3 +12,10 @@ @interface Foo(Top3) -(void)top3; @end + +@protocol P1 +@end + +@protocol P2 +@end + diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 42c6c2b5d9..5ec595c9e1 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -37,10 +37,18 @@ module category_top { header "category_top.h" } module category_left { header "category_left.h" export category_top + + explicit module sub { + header "category_left_sub.h" + } } module category_right { header "category_right.h" export category_top + + explicit module sub { + header "category_right_sub.h" + } } module category_bottom { header "category_bottom.h" diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m index f19dc7efcf..05a66ca4ee 100644 --- a/test/Modules/objc-categories.m +++ b/test/Modules/objc-categories.m @@ -39,3 +39,34 @@ void test(Foo *foo, LeftFoo *leftFoo) { void test_other(Foo *foo) { [foo other]; } + +// Make sure we don't see categories that should be hidden +void test_hidden_all_errors(Foo *foo) { + [foo left_sub]; // expected-warning{{instance method '-left_sub' not found (return type defaults to 'id')}} + foo.right_sub_prop = foo; // expected-error{{property 'right_sub_prop' not found on object of type 'Foo *'}} + int i = foo->right_sub_ivar; // expected-error{{'Foo' does not have a member named 'right_sub_ivar'}} + id p1 = foo; // expected-warning{{initializing 'id' with an expression of incompatible type 'Foo *'}} + id p2 = foo; // expected-warning{{initializing 'id' with an expression of incompatible type 'Foo *'}} +} + +@import category_left.sub; + +void test_hidden_right_errors(Foo *foo) { + // These are okay + [foo left_sub]; // okay + id p1 = foo; + // FIXME: these should fail + foo.right_sub_prop = foo; // expected-error{{property 'right_sub_prop' not found on object of type 'Foo *'}} + int i = foo->right_sub_ivar; // expected-error{{'Foo' does not have a member named 'right_sub_ivar'}} + id p2 = foo; // expected-warning{{initializing 'id' with an expression of incompatible type 'Foo *'}} +} + +@import category_right.sub; + +void test_hidden_okay(Foo *foo) { + [foo left_sub]; + foo.right_sub_prop = foo; + int i = foo->right_sub_ivar; + id p1 = foo; + id p2 = foo; +}