https://github.com/fscheidl updated https://github.com/llvm/llvm-project/pull/183305
>From c00a0a837b613bb9190cab48245b9b49642bfd32 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 | 6 ++ 8 files changed, 224 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 1896a0a9c1c34..081f9340fd63a 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -1631,6 +1631,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 @@ -1680,6 +1692,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.""" @@ -1852,6 +1872,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: """ @@ -4251,6 +4276,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), @@ -4436,6 +4462,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 cb1010aee1edd..ad872a0d3120d 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -430,6 +430,8 @@ libclang - Visit constraints of `auto` type to properly visit concept usages (#GH166580) - Visit switch initializer statements (https://bugs.kde.org/show_bug.cgi?id=415537#c2) - Fix crash in clang_getBinaryOperatorKindSpelling and clang_getUnaryOperatorKindSpelling +- 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 --------------- @@ -468,6 +470,8 @@ Python Binding Changes ``CodeCompletionResults.results`` should be changed to directly use ``CodeCompletionResults``: it nows supports ``__len__`` and ``__getitem__``, so it can be used the same as ``CodeCompletionResults.results``. +- 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 203634c80d82a..5e0b5303ed05d 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 @@ -4883,6 +4891,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 cb3245756a394..db215e1c05e7a 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 31b6a3222d916..dced45d9823cd 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -9538,6 +9538,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; @@ -9619,6 +9636,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 3d9d2e268a611..39dc8ab60650c 100644 --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -457,6 +457,12 @@ LLVM_21 { clang_Cursor_isGCCAssemblyVolatile; }; +LLVM_23 { + global: + clang_Cursor_isConstexpr; + clang_CXXMethod_getQualifiers; +}; + # Example of how to add a new symbol version entry. If you do add a new symbol # version, please update the example to depend on the version you added. # LLVM_X { >From d987c489bcf3ecae2b67e857deb06b3aa4bd38c1 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 081f9340fd63a..626bd870ef98d 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -1832,6 +1832,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 @@ -4282,6 +4291,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 ad872a0d3120d..e06befbb94e25 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -432,6 +432,8 @@ libclang - Fix crash in clang_getBinaryOperatorKindSpelling and clang_getUnaryOperatorKindSpelling - 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 --------------- @@ -472,6 +474,8 @@ Python Binding Changes so it can be used the same as ``CodeCompletionResults.results``. - 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 5e0b5303ed05d..bd1fbc2a12b42 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -4908,9 +4908,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 db215e1c05e7a..8502f50f3268a 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 dced45d9823cd..3583be0b5607c 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -9555,6 +9555,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 39dc8ab60650c..9d327724c6299 100644 --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -461,6 +461,7 @@ LLVM_23 { global: 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
