From b9556e695f46c95eeb8f06c8a842e55fb8beb8aa Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Tue, 9 Oct 2012 01:23:50 +0000 Subject: [PATCH] Move the logic that searches for overridden methods from libclang to ASTContext so that it can be widely available. llvm-svn: 165473 --- clang/include/clang/AST/ASTContext.h | 10 ++ clang/lib/AST/ASTContext.cpp | 186 +++++++++++++++++++++++++++ clang/tools/libclang/CXCursor.cpp | 186 +-------------------------- 3 files changed, 202 insertions(+), 180 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index f52ee0470a54..c9e9f4c0c667 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -625,6 +625,16 @@ public: /// Overridden method. void addOverriddenMethod(const CXXMethodDecl *Method, const CXXMethodDecl *Overridden); + + /// \brief Return C++ or ObjC overridden methods for the given \p Method. + /// + /// An ObjC method is considered to override any method in the class's + /// base classes, its protocols, or its categories' protocols, that has + /// the same selector and is of the same kind (class or instance). + /// A method in an implementation is not considered as overriding the same + /// method in the interface or its categories. + void getOverriddenMethods(const NamedDecl *Method, + SmallVectorImpl &Overridden); /// \brief Notify the AST context that a new import declaration has been /// parsed or implicitly created within this translation unit. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 94bb9a925955..67e89f3737d7 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1026,6 +1026,192 @@ void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, OverriddenMethods[Method].push_back(Overridden); } +static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, + const ObjCMethodDecl *Method, + SmallVectorImpl &Methods, + bool MovedToSuper) { + if (!Container) + return; + + // In categories look for overriden methods from protocols. A method from + // category is not "overriden" since it is considered as the "same" method + // (same USR) as the one from the interface. + if (const ObjCCategoryDecl * + Category = dyn_cast(Container)) { + // Check whether we have a matching method at this category but only if we + // are at the super class level. + if (MovedToSuper) + if (ObjCMethodDecl * + Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this category; there is no need to look + // into its protocols. + Methods.push_back(Overridden); + return; + } + + for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), + PEnd = Category->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + return; + } + + // Check whether we have a matching method at this level. + if (const ObjCMethodDecl * + Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this level; there is no need to look + // into other protocols or categories. + Methods.push_back(Overridden); + return; + } + + if (const ObjCProtocolDecl *Protocol = dyn_cast(Container)){ + for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), + PEnd = Protocol->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + } + + if (const ObjCInterfaceDecl * + Interface = dyn_cast(Container)) { + for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(), + PEnd = Interface->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + + for (const ObjCCategoryDecl *Category = Interface->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + CollectOverriddenMethodsRecurse(Category, Method, Methods, + MovedToSuper); + + if (const ObjCInterfaceDecl *Super = Interface->getSuperClass()) + return CollectOverriddenMethodsRecurse(Super, Method, Methods, + /*MovedToSuper=*/true); + } +} + +static inline void CollectOverriddenMethods(const ObjCContainerDecl *Container, + const ObjCMethodDecl *Method, + SmallVectorImpl &Methods) { + CollectOverriddenMethodsRecurse(Container, Method, Methods, + /*MovedToSuper=*/false); +} + +static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, + SmallVectorImpl &overridden) { + assert(Method->isOverriding()); + + if (const ObjCProtocolDecl * + ProtD = dyn_cast(Method->getDeclContext())) { + CollectOverriddenMethods(ProtD, Method, overridden); + + } else if (const ObjCImplDecl * + IMD = dyn_cast(Method->getDeclContext())) { + const ObjCInterfaceDecl *ID = IMD->getClassInterface(); + if (!ID) + return; + // Start searching for overridden methods using the method from the + // interface as starting point. + if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + Method = IFaceMeth; + CollectOverriddenMethods(ID, Method, overridden); + + } else if (const ObjCCategoryDecl * + CatD = dyn_cast(Method->getDeclContext())) { + const ObjCInterfaceDecl *ID = CatD->getClassInterface(); + if (!ID) + return; + // Start searching for overridden methods using the method from the + // interface as starting point. + if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + Method = IFaceMeth; + CollectOverriddenMethods(ID, Method, overridden); + + } else { + CollectOverriddenMethods( + dyn_cast_or_null(Method->getDeclContext()), + Method, overridden); + } +} + +static void collectOnCategoriesAfterLocation(SourceLocation Loc, + const ObjCInterfaceDecl *Class, + SourceManager &SM, + const ObjCMethodDecl *Method, + SmallVectorImpl &Methods) { + if (!Class) + return; + + for (const ObjCCategoryDecl *Category = Class->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation())) + CollectOverriddenMethodsRecurse(Category, Method, Methods, true); + + collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM, + Method, Methods); +} + +/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding() +/// returns false. +/// You'd think that in that case there are no overrides but categories can +/// "introduce" new overridden methods that are missed by Sema because the +/// overrides lookup that it does for methods, inside implementations, will +/// stop at the interface level (if there is a method there) and not look +/// further in super classes. +static void collectOverriddenMethodsFast(SourceManager &SM, + const ObjCMethodDecl *Method, + SmallVectorImpl &Methods) { + assert(!Method->isOverriding()); + + const ObjCContainerDecl * + ContD = cast(Method->getDeclContext()); + if (isa(ContD) || isa(ContD)) + return; + const ObjCInterfaceDecl *Class = Method->getClassInterface(); + if (!Class) + return; + + collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(), + SM, Method, Methods); +} + +void ASTContext::getOverriddenMethods(const NamedDecl *D, + SmallVectorImpl &Overridden) { + assert(D); + + if (const CXXMethodDecl *CXXMethod = dyn_cast(D)) { + for (CXXMethodDecl::method_iterator + M = CXXMethod->begin_overridden_methods(), + MEnd = CXXMethod->end_overridden_methods(); + M != MEnd; ++M) + Overridden.push_back(*M); + return; + } + + const ObjCMethodDecl *Method = dyn_cast(D); + if (!Method) + return; + + if (Method->isRedeclaration()) { + Method = cast(Method->getDeclContext())-> + getMethod(Method->getSelector(), Method->isInstanceMethod()); + } + + if (!Method->isOverriding()) { + collectOverriddenMethodsFast(SourceMgr, Method, Overridden); + } else { + collectOverriddenMethodsSlow(Method, Overridden); + assert(!Overridden.empty() && + "ObjCMethodDecl's overriding bit is not as expected"); + } +} + void ASTContext::addedLocalImportDecl(ImportDecl *Import) { assert(!Import->NextLocalImport && "Import declaration already in the chain"); assert(!Import->isFromASTFile() && "Non-local import declaration"); diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index a8cb1f96d4d6..ce517023f403 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -795,194 +795,20 @@ CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) { return static_cast(Cursor.data[2]); } -static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU, - ObjCContainerDecl *Container, - ObjCMethodDecl *Method, - SmallVectorImpl &Methods, - bool MovedToSuper) { - if (!Container) - return; - - // In categories look for overriden methods from protocols. A method from - // category is not "overriden" since it is considered as the "same" method - // (same USR) as the one from the interface. - if (ObjCCategoryDecl *Category = dyn_cast(Container)) { - // Check whether we have a matching method at this category but only if we - // are at the super class level. - if (MovedToSuper) - if (ObjCMethodDecl * - Overridden = Container->getMethod(Method->getSelector(), - Method->isInstanceMethod())) - if (Method != Overridden) { - // We found an override at this category; there is no need to look - // into its protocols. - Methods.push_back(MakeCXCursor(Overridden, TU)); - return; - } - - for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), - PEnd = Category->protocol_end(); - P != PEnd; ++P) - CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper); - return; - } - - // Check whether we have a matching method at this level. - if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(), - Method->isInstanceMethod())) - if (Method != Overridden) { - // We found an override at this level; there is no need to look - // into other protocols or categories. - Methods.push_back(MakeCXCursor(Overridden, TU)); - return; - } - - if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { - for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), - PEnd = Protocol->protocol_end(); - P != PEnd; ++P) - CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper); - } - - if (ObjCInterfaceDecl *Interface = dyn_cast(Container)) { - for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(), - PEnd = Interface->protocol_end(); - P != PEnd; ++P) - CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper); - - for (ObjCCategoryDecl *Category = Interface->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - CollectOverriddenMethodsRecurse(TU, Category, Method, Methods, - MovedToSuper); - - if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) - return CollectOverriddenMethodsRecurse(TU, Super, Method, Methods, - /*MovedToSuper=*/true); - } -} - -static inline void CollectOverriddenMethods(CXTranslationUnit TU, - ObjCContainerDecl *Container, - ObjCMethodDecl *Method, - SmallVectorImpl &Methods) { - CollectOverriddenMethodsRecurse(TU, Container, Method, Methods, - /*MovedToSuper=*/false); -} - -static void collectOverriddenMethodsSlow(CXTranslationUnit TU, - ObjCMethodDecl *Method, - SmallVectorImpl &overridden) { - assert(Method->isOverriding()); - - if (ObjCProtocolDecl * - ProtD = dyn_cast(Method->getDeclContext())) { - CollectOverriddenMethods(TU, ProtD, Method, overridden); - - } else if (ObjCImplDecl * - IMD = dyn_cast(Method->getDeclContext())) { - ObjCInterfaceDecl *ID = IMD->getClassInterface(); - if (!ID) - return; - // Start searching for overridden methods using the method from the - // interface as starting point. - if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), - Method->isInstanceMethod())) - Method = IFaceMeth; - CollectOverriddenMethods(TU, ID, Method, overridden); - - } else if (ObjCCategoryDecl * - CatD = dyn_cast(Method->getDeclContext())) { - ObjCInterfaceDecl *ID = CatD->getClassInterface(); - if (!ID) - return; - // Start searching for overridden methods using the method from the - // interface as starting point. - if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), - Method->isInstanceMethod())) - Method = IFaceMeth; - CollectOverriddenMethods(TU, ID, Method, overridden); - - } else { - CollectOverriddenMethods(TU, - dyn_cast_or_null(Method->getDeclContext()), - Method, overridden); - } -} - -static void collectOnCategoriesAfterLocation(SourceLocation Loc, - ObjCInterfaceDecl *Class, - CXTranslationUnit TU, - ObjCMethodDecl *Method, - SmallVectorImpl &Methods) { - if (!Class) - return; - - SourceManager &SM = static_cast(TU->TUData)->getSourceManager(); - for (ObjCCategoryDecl *Category = Class->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation())) - CollectOverriddenMethodsRecurse(TU, Category, Method, Methods, true); - - collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), TU, - Method, Methods); -} - -/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding() -/// returns false. -/// You'd think that in that case there are no overrides but categories can -/// "introduce" new overridden methods that are missed by Sema because the -/// overrides lookup that it does for methods, inside implementations, will -/// stop at the interface level (if there is a method there) and not look -/// further in super classes. -static void collectOverriddenMethodsFast(CXTranslationUnit TU, - ObjCMethodDecl *Method, - SmallVectorImpl &Methods) { - assert(!Method->isOverriding()); - - ObjCContainerDecl *ContD = cast(Method->getDeclContext()); - if (isa(ContD) || isa(ContD)) - return; - ObjCInterfaceDecl *Class = Method->getClassInterface(); - if (!Class) - return; - - collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(), - TU, Method, Methods); -} - void cxcursor::getOverriddenCursors(CXCursor cursor, SmallVectorImpl &overridden) { assert(clang_isDeclaration(cursor.kind)); - Decl *D = getCursorDecl(cursor); + const NamedDecl *D = dyn_cast_or_null(getCursorDecl(cursor)); if (!D) return; - // Handle C++ member functions. CXTranslationUnit TU = getCursorTU(cursor); - if (CXXMethodDecl *CXXMethod = dyn_cast(D)) { - for (CXXMethodDecl::method_iterator - M = CXXMethod->begin_overridden_methods(), - MEnd = CXXMethod->end_overridden_methods(); - M != MEnd; ++M) - overridden.push_back(MakeCXCursor(const_cast(*M), TU)); - return; - } + SmallVector OverDecls; + D->getASTContext().getOverriddenMethods(D, OverDecls); - ObjCMethodDecl *Method = dyn_cast(D); - if (!Method) - return; - - if (Method->isRedeclaration()) { - Method = cast(Method->getDeclContext())-> - getMethod(Method->getSelector(), Method->isInstanceMethod()); - } - - if (!Method->isOverriding()) { - collectOverriddenMethodsFast(TU, Method, overridden); - } else { - collectOverriddenMethodsSlow(TU, Method, overridden); - assert(!overridden.empty() && - "ObjCMethodDecl's overriding bit is not as expected"); + for (SmallVector::iterator + I = OverDecls.begin(), E = OverDecls.end(); I != E; ++I) { + overridden.push_back(MakeCXCursor(const_cast(*I), TU)); } }