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

Reply via email to