On Oct 9, 2012, at 10:25 AM, Argyrios Kyrtzidis <[email protected]> wrote:
> On Oct 9, 2012, at 9:42 AM, Jordan Rose <[email protected]> wrote: > >> Thanks, this could be very useful for some of the property-related warnings >> I'm working on now. But, is there a reason why this lives on ASTContext? Why >> not just split it up to ObjCMethodDecl and CXXMethodDecl? (I get that an IDE >> probably wants a generic "get overrides for the current method", but other >> than displaying them there aren't many common operations for both kinds of >> methods, and the rest of Clang usually knows what kind of method they're >> dealing with anyway.) > > Another common operation that Fariborz is going to use it for is "if the decl > does not have a comment, search for comments in the overrides". But we can > also split the ObjCMethodDecl into its own method (the CXXMethodDecl one is > too simple) and have the special and the common one at the same time. In r165518. > > -Argyrios > >> >> Jordan >> >> >> On Oct 8, 2012, at 18:23 , Argyrios Kyrtzidis <[email protected]> wrote: >> >>> Author: akirtzidis >>> Date: Mon Oct 8 20:23:50 2012 >>> New Revision: 165473 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=165473&view=rev >>> Log: >>> Move the logic that searches for overridden methods from libclang to >>> ASTContext so that it can be widely available. >>> >>> Modified: >>> cfe/trunk/include/clang/AST/ASTContext.h >>> cfe/trunk/lib/AST/ASTContext.cpp >>> cfe/trunk/tools/libclang/CXCursor.cpp >>> >>> Modified: cfe/trunk/include/clang/AST/ASTContext.h >>> URL: >>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=165473&r1=165472&r2=165473&view=diff >>> ============================================================================== >>> --- cfe/trunk/include/clang/AST/ASTContext.h (original) >>> +++ cfe/trunk/include/clang/AST/ASTContext.h Mon Oct 8 20:23:50 2012 >>> @@ -625,6 +625,16 @@ >>> /// 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<const NamedDecl *> >>> &Overridden); >>> >>> /// \brief Notify the AST context that a new import declaration has been >>> /// parsed or implicitly created within this translation unit. >>> >>> Modified: cfe/trunk/lib/AST/ASTContext.cpp >>> URL: >>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=165473&r1=165472&r2=165473&view=diff >>> ============================================================================== >>> --- cfe/trunk/lib/AST/ASTContext.cpp (original) >>> +++ cfe/trunk/lib/AST/ASTContext.cpp Mon Oct 8 20:23:50 2012 >>> @@ -1026,6 +1026,192 @@ >>> OverriddenMethods[Method].push_back(Overridden); >>> } >>> >>> +static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl >>> *Container, >>> + const ObjCMethodDecl *Method, >>> + SmallVectorImpl<const NamedDecl *> >>> &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<ObjCCategoryDecl>(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<ObjCProtocolDecl>(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<ObjCInterfaceDecl>(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<const NamedDecl *> >>> &Methods) { >>> + CollectOverriddenMethodsRecurse(Container, Method, Methods, >>> + /*MovedToSuper=*/false); >>> +} >>> + >>> +static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, >>> + SmallVectorImpl<const NamedDecl *> >>> &overridden) { >>> + assert(Method->isOverriding()); >>> + >>> + if (const ObjCProtocolDecl * >>> + ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) { >>> + CollectOverriddenMethods(ProtD, Method, overridden); >>> + >>> + } else if (const ObjCImplDecl * >>> + IMD = dyn_cast<ObjCImplDecl>(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<ObjCCategoryDecl>(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<ObjCContainerDecl>(Method->getDeclContext()), >>> + Method, overridden); >>> + } >>> +} >>> + >>> +static void collectOnCategoriesAfterLocation(SourceLocation Loc, >>> + const ObjCInterfaceDecl >>> *Class, >>> + SourceManager &SM, >>> + const ObjCMethodDecl *Method, >>> + SmallVectorImpl<const NamedDecl *> >>> &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<const NamedDecl *> >>> &Methods) { >>> + assert(!Method->isOverriding()); >>> + >>> + const ObjCContainerDecl * >>> + ContD = cast<ObjCContainerDecl>(Method->getDeclContext()); >>> + if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(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<const NamedDecl *> >>> &Overridden) { >>> + assert(D); >>> + >>> + if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(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<ObjCMethodDecl>(D); >>> + if (!Method) >>> + return; >>> + >>> + if (Method->isRedeclaration()) { >>> + Method = cast<ObjCContainerDecl>(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"); >>> >>> Modified: cfe/trunk/tools/libclang/CXCursor.cpp >>> URL: >>> http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=165473&r1=165472&r2=165473&view=diff >>> ============================================================================== >>> --- cfe/trunk/tools/libclang/CXCursor.cpp (original) >>> +++ cfe/trunk/tools/libclang/CXCursor.cpp Mon Oct 8 20:23:50 2012 >>> @@ -795,194 +795,20 @@ >>> return static_cast<CXTranslationUnit>(Cursor.data[2]); >>> } >>> >>> -static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU, >>> - ObjCContainerDecl *Container, >>> - ObjCMethodDecl *Method, >>> - SmallVectorImpl<CXCursor> &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<ObjCCategoryDecl>(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<ObjCProtocolDecl>(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<ObjCInterfaceDecl>(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<CXCursor> >>> &Methods) { >>> - CollectOverriddenMethodsRecurse(TU, Container, Method, Methods, >>> - /*MovedToSuper=*/false); >>> -} >>> - >>> -static void collectOverriddenMethodsSlow(CXTranslationUnit TU, >>> - ObjCMethodDecl *Method, >>> - SmallVectorImpl<CXCursor> >>> &overridden) { >>> - assert(Method->isOverriding()); >>> - >>> - if (ObjCProtocolDecl * >>> - ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) { >>> - CollectOverriddenMethods(TU, ProtD, Method, overridden); >>> - >>> - } else if (ObjCImplDecl * >>> - IMD = dyn_cast<ObjCImplDecl>(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<ObjCCategoryDecl>(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<ObjCContainerDecl>(Method->getDeclContext()), >>> - Method, overridden); >>> - } >>> -} >>> - >>> -static void collectOnCategoriesAfterLocation(SourceLocation Loc, >>> - ObjCInterfaceDecl *Class, >>> - CXTranslationUnit TU, >>> - ObjCMethodDecl *Method, >>> - SmallVectorImpl<CXCursor> >>> &Methods) { >>> - if (!Class) >>> - return; >>> - >>> - SourceManager &SM = static_cast<ASTUnit >>> *>(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<CXCursor> >>> &Methods) { >>> - assert(!Method->isOverriding()); >>> - >>> - ObjCContainerDecl *ContD = >>> cast<ObjCContainerDecl>(Method->getDeclContext()); >>> - if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD)) >>> - return; >>> - ObjCInterfaceDecl *Class = Method->getClassInterface(); >>> - if (!Class) >>> - return; >>> - >>> - collectOnCategoriesAfterLocation(Class->getLocation(), >>> Class->getSuperClass(), >>> - TU, Method, Methods); >>> -} >>> - >>> void cxcursor::getOverriddenCursors(CXCursor cursor, >>> SmallVectorImpl<CXCursor> &overridden) { >>> assert(clang_isDeclaration(cursor.kind)); >>> - Decl *D = getCursorDecl(cursor); >>> + const NamedDecl *D = dyn_cast_or_null<NamedDecl>(getCursorDecl(cursor)); >>> if (!D) >>> return; >>> >>> - // Handle C++ member functions. >>> CXTranslationUnit TU = getCursorTU(cursor); >>> - if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { >>> - for (CXXMethodDecl::method_iterator >>> - M = CXXMethod->begin_overridden_methods(), >>> - MEnd = CXXMethod->end_overridden_methods(); >>> - M != MEnd; ++M) >>> - overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), >>> TU)); >>> - return; >>> - } >>> - >>> - ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D); >>> - if (!Method) >>> - return; >>> - >>> - if (Method->isRedeclaration()) { >>> - Method = cast<ObjCContainerDecl>(Method->getDeclContext())-> >>> - getMethod(Method->getSelector(), >>> Method->isInstanceMethod()); >>> - } >>> + SmallVector<const NamedDecl *, 8> OverDecls; >>> + D->getASTContext().getOverriddenMethods(D, OverDecls); >>> >>> - 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<const NamedDecl *, 8>::iterator >>> + I = OverDecls.begin(), E = OverDecls.end(); I != E; ++I) { >>> + overridden.push_back(MakeCXCursor(const_cast<NamedDecl*>(*I), TU)); >>> } >>> } >>> >>> >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> [email protected] >>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >> > _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
