https://github.com/fscheidl updated https://github.com/llvm/llvm-project/pull/183305
>From a0f8fcbebc23af700a38509622898600934b5c6e Mon Sep 17 00:00:00 2001 From: Fabian Scheidl <[email protected]> Date: Mon, 9 Mar 2026 14:19:47 +0100 Subject: [PATCH 1/2] [libclang] Add clang_CXXMethod_isVolatile and clang_Cursor_isConstexpr --- clang/bindings/python/clang/cindex.py | 27 ++++++ .../python/tests/cindex/test_cursor.py | 93 +++++++++++++++++++ clang/docs/ReleaseNotes.rst | 4 + clang/include/clang-c/Index.h | 28 ++++++ clang/test/Index/cursor-properties.cpp | 22 +++++ clang/tools/c-index-test/c-index-test.c | 13 ++- clang/tools/libclang/CIndex.cpp | 33 +++++++ clang/tools/libclang/libclang.map | 2 + 8 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 clang/test/Index/cursor-properties.cpp diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index b71f9ed2275e0..7d3b54af3f8a5 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -1636,6 +1636,18 @@ def inner(self, *args, **kwargs): return inner +class Qualifiers(Structure): + """Represents the set of qualifiers (const, volatile, __restrict) + of a C++ member function or member function template. + """ + + _fields_ = [ + ("Const", c_uint, 1), + ("Volatile", c_uint, 1), + ("Restrict", c_uint, 1), + ] + + class Cursor(Structure): """ The Cursor class represents a reference to an element within the AST. It @@ -1685,6 +1697,14 @@ def is_const_method(self) -> bool: """ return bool(conf.lib.clang_CXXMethod_isConst(self)) + @cursor_null_guard + def get_method_qualifiers(self) -> Qualifiers: + """Returns the set of qualifiers for a C++ member function or member + function template. If the cursor does not refer to a C++ member function + or member function template, a zero-initialized Qualifiers is returned. + """ + return conf.lib.clang_CXXMethod_getQualifiers(self) + @cursor_null_guard def is_converting_constructor(self) -> bool: """Returns True if the cursor refers to a C++ converting constructor.""" @@ -1857,6 +1877,11 @@ def is_scoped_enum(self) -> bool: """Returns True if the cursor refers to a scoped enum declaration.""" return bool(conf.lib.clang_EnumDecl_isScoped(self)) + @cursor_null_guard + def is_constexpr(self) -> bool: + """Returns True if the cursor refers to a constexpr declaration.""" + return bool(conf.lib.clang_Cursor_isConstexpr(self)) + @cursor_null_guard def get_definition(self) -> Cursor | None: """ @@ -4306,6 +4331,7 @@ def set_property(self, property, value): ("clang_CXXConstructor_isMoveConstructor", [Cursor], c_uint), ("clang_CXXField_isMutable", [Cursor], c_uint), ("clang_CXXMethod_isConst", [Cursor], c_uint), + ("clang_CXXMethod_getQualifiers", [Cursor], Qualifiers), ("clang_CXXMethod_isDefaulted", [Cursor], c_uint), ("clang_CXXMethod_isDeleted", [Cursor], c_uint), ("clang_CXXMethod_isCopyAssignmentOperator", [Cursor], c_uint), @@ -4492,6 +4518,7 @@ def set_property(self, property, value): ("clang_Cursor_isAnonymousRecordDecl", [Cursor], c_uint), ("clang_Cursor_isBitField", [Cursor], c_uint), ("clang_Cursor_isFunctionInlined", [Cursor], c_uint), + ("clang_Cursor_isConstexpr", [Cursor], c_uint), ("clang_Location_isInSystemHeader", [SourceLocation], c_int), ("clang_PrintingPolicy_dispose", [PrintingPolicy]), ("clang_PrintingPolicy_getProperty", [PrintingPolicy, c_int], c_uint), diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py index 76680e576b307..13b848170b069 100644 --- a/clang/bindings/python/tests/cindex/test_cursor.py +++ b/clang/bindings/python/tests/cindex/test_cursor.py @@ -1,6 +1,7 @@ from clang.cindex import ( AvailabilityKind, BinaryOperator, + Qualifiers, Cursor, CursorKind, PrintingPolicy, @@ -197,6 +198,64 @@ def test_is_const_method(self): self.assertTrue(foo.is_const_method()) self.assertFalse(bar.is_const_method()) + def test_get_method_qualifiers(self): + """Ensure Cursor.get_method_qualifiers works.""" + source = """ + class X { + void unqualified(); + void c() const; + void v() volatile; + void cv() const volatile; + void r() __restrict; + void cvr() const volatile __restrict; + }; + """ + tu = get_tu(source, lang="cpp") + + unqualified = get_cursor(tu, "unqualified") + c = get_cursor(tu, "c") + v = get_cursor(tu, "v") + cv = get_cursor(tu, "cv") + r = get_cursor(tu, "r") + cvr = get_cursor(tu, "cvr") + self.assertIsNotNone(unqualified) + self.assertIsNotNone(c) + self.assertIsNotNone(v) + self.assertIsNotNone(cv) + self.assertIsNotNone(r) + self.assertIsNotNone(cvr) + + q = unqualified.get_method_qualifiers() + self.assertIsInstance(q, Qualifiers) + self.assertFalse(q.Const) + self.assertFalse(q.Volatile) + self.assertFalse(q.Restrict) + + q = c.get_method_qualifiers() + self.assertTrue(q.Const) + self.assertFalse(q.Volatile) + self.assertFalse(q.Restrict) + + q = v.get_method_qualifiers() + self.assertFalse(q.Const) + self.assertTrue(q.Volatile) + self.assertFalse(q.Restrict) + + q = cv.get_method_qualifiers() + self.assertTrue(q.Const) + self.assertTrue(q.Volatile) + self.assertFalse(q.Restrict) + + q = r.get_method_qualifiers() + self.assertFalse(q.Const) + self.assertFalse(q.Volatile) + self.assertTrue(q.Restrict) + + q = cvr.get_method_qualifiers() + self.assertTrue(q.Const) + self.assertTrue(q.Volatile) + self.assertTrue(q.Restrict) + def test_is_converting_constructor(self): """Ensure Cursor.is_converting_constructor works.""" source = "class X { explicit X(int); X(double); X(); };" @@ -565,6 +624,40 @@ def test_is_scoped_enum(self): self.assertFalse(regular_enum.is_scoped_enum()) self.assertTrue(scoped_enum.is_scoped_enum()) + def test_is_constexpr(self): + """Ensure Cursor.is_constexpr works.""" + source = """ + constexpr int x = 42; + int y = 1; + struct S { + constexpr int foo() { return 1; } + int bar() { return 2; } + }; + template<typename T> constexpr T tmpl(T v) { return v; } + template<typename T> T tmpl_nc(T v) { return v; } + """ + tu = get_tu(source, lang="cpp", flags=["--std=c++14"]) + + x = get_cursor(tu, "x") + y = get_cursor(tu, "y") + foo = get_cursor(tu, "foo") + bar = get_cursor(tu, "bar") + tmpl = get_cursor(tu, "tmpl") + tmpl_nc = get_cursor(tu, "tmpl_nc") + self.assertIsNotNone(x) + self.assertIsNotNone(y) + self.assertIsNotNone(foo) + self.assertIsNotNone(bar) + self.assertIsNotNone(tmpl) + self.assertIsNotNone(tmpl_nc) + + self.assertTrue(x.is_constexpr()) + self.assertFalse(y.is_constexpr()) + self.assertTrue(foo.is_constexpr()) + self.assertFalse(bar.is_constexpr()) + self.assertTrue(tmpl.is_constexpr()) + self.assertFalse(tmpl_nc.is_constexpr()) + def test_get_definition(self): """Ensure Cursor.get_definition works.""" tu = get_tu( diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2da7175b51ea3..9d4069d2479ac 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -583,6 +583,8 @@ libclang - Visit switch initializer statements (https://bugs.kde.org/show_bug.cgi?id=415537#c2) - Fix crash in clang_getBinaryOperatorKindSpelling and clang_getUnaryOperatorKindSpelling - The clang_Module_getASTFile API is deprecated and now always returns nullptr +- Added ``clang_CXXMethod_getQualifiers`` to query const/volatile/__restrict qualifiers of a member function. +- Added ``clang_Cursor_isConstexpr`` to determine if a cursor refers to a constexpr declaration. Code Completion --------------- @@ -623,6 +625,8 @@ Python Binding Changes so it can be used the same as ``CodeCompletionResults.results``. - Added a new helper method ``get_clang_version`` to the class ``Config`` to read the version string of the libclang in use. +- Added ``Cursor.get_method_qualifiers``, a binding for ``clang_CXXMethod_getQualifiers``. +- Added ``Cursor.is_constexpr``, a binding for ``clang_Cursor_isConstexpr``. OpenMP Support -------------- diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index dcf1f4f1b4258..9ae9824b65c43 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3351,6 +3351,14 @@ CINDEX_LINKAGE unsigned clang_Cursor_isMacroBuiltin(CXCursor C); */ CINDEX_LINKAGE unsigned clang_Cursor_isFunctionInlined(CXCursor C); +/** + * Determine whether a cursor refers to a constexpr declaration. + * + * If the cursor does not refer to a constexpr variable or function + * declaration, 0 is returned. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isConstexpr(CXCursor C); + /** * Determine whether a CXType has the "volatile" qualifier set, * without looking through typedefs that may have added "volatile" at @@ -4885,6 +4893,26 @@ CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C); */ CINDEX_LINKAGE unsigned clang_CXXMethod_isConst(CXCursor C); +/** + * Set of qualifiers (const, volatile, __restrict) of a C++ member function + * or member function template. + */ +typedef struct { + unsigned Const : 1; + unsigned Volatile : 1; + unsigned Restrict : 1; + unsigned /*Reserved for other qualifiers*/ : 29; +} CXQualifiers; + +/** + * Retrieve the set of qualifiers for a C++ member function or member + * function template. + * + * If the cursor does not refer to a C++ member function or member function + * template, a zero-initialized CXQualifiers is returned. + */ +CINDEX_LINKAGE CXQualifiers clang_CXXMethod_getQualifiers(CXCursor C); + /** * Given a cursor that represents a template, determine * the cursor kind of the specializations would be generated by instantiating diff --git a/clang/test/Index/cursor-properties.cpp b/clang/test/Index/cursor-properties.cpp new file mode 100644 index 0000000000000..ad9dc3efa2abe --- /dev/null +++ b/clang/test/Index/cursor-properties.cpp @@ -0,0 +1,22 @@ +struct Foo { + void normal(); + void c() const; + void v() volatile; + void cv() const volatile; + void r() __restrict; + void cvr() const volatile __restrict; + constexpr int baz() { return 1; } +}; +constexpr int x = 42; +int y = 1; + +// RUN: c-index-test -test-print-type --std=c++14 %s | FileCheck %s +// CHECK: CXXMethod=normal:2:8 [type=void ()] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] +// CHECK: CXXMethod=c:3:8 (const) [type=void () const] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] +// CHECK: CXXMethod=v:4:8 (volatile) [type=void () volatile] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] +// CHECK: CXXMethod=cv:5:8 (const) (volatile) [type=void () const volatile] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] +// CHECK: CXXMethod=r:6:8 (restrict) [type=void () __restrict] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] +// CHECK: CXXMethod=cvr:7:8 (const) (volatile) (restrict) [type=void () const volatile __restrict] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] +// CHECK: CXXMethod=baz:8:17 (Definition) (constexpr) [type=int ()] [typekind=FunctionProto] [resulttype=int] [resulttypekind=Int] [isPOD=0] +// CHECK: VarDecl=x:10:15 (Definition) (constexpr) [type=const int] [typekind=Int] const [isPOD=1] +// CHECK: VarDecl=y:11:5 (Definition) [type=int] [typekind=Int] [isPOD=1] diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 4b3e105aa7aff..bd863840f2ed7 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -952,8 +952,15 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { printf(" (static)"); if (clang_CXXMethod_isVirtual(Cursor)) printf(" (virtual)"); - if (clang_CXXMethod_isConst(Cursor)) - printf(" (const)"); + { + CXQualifiers Q = clang_CXXMethod_getQualifiers(Cursor); + if (Q.Const) + printf(" (const)"); + if (Q.Volatile) + printf(" (volatile)"); + if (Q.Restrict) + printf(" (restrict)"); + } if (clang_CXXMethod_isPureVirtual(Cursor)) printf(" (pure)"); if (clang_CXXMethod_isCopyAssignmentOperator(Cursor)) @@ -966,6 +973,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { printf(" (abstract)"); if (clang_EnumDecl_isScoped(Cursor)) printf(" (scoped)"); + if (clang_Cursor_isConstexpr(Cursor)) + printf(" (constexpr)"); if (clang_Cursor_isVariadic(Cursor)) printf(" (variadic)"); if (clang_Cursor_isObjCOptional(Cursor)) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 3ee37ed2dfc27..2a887cdfb7f58 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -9533,6 +9533,23 @@ unsigned clang_CXXMethod_isConst(CXCursor C) { return (Method && Method->getMethodQualifiers().hasConst()) ? 1 : 0; } +CXQualifiers clang_CXXMethod_getQualifiers(CXCursor C) { + CXQualifiers Q = {}; + if (!clang_isDeclaration(C.kind)) + return Q; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXMethodDecl *Method = + D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; + if (Method) { + Qualifiers MQ = Method->getMethodQualifiers(); + Q.Const = MQ.hasConst(); + Q.Volatile = MQ.hasVolatile(); + Q.Restrict = MQ.hasRestrict(); + } + return Q; +} + unsigned clang_CXXMethod_isDefaulted(CXCursor C) { if (!clang_isDeclaration(C.kind)) return 0; @@ -9614,6 +9631,22 @@ unsigned clang_CXXMethod_isExplicit(CXCursor C) { return 0; } +unsigned clang_Cursor_isConstexpr(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return 0; + + if (const auto *VD = dyn_cast<VarDecl>(D)) + return VD->isConstexpr(); + if (const FunctionDecl *FD = D->getAsFunction()) + return FD->isConstexpr(); + + return 0; +} + unsigned clang_CXXRecord_isAbstract(CXCursor C) { if (!clang_isDeclaration(C.kind)) return 0; diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map index 2691602d432f6..c33579219d42b 100644 --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -460,6 +460,8 @@ LLVM_21 { LLVM_23 { global: clang_ModuleCache_prune; + clang_Cursor_isConstexpr; + clang_CXXMethod_getQualifiers; }; # Example of how to add a new symbol version entry. If you do add a new symbol >From 6acaf02df235d9aa648b251b5a3432329997ba48 Mon Sep 17 00:00:00 2001 From: Fabian Scheidl <[email protected]> Date: Tue, 7 Apr 2026 19:10:41 +0200 Subject: [PATCH 2/2] [libclang] Add clang_CXXMethod_isExplicitObjectMemberFunction --- clang/bindings/python/clang/cindex.py | 10 ++++ .../python/tests/cindex/test_cursor.py | 46 ++++++++++++++++++- clang/docs/ReleaseNotes.rst | 4 ++ clang/include/clang-c/Index.h | 11 +++++ clang/test/Index/cursor-properties.cpp | 11 ++++- clang/tools/c-index-test/c-index-test.c | 2 + clang/tools/libclang/CIndex.cpp | 10 ++++ clang/tools/libclang/libclang.map | 1 + 8 files changed, 92 insertions(+), 3 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 7d3b54af3f8a5..2c55171c1101d 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -1837,6 +1837,15 @@ class Foo { """ return bool(conf.lib.clang_CXXMethod_isExplicit(self)) + @cursor_null_guard + def is_explicit_object_member_function(self) -> bool: + """Returns True if the cursor refers to a C++ member function with an + explicit object parameter (C++23). + """ + return bool( + conf.lib.clang_CXXMethod_isExplicitObjectMemberFunction(self) + ) + @cursor_null_guard def is_mutable_field(self) -> bool: """Returns True if the cursor refers to a C++ field that is declared @@ -4337,6 +4346,7 @@ def set_property(self, property, value): ("clang_CXXMethod_isCopyAssignmentOperator", [Cursor], c_uint), ("clang_CXXMethod_isMoveAssignmentOperator", [Cursor], c_uint), ("clang_CXXMethod_isExplicit", [Cursor], c_uint), + ("clang_CXXMethod_isExplicitObjectMemberFunction", [Cursor], c_uint), ("clang_CXXMethod_isPureVirtual", [Cursor], c_uint), ("clang_CXXMethod_isStatic", [Cursor], c_uint), ("clang_CXXMethod_isVirtual", [Cursor], c_uint), diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py index 13b848170b069..bcb81cde04087 100644 --- a/clang/bindings/python/tests/cindex/test_cursor.py +++ b/clang/bindings/python/tests/cindex/test_cursor.py @@ -1,11 +1,11 @@ from clang.cindex import ( AvailabilityKind, BinaryOperator, - Qualifiers, Cursor, CursorKind, PrintingPolicy, PrintingPolicyProperty, + Qualifiers, StorageClass, TemplateArgumentKind, TranslationUnit, @@ -256,6 +256,29 @@ class X { self.assertTrue(q.Volatile) self.assertTrue(q.Restrict) + # Explicit object member functions have no method qualifiers + source = """ + struct S { + void explicit_const(this const S&); + void explicit_cv(this const volatile S&); + }; + """ + tu = get_tu(source, lang="cpp", flags=["-std=c++23"]) + ec = get_cursor(tu, "explicit_const") + ecv = get_cursor(tu, "explicit_cv") + self.assertIsNotNone(ec) + self.assertIsNotNone(ecv) + + q = ec.get_method_qualifiers() + self.assertFalse(q.Const) + self.assertFalse(q.Volatile) + self.assertFalse(q.Restrict) + + q = ecv.get_method_qualifiers() + self.assertFalse(q.Const) + self.assertFalse(q.Volatile) + self.assertFalse(q.Restrict) + def test_is_converting_constructor(self): """Ensure Cursor.is_converting_constructor works.""" source = "class X { explicit X(int); X(double); X(); };" @@ -567,6 +590,25 @@ def test_is_static_method(self): self.assertTrue(foo.is_static_method()) self.assertFalse(bar.is_static_method()) + def test_is_explicit_object_member_function(self): + source = """ + struct S { + void regular(); + void explicit_obj(this const S&); + static void static_method(); + }; + """ + tu = get_tu(source, lang="cpp", flags=["-std=c++23"]) + regular = get_cursor(tu, "regular") + explicit_obj = get_cursor(tu, "explicit_obj") + static_method = get_cursor(tu, "static_method") + self.assertIsNotNone(regular) + self.assertIsNotNone(explicit_obj) + self.assertIsNotNone(static_method) + self.assertFalse(regular.is_explicit_object_member_function()) + self.assertTrue(explicit_obj.is_explicit_object_member_function()) + self.assertFalse(static_method.is_explicit_object_member_function()) + def test_is_pure_virtual_method(self): """Ensure Cursor.is_pure_virtual_method works.""" source = "class X { virtual void foo() = 0; virtual void bar(); };" @@ -636,7 +678,7 @@ def test_is_constexpr(self): template<typename T> constexpr T tmpl(T v) { return v; } template<typename T> T tmpl_nc(T v) { return v; } """ - tu = get_tu(source, lang="cpp", flags=["--std=c++14"]) + tu = get_tu(source, lang="cpp", flags=["-std=c++14"]) x = get_cursor(tu, "x") y = get_cursor(tu, "y") diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9d4069d2479ac..3efc7df494316 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -585,6 +585,8 @@ libclang - The clang_Module_getASTFile API is deprecated and now always returns nullptr - Added ``clang_CXXMethod_getQualifiers`` to query const/volatile/__restrict qualifiers of a member function. - Added ``clang_Cursor_isConstexpr`` to determine if a cursor refers to a constexpr declaration. +- Added ``clang_CXXMethod_isExplicitObjectMemberFunction`` to determine if a method has an + explicit object parameter (C++23). Code Completion --------------- @@ -627,6 +629,8 @@ Python Binding Changes read the version string of the libclang in use. - Added ``Cursor.get_method_qualifiers``, a binding for ``clang_CXXMethod_getQualifiers``. - Added ``Cursor.is_constexpr``, a binding for ``clang_Cursor_isConstexpr``. +- Added ``Cursor.is_explicit_object_member_function``, a binding for + ``clang_CXXMethod_isExplicitObjectMemberFunction``. OpenMP Support -------------- diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 9ae9824b65c43..b061f846358f0 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -4910,9 +4910,20 @@ typedef struct { * * If the cursor does not refer to a C++ member function or member function * template, a zero-initialized CXQualifiers is returned. + * + * For explicit object member functions (C++23), this returns zero-initialized + * CXQualifiers. Use \c clang_CXXMethod_isExplicitObjectMemberFunction to + * distinguish explicit from implicit object member functions. */ CINDEX_LINKAGE CXQualifiers clang_CXXMethod_getQualifiers(CXCursor C); +/** + * Determine if a C++ member function or member function template is an + * explicit object member function (C++23). + */ +CINDEX_LINKAGE unsigned +clang_CXXMethod_isExplicitObjectMemberFunction(CXCursor C); + /** * Given a cursor that represents a template, determine * the cursor kind of the specializations would be generated by instantiating diff --git a/clang/test/Index/cursor-properties.cpp b/clang/test/Index/cursor-properties.cpp index ad9dc3efa2abe..f1f576d82b230 100644 --- a/clang/test/Index/cursor-properties.cpp +++ b/clang/test/Index/cursor-properties.cpp @@ -10,7 +10,13 @@ struct Foo { constexpr int x = 42; int y = 1; -// RUN: c-index-test -test-print-type --std=c++14 %s | FileCheck %s +struct Bar { + void explicit_const(this const Bar&); + void explicit_volatile(this volatile Bar&); + void explicit_cv(this const volatile Bar&); +}; + +// RUN: c-index-test -test-print-type --std=c++23 %s | FileCheck %s // CHECK: CXXMethod=normal:2:8 [type=void ()] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] // CHECK: CXXMethod=c:3:8 (const) [type=void () const] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] // CHECK: CXXMethod=v:4:8 (volatile) [type=void () volatile] [typekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [isPOD=0] @@ -20,3 +26,6 @@ int y = 1; // CHECK: CXXMethod=baz:8:17 (Definition) (constexpr) [type=int ()] [typekind=FunctionProto] [resulttype=int] [resulttypekind=Int] [isPOD=0] // CHECK: VarDecl=x:10:15 (Definition) (constexpr) [type=const int] [typekind=Int] const [isPOD=1] // CHECK: VarDecl=y:11:5 (Definition) [type=int] [typekind=Int] [isPOD=1] +// CHECK: CXXMethod=explicit_const:14:8 (explicit object) [type=void (const Bar &)] [typekind=FunctionProto] [canonicaltype=void (const Bar &)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [const Bar &] [LValueReference]] [isPOD=0] +// CHECK: CXXMethod=explicit_volatile:15:8 (explicit object) [type=void (volatile Bar &)] [typekind=FunctionProto] [canonicaltype=void (volatile Bar &)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [volatile Bar &] [LValueReference]] [isPOD=0] +// CHECK: CXXMethod=explicit_cv:16:8 (explicit object) [type=void (const volatile Bar &)] [typekind=FunctionProto] [canonicaltype=void (const volatile Bar &)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [const volatile Bar &] [LValueReference]] [isPOD=0] diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index bd863840f2ed7..3287283494029 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -961,6 +961,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { if (Q.Restrict) printf(" (restrict)"); } + if (clang_CXXMethod_isExplicitObjectMemberFunction(Cursor)) + printf(" (explicit object)"); if (clang_CXXMethod_isPureVirtual(Cursor)) printf(" (pure)"); if (clang_CXXMethod_isCopyAssignmentOperator(Cursor)) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 2a887cdfb7f58..e564f199009a9 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -9550,6 +9550,16 @@ CXQualifiers clang_CXXMethod_getQualifiers(CXCursor C) { return Q; } +unsigned clang_CXXMethod_isExplicitObjectMemberFunction(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXMethodDecl *Method = + D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; + return (Method && Method->isExplicitObjectMemberFunction()) ? 1 : 0; +} + unsigned clang_CXXMethod_isDefaulted(CXCursor C) { if (!clang_isDeclaration(C.kind)) return 0; diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map index c33579219d42b..a2756645db48c 100644 --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -462,6 +462,7 @@ LLVM_23 { clang_ModuleCache_prune; clang_Cursor_isConstexpr; clang_CXXMethod_getQualifiers; + clang_CXXMethod_isExplicitObjectMemberFunction; }; # Example of how to add a new symbol version entry. If you do add a new symbol _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
