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.vladis...@gmail.com> Co-authored-by: Aaron Ballman <aa...@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits