Extend libclang with an API that determines, given a C++ virtual
member function or an Objective-C method, which other member
functions/methods it overrides.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@115338 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index f419062..a291f47 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -4065,6 +4065,117 @@
   return clang_getNullCursor();
 }
 
+static void CollectOverriddenMethods(DeclContext *Ctx, 
+                                     ObjCMethodDecl *Method,
+                            llvm::SmallVectorImpl<ObjCMethodDecl *> &Methods) {
+  if (!Ctx)
+    return;
+
+  // If we have a class or category implementation, jump straight to the 
+  // interface.
+  if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(Ctx))
+    return CollectOverriddenMethods(Impl->getClassInterface(), Method, Methods);
+  
+  ObjCContainerDecl *Container = dyn_cast<ObjCContainerDecl>(Ctx);
+  if (!Container)
+    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(Overridden);
+      return;
+    }
+
+  if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
+    for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
+                                          PEnd = Protocol->protocol_end();
+         P != PEnd; ++P)
+      CollectOverriddenMethods(*P, Method, Methods);
+  }
+
+  if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+    for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
+                                          PEnd = Category->protocol_end();
+         P != PEnd; ++P)
+      CollectOverriddenMethods(*P, Method, Methods);
+  }
+
+  if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
+    for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
+                                           PEnd = Interface->protocol_end();
+         P != PEnd; ++P)
+      CollectOverriddenMethods(*P, Method, Methods);
+
+    for (ObjCCategoryDecl *Category = Interface->getCategoryList();
+         Category; Category = Category->getNextClassCategory())
+      CollectOverriddenMethods(Category, Method, Methods);
+
+    // We only look into the superclass if we haven't found anything yet.
+    if (Methods.empty())
+      if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
+        return CollectOverriddenMethods(Super, Method, Methods);
+  }
+}
+
+void clang_getOverriddenCursors(CXCursor cursor, 
+                                CXCursor **overridden,
+                                unsigned *num_overridden) {
+  if (overridden)
+    *overridden = 0;
+  if (num_overridden)
+    *num_overridden = 0;
+  if (!overridden || !num_overridden)
+    return;
+
+  if (!clang_isDeclaration(cursor.kind))
+    return;
+
+  Decl *D = getCursorDecl(cursor);
+  if (!D)
+    return;
+
+  // Handle C++ member functions.
+  ASTUnit *CXXUnit = getCursorASTUnit(cursor);
+  if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
+    *num_overridden = CXXMethod->size_overridden_methods();
+    if (!*num_overridden)
+      return;
+
+    *overridden = new CXCursor [*num_overridden];
+    unsigned I = 0;
+    for (CXXMethodDecl::method_iterator
+              M = CXXMethod->begin_overridden_methods(),
+           MEnd = CXXMethod->end_overridden_methods();
+         M != MEnd; (void)++M, ++I)
+      (*overridden)[I] = MakeCXCursor(const_cast<CXXMethodDecl*>(*M), CXXUnit);
+    return;
+  }
+
+  ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
+  if (!Method)
+    return;
+
+  // Handle Objective-C methods.
+  llvm::SmallVector<ObjCMethodDecl *, 4> Methods;
+  CollectOverriddenMethods(Method->getDeclContext(), Method, Methods);
+
+  if (Methods.empty())
+    return;
+
+  *num_overridden = Methods.size();
+  *overridden = new CXCursor [Methods.size()];
+  for (unsigned I = 0, N = Methods.size(); I != N; ++I)
+    (*overridden)[I] = MakeCXCursor(Methods[I], CXXUnit);  
+}
+
+void clang_disposeOverriddenCursors(CXCursor *overridden) {
+  delete [] overridden;
+}
+
 } // end: extern "C"