[cfe-commits] r115338 - in /cfe/trunk: include/clang-c/Index.h test/Index/local-symbols.m test/Index/overrides.cpp test/Index/overrides.m test/Index/properties-class-extensions.m tools/c-index-test/c-index-test.c tools/libclang/CIndex.cpp tools/libclang/libclang.darwin.exports tools/libclang/libclang.exports

Douglas Gregor dgregor at apple.com
Fri Oct 1 13:25:15 PDT 2010


Author: dgregor
Date: Fri Oct  1 15:25:15 2010
New Revision: 115338

URL: http://llvm.org/viewvc/llvm-project?rev=115338&view=rev
Log:
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.

Added:
    cfe/trunk/test/Index/overrides.cpp
    cfe/trunk/test/Index/overrides.m
Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/test/Index/local-symbols.m
    cfe/trunk/test/Index/properties-class-extensions.m
    cfe/trunk/tools/c-index-test/c-index-test.c
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/libclang.darwin.exports
    cfe/trunk/tools/libclang/libclang.exports

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=115338&r1=115337&r2=115338&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Fri Oct  1 15:25:15 2010
@@ -1417,7 +1417,59 @@
  * and the lexical context of the second \c C::f is the translation unit.
  */
 CINDEX_LINKAGE CXCursor clang_getCursorLexicalParent(CXCursor cursor);
-  
+
+/**
+ * \brief Determine the set of methods that are overridden by the given
+ * method.
+ *
+ * In both Objective-C and C++, a method (aka virtual member function,
+ * in C++) can override a virtual method in a base class. For
+ * Objective-C, a method is said to override any method in the class's
+ * interface (if we're coming from an implementation), its protocols,
+ * or its categories, that has the same selector and is of the same
+ * kind (class or instance). If no such method exists, the search
+ * continues to the class's superclass, its protocols, and its
+ * categories, and so on.
+ *
+ * For C++, a virtual member function overrides any virtual member
+ * function with the same signature that occurs in its base
+ * classes. With multiple inheritance, a virtual member function can
+ * override several virtual member functions coming from different
+ * base classes.
+ *
+ * In all cases, this function determines the immediate overridden
+ * method, rather than all of the overridden methods. For example, if
+ * a method is originally declared in a class A, then overridden in B
+ * (which in inherits from A) and also in C (which inherited from B),
+ * then the only overridden method returned from this function when
+ * invoked on C's method will be B's method. The client may then
+ * invoke this function again, given the previously-found overridden
+ * methods, to map out the complete method-override set.
+ *
+ * \param cursor A cursor representing an Objective-C or C++
+ * method. This routine will compute the set of methods that this
+ * method overrides.
+ * 
+ * \param overridden A pointer whose pointee will be replaced with a
+ * pointer to an array of cursors, representing the set of overridden
+ * methods. If there are no overridden methods, the pointee will be
+ * set to NULL. The pointee must be freed via a call to 
+ * \c clang_disposeOverriddenCursors().
+ *
+ * \param num_overridden A pointer to the number of overridden
+ * functions, will be set to the number of overridden functions in the
+ * array pointed to by \p overridden.
+ */
+CINDEX_LINKAGE void clang_getOverriddenCursors(CXCursor cursor, 
+                                               CXCursor **overridden,
+                                               unsigned *num_overridden);
+
+/**
+ * \brief Free the set of overridden cursors returned by \c
+ * clang_getOverriddenCursors().
+ */
+CINDEX_LINKAGE void clang_disposeOverriddenCursors(CXCursor *overridden);
+
 /**
  * @}
  */

Modified: cfe/trunk/test/Index/local-symbols.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/local-symbols.m?rev=115338&r1=115337&r2=115338&view=diff
==============================================================================
--- cfe/trunk/test/Index/local-symbols.m (original)
+++ cfe/trunk/test/Index/local-symbols.m Fri Oct  1 15:25:15 2010
@@ -32,7 +32,7 @@
 // CHECK: local-symbols.m:9:1: ObjCInstanceMethodDecl=bar:9:1 Extent=[9:1 - 9:12]
 // CHECK: local-symbols.m:9:4: TypeRef=id:0:0 Extent=[9:4 - 9:6]
 // CHECK: local-symbols.m:12:1: ObjCImplementationDecl=Foo:12:1 (Definition) Extent=[12:1 - 16:2]
-// CHECK: local-symbols.m:13:1: ObjCInstanceMethodDecl=bar:13:1 (Definition) Extent=[13:1 - 15:2]
+// CHECK: local-symbols.m:13:1: ObjCInstanceMethodDecl=bar:13:1 (Definition) [Overrides @9:1] Extent=[13:1 - 15:2]
 // CHECK: local-symbols.m:13:4: TypeRef=id:0:0 Extent=[13:4 - 13:6]
 // CHECK: local-symbols.m:14:10: UnexposedExpr= Extent=[14:10 - 14:11]
 // CHECK: local-symbols.m:14:10: UnexposedExpr= Extent=[14:10 - 14:11]

Added: cfe/trunk/test/Index/overrides.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/overrides.cpp?rev=115338&view=auto
==============================================================================
--- cfe/trunk/test/Index/overrides.cpp (added)
+++ cfe/trunk/test/Index/overrides.cpp Fri Oct  1 15:25:15 2010
@@ -0,0 +1,20 @@
+struct A {
+  virtual void f(int);
+};
+
+struct B {
+  virtual void f(int);
+  virtual void g();
+};
+
+struct C : B, A { 
+  virtual void g();
+};
+
+struct D : C {
+  virtual void f(int);
+};
+
+// RUN: c-index-test -test-load-source local %s | FileCheck %s
+// CHECK: overrides.cpp:11:16: CXXMethod=g:11:16 [Overrides @7:16] Extent=[11:16 - 11:19]
+// CHECK: overrides.cpp:15:16: CXXMethod=f:15:16 [Overrides @2:16, @6:16] Extent=[15:16 - 15:22]

Added: cfe/trunk/test/Index/overrides.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/overrides.m?rev=115338&view=auto
==============================================================================
--- cfe/trunk/test/Index/overrides.m (added)
+++ cfe/trunk/test/Index/overrides.m Fri Oct  1 15:25:15 2010
@@ -0,0 +1,35 @@
+
+ at protocol P1
+- (void)protoMethod;
+- (void)protoMethodWithParam:(int)param;
+ at end
+
+ at protocol P3
+- (void)protoMethod;
+ at end
+
+ at protocol P2 <P1>
+- (void)protoMethod;
+ at end
+
+ at interface A
+- (void)method;
++ (void)methodWithParam:(int)param;
+ at end
+
+ at interface B : A <P2, P3>
+- (void)method;
+- (void)protoMethod;
+ at end
+
+ at implementation B
+- (void)method { }
++ (void)methodWithParam:(int)param { }
+ at end
+
+// RUN: c-index-test -test-load-source local %s | FileCheck %s
+// CHECK: overrides.m:12:1: ObjCInstanceMethodDecl=protoMethod:12:1 [Overrides @3:1] Extent=[12:1 - 12:21]
+// CHECK: overrides.m:21:1: ObjCInstanceMethodDecl=method:21:1 [Overrides @16:1] Extent=[21:1 - 21:16]
+// CHECK: overrides.m:22:1: ObjCInstanceMethodDecl=protoMethod:22:1 [Overrides @12:1, @8:1] Extent=[22:1 - 22:21]
+// CHECK: overrides.m:26:1: ObjCInstanceMethodDecl=method:26:1 (Definition) [Overrides @21:1] Extent=[26:1 - 26:19]
+// CHECK: overrides.m:27:1: ObjCClassMethodDecl=methodWithParam::27:1 (Definition) [Overrides @17:1] Extent=[27:1 - 27:39]

Modified: cfe/trunk/test/Index/properties-class-extensions.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/properties-class-extensions.m?rev=115338&r1=115337&r2=115338&view=diff
==============================================================================
--- cfe/trunk/test/Index/properties-class-extensions.m (original)
+++ cfe/trunk/test/Index/properties-class-extensions.m Fri Oct  1 15:25:15 2010
@@ -80,7 +80,7 @@
 // CHECK: properties-class-extensions.m:30:12: ObjCClassRef=Rdar8467189_Foo:28:12 Extent=[30:12 - 30:27]
 // CHECK: properties-class-extensions.m:31:40: ObjCPropertyDecl=Rdar8467189_Bar:31:40 Extent=[31:40 - 31:55]
 // CHECK: properties-class-extensions.m:31:23: ObjCClassRef=Rdar8467189_Bar:24:8 Extent=[31:23 - 31:38]
-// CHECK: properties-class-extensions.m:31:40: ObjCInstanceMethodDecl=Rdar8467189_Bar:31:40 Extent=[31:40 - 31:55]
+// CHECK: properties-class-extensions.m:31:40: ObjCInstanceMethodDecl=Rdar8467189_Bar:31:40 [Overrides @26:39] Extent=[31:40 - 31:55]
 // CHECK: properties-class-extensions.m:31:40: ObjCInstanceMethodDecl=setRdar8467189_Bar::31:40 Extent=[31:40 - 31:55]
 // CHECK: properties-class-extensions.m:31:40: ParmDecl=Rdar8467189_Bar:31:40 (Definition) Extent=[31:40 - 31:55]
 // CHECK: properties-class-extensions.m:35:12: ObjCInterfaceDecl=Qux:35:12 Extent=[35:1 - 36:5]

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=115338&r1=115337&r2=115338&view=diff
==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Fri Oct  1 15:25:15 2010
@@ -167,7 +167,9 @@
     CXCursor Referenced;
     unsigned line, column;
     CXCursor SpecializationOf;
-    
+    CXCursor *overridden;
+    unsigned num_overridden;
+
     ks = clang_getCursorKindSpelling(Cursor.kind);
     string = clang_getCursorSpelling(Cursor);
     printf("%s=%s", clang_getCString(ks),
@@ -251,6 +253,21 @@
              clang_getCString(Name), line, column);
       clang_disposeString(Name);
     }
+
+    clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
+    if (num_overridden) {      
+      unsigned I;
+      printf(" [Overrides ");
+      for (I = 0; I != num_overridden; ++I) {
+        CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
+        clang_getInstantiationLocation(Loc, 0, &line, &column, 0);
+        if (I)
+          printf(", ");
+        printf("@%d:%d", line, column);
+      }
+      printf("]");
+      clang_disposeOverriddenCursors(overridden);
+    }
   }
 }
 

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=115338&r1=115337&r2=115338&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Fri Oct  1 15:25:15 2010
@@ -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"
 
 

Modified: cfe/trunk/tools/libclang/libclang.darwin.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.darwin.exports?rev=115338&r1=115337&r2=115338&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.darwin.exports (original)
+++ cfe/trunk/tools/libclang/libclang.darwin.exports Fri Oct  1 15:25:15 2010
@@ -21,6 +21,7 @@
 _clang_disposeCodeCompleteResults
 _clang_disposeDiagnostic
 _clang_disposeIndex
+_clang_disposeOverriddenCursors
 _clang_disposeString
 _clang_disposeTokens
 _clang_disposeTranslationUnit
@@ -77,6 +78,7 @@
 _clang_getNumDiagnostics
 _clang_getNumOverloadedDecls
 _clang_getOverloadedDecl
+_clang_getOverriddenCursors
 _clang_getPointeeType
 _clang_getRange
 _clang_getRangeEnd

Modified: cfe/trunk/tools/libclang/libclang.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.exports?rev=115338&r1=115337&r2=115338&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.exports (original)
+++ cfe/trunk/tools/libclang/libclang.exports Fri Oct  1 15:25:15 2010
@@ -21,6 +21,7 @@
 clang_disposeCodeCompleteResults
 clang_disposeDiagnostic
 clang_disposeIndex
+clang_disposeOverriddenCursors
 clang_disposeString
 clang_disposeTokens
 clang_disposeTranslationUnit
@@ -77,6 +78,7 @@
 clang_getNumDiagnostics
 clang_getNumOverloadedDecls
 clang_getOverloadedDecl
+clang_getOverriddenCursors
 clang_getPointeeType
 clang_getRange
 clang_getRangeEnd





More information about the cfe-commits mailing list