[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@gmail.com> Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
This commit is contained in:
parent
fe18796142
commit
304c053a5c
@ -2713,6 +2713,21 @@ class Type(Structure):
|
||||
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 @@ functionList: list[LibFunc] = [
|
||||
),
|
||||
("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),
|
||||
|
@ -559,3 +559,21 @@ class A
|
||||
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)
|
||||
|
@ -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
|
||||
--------------
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user