[cfe-commits] r165473 - in /cfe/trunk: include/clang/AST/ASTContext.h lib/AST/ASTContext.cpp tools/libclang/CXCursor.cpp

Argyrios Kyrtzidis kyrtzidis at apple.com
Tue Oct 9 11:33:17 PDT 2012


On Oct 9, 2012, at 10:25 AM, Argyrios Kyrtzidis <kyrtzidis at apple.com> wrote:

> On Oct 9, 2012, at 9:42 AM, Jordan Rose <jordan_rose at apple.com> 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 <akyrtzi at gmail.com> 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
>>> cfe-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>> 
> 




More information about the cfe-commits mailing list