Skip to content

Commit 304c053

Browse files
trelauEndilllAaronBallman
authored
[cindex] Add API to query the class methods of a type (#123539)
Inspired by #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@gmail.com> Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
1 parent fe18796 commit 304c053

File tree

6 files changed

+87
-0
lines changed

6 files changed

+87
-0
lines changed

clang/bindings/python/clang/cindex.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,21 @@ def visitor(base, children):
27132713
conf.lib.clang_visitCXXBaseClasses(self, fields_visit_callback(visitor), bases)
27142714
return iter(bases)
27152715

2716+
def get_methods(self):
2717+
"""Return an iterator for accessing the methods of this type."""
2718+
2719+
def visitor(method, children):
2720+
assert method != conf.lib.clang_getNullCursor()
2721+
2722+
# Create reference to TU so it isn't GC'd before Cursor.
2723+
method._tu = self._tu
2724+
methods.append(method)
2725+
return 1 # continue
2726+
2727+
methods: list[Cursor] = []
2728+
conf.lib.clang_visitCXXMethods(self, fields_visit_callback(visitor), methods)
2729+
return iter(methods)
2730+
27162731
def get_exception_specification_kind(self):
27172732
"""
27182733
Return the kind of the exception specification; a value from
@@ -4020,6 +4035,7 @@ def set_property(self, property, value):
40204035
),
40214036
("clang_visitChildren", [Cursor, cursor_visit_callback, py_object], c_uint),
40224037
("clang_visitCXXBaseClasses", [Type, fields_visit_callback, py_object], c_uint),
4038+
("clang_visitCXXMethods", [Type, fields_visit_callback, py_object], c_uint),
40234039
("clang_Cursor_getNumArguments", [Cursor], c_int),
40244040
("clang_Cursor_getArgument", [Cursor, c_uint], Cursor),
40254041
("clang_Cursor_getNumTemplateArguments", [Cursor], c_int),

clang/bindings/python/tests/cindex/test_type.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,21 @@ class Template : public A, public B, virtual C {
559559
self.assertEqual(bases[1].get_base_offsetof(cursor_type_decl), 96)
560560
self.assertTrue(bases[2].is_virtual_base())
561561
self.assertEqual(bases[2].get_base_offsetof(cursor_type_decl), 128)
562+
563+
def test_class_methods(self):
564+
source = """
565+
template <typename T>
566+
class Template { void Foo(); };
567+
typedef Template<int> instance;
568+
instance bar;
569+
"""
570+
tu = get_tu(source, lang="cpp", flags=["--target=x86_64-linux-gnu"])
571+
cursor = get_cursor(tu, "instance")
572+
cursor_type = cursor.underlying_typedef_type
573+
self.assertEqual(cursor.kind, CursorKind.TYPEDEF_DECL)
574+
methods = list(cursor_type.get_methods())
575+
self.assertEqual(len(methods), 4)
576+
self.assertEqual(methods[0].kind, CursorKind.CXX_METHOD)
577+
self.assertEqual(methods[1].kind, CursorKind.CONSTRUCTOR)
578+
self.assertEqual(methods[2].kind, CursorKind.CONSTRUCTOR)
579+
self.assertEqual(methods[3].kind, CursorKind.CONSTRUCTOR)

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ clang-format
349349

350350
libclang
351351
--------
352+
- Added ``clang_visitCXXMethods``, which allows visiting the methods
353+
of a class.
352354

353355
- Fixed a buffer overflow in ``CXString`` implementation. The fix may result in
354356
increased memory allocation.
@@ -388,6 +390,8 @@ Sanitizers
388390

389391
Python Binding Changes
390392
----------------------
393+
- Added ``Type.get_methods``, a binding for ``clang_visitCXXMethods``, which
394+
allows visiting the methods of a class.
391395

392396
OpenMP Support
393397
--------------

clang/include/clang-c/Index.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6628,6 +6628,28 @@ CINDEX_LINKAGE unsigned clang_visitCXXBaseClasses(CXType T,
66286628
CXFieldVisitor visitor,
66296629
CXClientData client_data);
66306630

6631+
/**
6632+
* Visit the class methods of a type.
6633+
*
6634+
* This function visits all the methods of the given cursor,
6635+
* invoking the given \p visitor function with the cursors of each
6636+
* visited method. The traversal may be ended prematurely, if
6637+
* the visitor returns \c CXFieldVisit_Break.
6638+
*
6639+
* \param T The record type whose field may be visited.
6640+
*
6641+
* \param visitor The visitor function that will be invoked for each
6642+
* field of \p T.
6643+
*
6644+
* \param client_data Pointer data supplied by the client, which will
6645+
* be passed to the visitor each time it is invoked.
6646+
*
6647+
* \returns A non-zero value if the traversal was terminated
6648+
* prematurely by the visitor returning \c CXFieldVisit_Break.
6649+
*/
6650+
CINDEX_LINKAGE unsigned clang_visitCXXMethods(CXType T, CXFieldVisitor visitor,
6651+
CXClientData client_data);
6652+
66316653
/**
66326654
* Describes the kind of binary operators.
66336655
*/

clang/tools/libclang/CIndexCXX.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,32 @@ unsigned clang_visitCXXBaseClasses(CXType PT, CXFieldVisitor visitor,
5454
return true;
5555
}
5656

57+
unsigned clang_visitCXXMethods(CXType PT, CXFieldVisitor visitor,
58+
CXClientData client_data) {
59+
CXCursor PC = clang_getTypeDeclaration(PT);
60+
if (clang_isInvalid(PC.kind))
61+
return false;
62+
const auto *RD =
63+
dyn_cast_if_present<CXXRecordDecl>(cxcursor::getCursorDecl(PC));
64+
if (!RD || RD->isInvalidDecl())
65+
return false;
66+
RD = RD->getDefinition();
67+
if (!RD || RD->isInvalidDecl())
68+
return false;
69+
70+
for (const auto *Method : RD->methods()) {
71+
// Callback to the client.
72+
switch (
73+
visitor(cxcursor::MakeCXCursor(Method, getCursorTU(PC)), client_data)) {
74+
case CXVisit_Break:
75+
return true;
76+
case CXVisit_Continue:
77+
break;
78+
}
79+
}
80+
return true;
81+
}
82+
5783
enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) {
5884
AccessSpecifier spec = AS_none;
5985

clang/tools/libclang/libclang.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ LLVM_20 {
435435
clang_getTypePrettyPrinted;
436436
clang_isBeforeInTranslationUnit;
437437
clang_visitCXXBaseClasses;
438+
clang_visitCXXMethods;
438439
};
439440

440441
# Example of how to add a new symbol version entry. If you do add a new symbol

0 commit comments

Comments
 (0)