[clang] 304c053 - [cindex] Add API to query the class methods of a type (#123539)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 1 12:59:29 PST 2025
Author: Trevor Laughlin
Date: 2025-03-02T00:59:26+04:00
New Revision: 304c053a5c7b8a67f6f3fddf9492971a57901715
URL: https://github.com/llvm/llvm-project/commit/304c053a5c7b8a67f6f3fddf9492971a57901715
DIFF: https://github.com/llvm/llvm-project/commit/304c053a5c7b8a67f6f3fddf9492971a57901715.diff
LOG: [cindex] Add API to query the class methods of a type (#123539)
Inspired by https://github.com/llvm/llvm-project/pull/120300, add a new
API `clang_visitCXXMethods` to libclang (and the Python bindings) which
allows iterating over the class methods of a type.
---------
Co-authored-by: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
Added:
Modified:
clang/bindings/python/clang/cindex.py
clang/bindings/python/tests/cindex/test_type.py
clang/docs/ReleaseNotes.rst
clang/include/clang-c/Index.h
clang/tools/libclang/CIndexCXX.cpp
clang/tools/libclang/libclang.map
Removed:
################################################################################
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 722562220eeea..879a0a3c5c58c 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2713,6 +2713,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
@@ -4020,6 +4035,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 7873c2048e53c..c4377c842cd96 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -349,6 +349,8 @@ clang-format
libclang
--------
+- Added ``clang_visitCXXMethods``, which allows visiting the methods
+ of a class.
- Fixed a buffer overflow in ``CXString`` implementation. The fix may result in
increased memory allocation.
@@ -388,6 +390,8 @@ Sanitizers
Python Binding Changes
----------------------
+- 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 ed6bd797684d9..3a511de553ad4 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -6628,6 +6628,28 @@ 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..605f3ef9a4a62 100644
--- a/clang/tools/libclang/CIndexCXX.cpp
+++ b/clang/tools/libclang/CIndexCXX.cpp
@@ -54,6 +54,32 @@ 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 auto *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 (const 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 600f86f00aaea..07471ca42c97e 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -435,6 +435,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
More information about the cfe-commits
mailing list