[clang] [cindex] Add API to query the class methods of a type (PR #123539)

Trevor Laughlin via cfe-commits cfe-commits at lists.llvm.org
Sat Mar 1 08:28:43 PST 2025


https://github.com/trelau updated https://github.com/llvm/llvm-project/pull/123539

>From bb0542e8f2ad50892ee9d2c1f76ec1def85c3e56 Mon Sep 17 00:00:00 2001
From: Trevor Laughlin <trevor.w.laughlin at gmail.com>
Date: Sun, 19 Jan 2025 19:21:10 -0500
Subject: [PATCH 1/6] [cindex] Add API to query the class methods of a type

---
 clang/bindings/python/clang/cindex.py         | 16 +++++++++++
 .../bindings/python/tests/cindex/test_type.py | 18 +++++++++++++
 clang/docs/ReleaseNotes.rst                   |  4 +++
 clang/include/clang-c/Index.h                 | 23 ++++++++++++++++
 clang/tools/libclang/CIndexCXX.cpp            | 27 +++++++++++++++++++
 clang/tools/libclang/libclang.map             |  1 +
 6 files changed, 89 insertions(+)

diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 806e1b40f3c9e..9e65ea2942d16 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2710,6 +2710,21 @@ def visitor(base, children):
         conf.lib.clang_visitCXXBaseClasses(self, fields_visit_callback(visitor), bases)
         return iter(bases)
 
+    def get_methods(self):
+        """Return an iterator for accessing the methods of this type."""
+
+        def visitor(method, children):
+            assert method != conf.lib.clang_getNullCursor()
+
+            # Create reference to TU so it isn't GC'd before Cursor.
+            method._tu = self._tu
+            methods.append(method)
+            return 1  # continue
+
+        methods: list[Cursor] = []
+        conf.lib.clang_visitCXXMethods(self, fields_visit_callback(visitor), methods)
+        return iter(methods)
+
     def get_exception_specification_kind(self):
         """
         Return the kind of the exception specification; a value from
@@ -4017,6 +4032,7 @@ def set_property(self, property, value):
     ),
     ("clang_visitChildren", [Cursor, cursor_visit_callback, py_object], c_uint),
     ("clang_visitCXXBaseClasses", [Type, fields_visit_callback, py_object], c_uint),
+    ("clang_visitCXXMethods", [Type, fields_visit_callback, py_object], c_uint),
     ("clang_Cursor_getNumArguments", [Cursor], c_int),
     ("clang_Cursor_getArgument", [Cursor, c_uint], Cursor),
     ("clang_Cursor_getNumTemplateArguments", [Cursor], c_int),
diff --git a/clang/bindings/python/tests/cindex/test_type.py b/clang/bindings/python/tests/cindex/test_type.py
index 9bac33f3041f4..bc893d509524e 100644
--- a/clang/bindings/python/tests/cindex/test_type.py
+++ b/clang/bindings/python/tests/cindex/test_type.py
@@ -559,3 +559,21 @@ class Template : public A, public B, virtual C {
         self.assertEqual(bases[1].get_base_offsetof(cursor_type_decl), 96)
         self.assertTrue(bases[2].is_virtual_base())
         self.assertEqual(bases[2].get_base_offsetof(cursor_type_decl), 128)
+
+    def test_class_methods(self):
+        source = """
+        template <typename T>
+        class Template { void Foo(); };
+        typedef Template<int> instance;
+        instance bar;
+        """
+        tu = get_tu(source, lang="cpp", flags=["--target=x86_64-linux-gnu"])
+        cursor = get_cursor(tu, "instance")
+        cursor_type = cursor.underlying_typedef_type
+        self.assertEqual(cursor.kind, CursorKind.TYPEDEF_DECL)
+        methods = list(cursor_type.get_methods())
+        self.assertEqual(len(methods), 4)
+        self.assertEqual(methods[0].kind, CursorKind.CXX_METHOD)
+        self.assertEqual(methods[1].kind, CursorKind.CONSTRUCTOR)
+        self.assertEqual(methods[2].kind, CursorKind.CONSTRUCTOR)
+        self.assertEqual(methods[3].kind, CursorKind.CONSTRUCTOR)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b02ac467cd3a2..dd9f722a6a08c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1241,6 +1241,8 @@ libclang
   of a class.
 - Added ``clang_getOffsetOfBase``, which allows computing the offset of a base
   class in a class's layout.
+- Added ``clang_visitCXXMethods``, which allows visiting the methods
+  of a class.
 
 Static Analyzer
 ---------------
@@ -1394,6 +1396,8 @@ Python Binding Changes
   allows visiting the base classes of a class.
 - Added ``Cursor.get_base_offsetof``, a binding for ``clang_getOffsetOfBase``,
   which allows computing the offset of a base class in a class's layout.
+- Added ``Type.get_methods``, a binding for ``clang_visitCXXMethods``, which
+  allows visiting the methods of a class.
 
 OpenMP Support
 --------------
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index aac5d1fa8aa2e..5d961ca0cdd7f 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -6680,6 +6680,29 @@ CINDEX_LINKAGE unsigned clang_visitCXXBaseClasses(CXType T,
                                                   CXFieldVisitor visitor,
                                                   CXClientData client_data);
 
+/**
+ * Visit the class methods of a type.
+ *
+ * This function visits all the methods of the given cursor,
+ * invoking the given \p visitor function with the cursors of each
+ * visited method. The traversal may be ended prematurely, if
+ * the visitor returns \c CXFieldVisit_Break.
+ *
+ * \param T the record type whose field may be visited.
+ *
+ * \param visitor the visitor function that will be invoked for each
+ * field of \p T.
+ *
+ * \param client_data pointer data supplied by the client, which will
+ * be passed to the visitor each time it is invoked.
+ *
+ * \returns a non-zero value if the traversal was terminated
+ * prematurely by the visitor returning \c CXFieldVisit_Break.
+ */
+CINDEX_LINKAGE unsigned clang_visitCXXMethods(CXType T,
+                                              CXFieldVisitor visitor,
+                                              CXClientData client_data);
+
 /**
  * Describes the kind of binary operators.
  */
diff --git a/clang/tools/libclang/CIndexCXX.cpp b/clang/tools/libclang/CIndexCXX.cpp
index 8b84fdc22ecff..4d8ff696950b3 100644
--- a/clang/tools/libclang/CIndexCXX.cpp
+++ b/clang/tools/libclang/CIndexCXX.cpp
@@ -54,6 +54,33 @@ unsigned clang_visitCXXBaseClasses(CXType PT, CXFieldVisitor visitor,
   return true;
 }
 
+unsigned clang_visitCXXMethods(CXType PT, CXFieldVisitor visitor,
+                               CXClientData client_data) {
+  CXCursor PC = clang_getTypeDeclaration(PT);
+  if (clang_isInvalid(PC.kind))
+    return false;
+  const CXXRecordDecl *RD =
+      dyn_cast_if_present<CXXRecordDecl>(cxcursor::getCursorDecl(PC));
+  if (!RD || RD->isInvalidDecl())
+    return false;
+  RD = RD->getDefinition();
+  if (!RD || RD->isInvalidDecl())
+    return false;
+
+  for (auto Method : RD->methods()) {
+    // Callback to the client.
+    switch (
+        visitor(cxcursor::MakeCXCursor(Method, getCursorTU(PC)),
+                client_data)) {
+    case CXVisit_Break:
+      return true;
+    case CXVisit_Continue:
+      break;
+    }
+  }
+  return true;
+}
+
 enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) {
   AccessSpecifier spec = AS_none;
 
diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map
index 8ca8a58b76d9e..a86c5a95303f8 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -440,6 +440,7 @@ LLVM_20 {
     clang_getTypePrettyPrinted;
     clang_isBeforeInTranslationUnit;
     clang_visitCXXBaseClasses;
+    clang_visitCXXMethods;
 };
 
 # Example of how to add a new symbol version entry.  If you do add a new symbol

>From 76a3b8f891216994cc586956524caef0b57de6cf Mon Sep 17 00:00:00 2001
From: Trevor Laughlin <trevor.w.laughlin at gmail.com>
Date: Sat, 15 Feb 2025 19:52:48 -0500
Subject: [PATCH 2/6] Update to const auto *Method

Co-authored-by: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
---
 clang/tools/libclang/CIndexCXX.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/tools/libclang/CIndexCXX.cpp b/clang/tools/libclang/CIndexCXX.cpp
index 4d8ff696950b3..cb4442da2e8d1 100644
--- a/clang/tools/libclang/CIndexCXX.cpp
+++ b/clang/tools/libclang/CIndexCXX.cpp
@@ -67,7 +67,7 @@ unsigned clang_visitCXXMethods(CXType PT, CXFieldVisitor visitor,
   if (!RD || RD->isInvalidDecl())
     return false;
 
-  for (auto Method : RD->methods()) {
+  for (const auto *Method : RD->methods()) {
     // Callback to the client.
     switch (
         visitor(cxcursor::MakeCXCursor(Method, getCursorTU(PC)),

>From 197eb868f253bf31b2d61efe7e654beaa7da2a16 Mon Sep 17 00:00:00 2001
From: Trevor Laughlin <trevor.w.laughlin at gmail.com>
Date: Fri, 21 Feb 2025 21:10:36 -0800
Subject: [PATCH 3/6] Fix capitalization

Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
 clang/include/clang-c/Index.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 622435b03bc1a..50cf464aa442f 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -6636,15 +6636,15 @@ CINDEX_LINKAGE unsigned clang_visitCXXBaseClasses(CXType T,
  * visited method. The traversal may be ended prematurely, if
  * the visitor returns \c CXFieldVisit_Break.
  *
- * \param T the record type whose field may be visited.
+ * \param T The record type whose field may be visited.
  *
- * \param visitor the visitor function that will be invoked for each
+ * \param visitor The visitor function that will be invoked for each
  * field of \p T.
  *
- * \param client_data pointer data supplied by the client, which will
+ * \param client_data Pointer data supplied by the client, which will
  * be passed to the visitor each time it is invoked.
  *
- * \returns a non-zero value if the traversal was terminated
+ * \returns A non-zero value if the traversal was terminated
  * prematurely by the visitor returning \c CXFieldVisit_Break.
  */
 CINDEX_LINKAGE unsigned clang_visitCXXMethods(CXType T,

>From ea948141ca368a5628766a5fd688c236b272fc39 Mon Sep 17 00:00:00 2001
From: Trevor Laughlin <trevor.w.laughlin at gmail.com>
Date: Fri, 21 Feb 2025 21:11:03 -0800
Subject: [PATCH 4/6] Use auto

Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
 clang/tools/libclang/CIndexCXX.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/tools/libclang/CIndexCXX.cpp b/clang/tools/libclang/CIndexCXX.cpp
index cb4442da2e8d1..1bb8ea8e69e47 100644
--- a/clang/tools/libclang/CIndexCXX.cpp
+++ b/clang/tools/libclang/CIndexCXX.cpp
@@ -59,7 +59,7 @@ unsigned clang_visitCXXMethods(CXType PT, CXFieldVisitor visitor,
   CXCursor PC = clang_getTypeDeclaration(PT);
   if (clang_isInvalid(PC.kind))
     return false;
-  const CXXRecordDecl *RD =
+  const auto *RD =
       dyn_cast_if_present<CXXRecordDecl>(cxcursor::getCursorDecl(PC));
   if (!RD || RD->isInvalidDecl())
     return false;

>From 4dd77c2c3685efcab1d38bdbcdfbd3a2442369ec Mon Sep 17 00:00:00 2001
From: Trevor Laughlin <trevor.w.laughlin at gmail.com>
Date: Sat, 1 Mar 2025 09:58:18 -0500
Subject: [PATCH 5/6] Fix clang code formatter

---
 clang/tools/libclang/CIndexCXX.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/tools/libclang/CIndexCXX.cpp b/clang/tools/libclang/CIndexCXX.cpp
index 1bb8ea8e69e47..605f3ef9a4a62 100644
--- a/clang/tools/libclang/CIndexCXX.cpp
+++ b/clang/tools/libclang/CIndexCXX.cpp
@@ -70,8 +70,7 @@ unsigned clang_visitCXXMethods(CXType PT, CXFieldVisitor visitor,
   for (const auto *Method : RD->methods()) {
     // Callback to the client.
     switch (
-        visitor(cxcursor::MakeCXCursor(Method, getCursorTU(PC)),
-                client_data)) {
+        visitor(cxcursor::MakeCXCursor(Method, getCursorTU(PC)), client_data)) {
     case CXVisit_Break:
       return true;
     case CXVisit_Continue:

>From 10d4b9ec837844285d63f1028b1165fbb09e9203 Mon Sep 17 00:00:00 2001
From: Trevor Laughlin <trevor.w.laughlin at gmail.com>
Date: Sat, 1 Mar 2025 11:28:32 -0500
Subject: [PATCH 6/6] Another clang format fix

---
 clang/include/clang-c/Index.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 50cf464aa442f..3a511de553ad4 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -6647,8 +6647,7 @@ CINDEX_LINKAGE unsigned clang_visitCXXBaseClasses(CXType T,
  * \returns A non-zero value if the traversal was terminated
  * prematurely by the visitor returning \c CXFieldVisit_Break.
  */
-CINDEX_LINKAGE unsigned clang_visitCXXMethods(CXType T,
-                                              CXFieldVisitor visitor,
+CINDEX_LINKAGE unsigned clang_visitCXXMethods(CXType T, CXFieldVisitor visitor,
                                               CXClientData client_data);
 
 /**



More information about the cfe-commits mailing list