https://github.com/Serafean updated 
https://github.com/llvm/llvm-project/pull/182303

>From c18fc216b067d90acffebab0d2a8d5463a234f89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Bedn=C3=A1r?= <[email protected]>
Date: Wed, 18 Feb 2026 22:25:44 +0100
Subject: [PATCH] [libclang]Return *OperatorKind for oveloaded operators

Currently clang_getCursorBinaryOperatorKind and 
clang_getCursorUnaryOperatorKind only
return valid values for operations on POD and rewritten operators.
Extend this to also correctly return for overloaded operators by
handling CXXOperatorCallExpr.

Note: this is necessary to ever get CXUnaryOperator_Coawait.
---
 clang/docs/ReleaseNotes.rst             |   1 +
 clang/test/Index/binop.cpp              | 146 ++++++++++++++++++++++++
 clang/test/Index/unaryop.cpp            |  83 ++++++++++++++
 clang/tools/c-index-test/c-index-test.c |  21 +++-
 clang/tools/libclang/CIndex.cpp         |  50 ++++++--
 5 files changed, 289 insertions(+), 12 deletions(-)
 create mode 100644 clang/test/Index/unaryop.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6e9e5baea2921..4c70305f3d207 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -397,6 +397,7 @@ clang-format
 
 libclang
 --------
+- Return valid CXUnaryOperatorKind and CXBinaryOperatorKind for overloaded 
operators.
 
 Code Completion
 ---------------
diff --git a/clang/test/Index/binop.cpp b/clang/test/Index/binop.cpp
index 576fd73cc2abf..0be4f28116fe7 100644
--- a/clang/test/Index/binop.cpp
+++ b/clang/test/Index/binop.cpp
@@ -58,6 +58,7 @@ void func(void) {
 #pragma clang diagnostic pop
 }
 
+// CHECK: CallExpr=C:3:8 BinOp= 0
 // CHECK: BinaryOperator=.* BinOp=.* 1
 // CHECK: BinaryOperator=->* BinOp=->* 2
 // CHECK: BinaryOperator=* BinOp=* 3
@@ -90,3 +91,148 @@ void func(void) {
 // CHECK: CompoundAssignOperator=^= BinOp=^= 31
 // CHECK: CompoundAssignOperator=|= BinOp=|= 32
 // CHECK: BinaryOperator=, BinOp=, 33
+
+struct D {
+  D() = default;
+  D& operator+(){return *this;}
+  D& operator-(){return *this;}
+  D& operator*(const D&){return *this;}
+  D& operator/(const D&){return *this;}
+  D& operator%(const D&){return *this;}
+  D& operator+(const D&){return *this;}
+  D& operator-(const D&){return *this;}
+
+  D& operator<<(const D&){return *this;}
+  D& operator>>(const D&){return *this;}
+
+  bool operator<(const D&){return true;}
+  bool operator>(const D&){return true;}
+  bool operator<=(const D&){return true;}
+  bool operator>=(const D&){return true;}
+  bool operator==(const D&){return true;}
+  bool operator!=(const D&){return true;}
+
+  D& operator|(const D&){return *this;}
+  D& operator&(const D&){return *this;}
+  D& operator^(const D&){return *this;}
+
+  bool operator&&(const D&){return true;}
+  bool operator||(const D&){return true;}
+
+  D& operator+=(const D&){return *this;}
+  D& operator-=(const D&){return *this;}
+  D& operator*=(const D&){return *this;}
+  D& operator/=(const D&){return *this;}
+  D& operator%=(const D&){return *this;}
+  D& operator&=(const D&){return *this;}
+  D& operator|=(const D&){return *this;}
+  D& operator^=(const D&){return *this;}
+  D& operator<<=(const D&){return *this;}
+  D& operator>>=(const D&){return *this;}
+  D& operator,(const D&){return *this;}
+
+  int& operator->*(int D::*i){return this->i;}
+
+  // Negative test of --/++
+  D& operator++(){return *this;};
+  D& operator++(int){return *this;};
+  D& operator--(){return *this;};
+  D& operator--(int){return *this;};
+
+  int i;
+};
+
+void func2(void) {
+  #pragma clang diagnostic push
+  #pragma clang diagnostic ignored "-Wunused-value"
+  D a, b;
+  int D::*p = &D::i;
+
+  D *pc;
+  a->*p;
+
+  a *b;
+  a / b;
+  a % b;
+  a + b;
+  a - b;
+
+  a << b;
+  a >> b;
+
+  a < b;
+  a > b;
+
+  a <= b;
+  a >= b;
+  a == b;
+  a != b;
+
+  a &b;
+  a ^ b;
+  a | b;
+
+  a &&b;
+  a || b;
+
+  a = b;
+
+  a *= b;
+  a /= b;
+  a %= b;
+  a += b;
+  a -= b;
+
+  a <<= b;
+  a >>= b;
+
+  a &= b;
+  a ^= b;
+  a |= b;
+  a, b;
+
+// Negative test
+  a++;
+  ++a;
+  a--;
+  --a;
+  #pragma clang diagnostic pop
+}
+
+// CHECK: CallExpr=D:96:3 BinOp= 0
+// CHECK: CallExpr=D:96:3 BinOp= 0
+// CHECK: CallExpr=operator->*:134:8 BinOp=->* 2
+// CHECK: CallExpr=operator*:99:6 BinOp=* 3
+// CHECK: CallExpr=operator/:100:6 BinOp=/ 4
+// CHECK: CallExpr=operator%:101:6 BinOp=% 5
+// CHECK: CallExpr=operator+:102:6 BinOp=+ 6
+// CHECK: CallExpr=operator-:103:6 BinOp=- 7
+// CHECK: CallExpr=operator<<:105:6 BinOp=<< 8
+// CHECK: CallExpr=operator>>:106:6 BinOp=>> 9
+// CHECK: CallExpr=operator<:108:8 BinOp=< 11
+// CHECK: CallExpr=operator>:109:8 BinOp=> 12
+// CHECK: CallExpr=operator<=:110:8 BinOp=<= 13
+// CHECK: CallExpr=operator>=:111:8 BinOp=>= 14
+// CHECK: CallExpr=operator==:112:8 BinOp=== 15
+// CHECK: CallExpr=operator!=:113:8 BinOp=!= 16
+// CHECK: CallExpr=operator&:116:6 BinOp=& 17
+// CHECK: CallExpr=operator^:117:6 BinOp=^ 18
+// CHECK: CallExpr=operator|:115:6 BinOp=| 19
+// CHECK: CallExpr=operator&&:119:8 BinOp=&& 20
+// CHECK: CallExpr=operator||:120:8 BinOp=|| 21
+// CHECK: CallExpr=operator=:95:8 BinOp== 22
+// CHECK: CallExpr=operator*=:124:6 BinOp=*= 23
+// CHECK: CallExpr=operator/=:125:6 BinOp=/= 24
+// CHECK: CallExpr=operator%=:126:6 BinOp=%= 25
+// CHECK: CallExpr=operator+=:122:6 BinOp=+= 26
+// CHECK: CallExpr=operator-=:123:6 BinOp=-= 27
+// CHECK: CallExpr=operator<<=:130:6 BinOp=<<= 28
+// CHECK: CallExpr=operator>>=:131:6 BinOp=>>= 29
+// CHECK: CallExpr=operator&=:127:6 BinOp=&= 30
+// CHECK: CallExpr=operator^=:129:6 BinOp=^= 31
+// CHECK: CallExpr=operator|=:128:6 BinOp=|= 32
+// CHECK: CallExpr=operator,:132:6 BinOp=, 33
+// CHECK: CallExpr=operator++:138:6 BinOp= 0
+// CHECK: CallExpr=operator++:137:6 BinOp= 0
+// CHECK: CallExpr=operator--:140:6 BinOp= 0
+// CHECK: CallExpr=operator--:139:6 BinOp= 0
diff --git a/clang/test/Index/unaryop.cpp b/clang/test/Index/unaryop.cpp
new file mode 100644
index 0000000000000..368113a8a5edc
--- /dev/null
+++ b/clang/test/Index/unaryop.cpp
@@ -0,0 +1,83 @@
+// RUN: c-index-test -test-print-unops %s | FileCheck %s
+
+void func(){
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-value"
+    int i;
+
+    i++;
+    ++i;
+    i--;
+    --i;
+    int *p = &i;
+    *p;
+    int c= +i;
+    int d= -i;
+
+    ~i;
+    !i;
+
+#pragma clang diagnostic pop
+}
+
+// CHECK: UnaryOperator= UnOp=++ 1
+// CHECK: UnaryOperator= UnOp=++ 3
+// CHECK: UnaryOperator= UnOp=-- 2
+// CHECK: UnaryOperator= UnOp=-- 4
+// CHECK: UnaryOperator= UnOp=& 5
+// CHECK: UnaryOperator= UnOp=* 6
+// CHECK: UnaryOperator= UnOp=+ 7
+// CHECK: UnaryOperator= UnOp=- 8
+// CHECK: UnaryOperator= UnOp=~ 9
+// CHECK: UnaryOperator= UnOp=! 10
+
+struct C{
+    C() = default;
+    C& operator++();
+    C& operator++(int);
+    C& operator--();
+    C& operator--(int);
+    C& operator*();
+    C* operator&();
+    C& operator+();
+    C& operator-();
+    C& operator!();
+    C& operator~();
+};
+
+void func2(){
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-value"
+    C i;
+    i++;
+    ++i;
+    i--;
+    --i;
+    C *p = &i;
+    *i;
+    +i;
+    C n = +i;
+    -i;
+    C m = -i;
+
+    ~i;
+    !i;
+
+#pragma clang diagnostic pop
+}
+
+// CHECK: CallExpr=C:35:5 UnOp= 0
+// CHECK: CallExpr=operator++:37:8 UnOp=++ 1
+// CHECK: CallExpr=operator++:36:8 UnOp=++ 3
+// CHECK: CallExpr=operator--:39:8 UnOp=-- 2
+// CHECK: CallExpr=operator--:38:8 UnOp=-- 4
+// CHECK: CallExpr=operator&:41:8 UnOp=& 5
+// CHECK: CallExpr=operator*:40:8 UnOp=* 6
+// CHECK: CallExpr=operator+:42:8 UnOp=+ 7
+// CHECK: CallExpr=C:34:8 UnOp= 0
+// CHECK: CallExpr=operator+:42:8 UnOp=+ 7
+// CHECK: CallExpr=operator-:43:8 UnOp=- 8
+// CHECK: CallExpr=C:34:8 UnOp= 0
+// CHECK: CallExpr=operator-:43:8 UnOp=- 8
+// CHECK: CallExpr=operator~:45:8 UnOp=~ 9
+// CHECK: CallExpr=operator!:44:8 UnOp=! 10
diff --git a/clang/tools/c-index-test/c-index-test.c 
b/clang/tools/c-index-test/c-index-test.c
index cb3245756a394..24be3952c009d 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -1865,7 +1865,8 @@ static enum CXChildVisitResult PrintBinOps(CXCursor C, 
CXCursor p,
   enum CXCursorKind ck = clang_getCursorKind(C);
   enum CXBinaryOperatorKind bok;
   CXString opstr;
-  if (ck != CXCursor_BinaryOperator && ck != CXCursor_CompoundAssignOperator)
+  if (ck != CXCursor_BinaryOperator && ck != CXCursor_CompoundAssignOperator &&
+      ck != CXCursor_CallExpr)
     return CXChildVisit_Recurse;
 
   PrintCursor(C, NULL);
@@ -1876,6 +1877,22 @@ static enum CXChildVisitResult PrintBinOps(CXCursor C, 
CXCursor p,
   return CXChildVisit_Recurse;
 }
 
+static enum CXChildVisitResult PrintUnOps(CXCursor C, CXCursor p,
+                                          CXClientData d) {
+  enum CXCursorKind ck = clang_getCursorKind(C);
+  enum CXUnaryOperatorKind bok;
+  CXString opstr;
+  if (ck != CXCursor_UnaryOperator && ck != CXCursor_CallExpr)
+    return CXChildVisit_Recurse;
+
+  PrintCursor(C, NULL);
+  bok = clang_getCursorUnaryOperatorKind(C);
+  opstr = clang_getUnaryOperatorKindSpelling(bok);
+  printf(" UnOp=%s %d\n", clang_getCString(opstr), bok);
+  clang_disposeString(opstr);
+  return CXChildVisit_Recurse;
+}
+
 
/******************************************************************************/
 /* Mangling testing.                                                          
*/
 
/******************************************************************************/
@@ -5182,6 +5199,8 @@ int cindextest_main(int argc, const char **argv) {
                                     PrintBitWidth, 0);
   else if (argc > 2 && strcmp(argv[1], "-test-print-binops") == 0)
     return perform_test_load_source(argc - 2, argv + 2, "all", PrintBinOps, 0);
+  else if (argc > 2 && strcmp(argv[1], "-test-print-unops") == 0)
+    return perform_test_load_source(argc - 2, argv + 2, "all", PrintUnOps, 0);
   else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0)
     return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
   else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0)
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 15eec87652451..4e22fbddb1e3d 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -10181,16 +10181,28 @@ CXString clang_getBinaryOperatorKindSpelling(enum 
CXBinaryOperatorKind kind) {
 }
 
 enum CXBinaryOperatorKind clang_getCursorBinaryOperatorKind(CXCursor cursor) {
-  if (clang_isExpression(cursor.kind)) {
-    const Expr *expr = getCursorExpr(cursor);
+  if (!clang_isExpression(cursor.kind))
+    return CXBinaryOperator_Invalid;
 
-    if (const auto *op = dyn_cast<BinaryOperator>(expr))
-      return static_cast<CXBinaryOperatorKind>(op->getOpcode() + 1);
+  const Expr *expr = getCursorExpr(cursor);
+  if (!expr)
+    return CXBinaryOperator_Invalid;
 
-    if (const auto *op = dyn_cast<CXXRewrittenBinaryOperator>(expr))
-      return static_cast<CXBinaryOperatorKind>(op->getOpcode() + 1);
-  }
+  if (const auto *op = dyn_cast<BinaryOperator>(expr))
+    return static_cast<CXBinaryOperatorKind>(op->getOpcode() + 1);
 
+  if (const auto *op = dyn_cast<CXXRewrittenBinaryOperator>(expr))
+    return static_cast<CXBinaryOperatorKind>(op->getOpcode() + 1);
+
+  if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(expr)) {
+    const OverloadedOperatorKind Kind = OCE->getOperator();
+    bool isPostfixOp = (OCE->getNumArgs() == 2 &&
+                    (Kind == OO_PlusPlus || Kind == OO_MinusMinus));
+    if (OCE->getNumArgs() == 2 && !isPostfixOp) {
+      auto opcode = BinaryOperator::getOverloadedOpcode(Kind);
+      return static_cast<CXBinaryOperatorKind>(opcode + 1);
+    }
+  }
   return CXBinaryOperator_Invalid;
 }
 
@@ -10200,11 +10212,27 @@ CXString clang_getUnaryOperatorKindSpelling(enum 
CXUnaryOperatorKind kind) {
 }
 
 enum CXUnaryOperatorKind clang_getCursorUnaryOperatorKind(CXCursor cursor) {
-  if (clang_isExpression(cursor.kind)) {
-    const Expr *expr = getCursorExpr(cursor);
+  if (!clang_isExpression(cursor.kind)) {
+    return CXUnaryOperator_Invalid;
+  }
 
-    if (const auto *op = dyn_cast<UnaryOperator>(expr))
-      return static_cast<CXUnaryOperatorKind>(op->getOpcode() + 1);
+  const Expr *expr = getCursorExpr(cursor);
+  if (!expr) {
+    return CXUnaryOperator_Invalid;
+  }
+
+  if (const auto *op = dyn_cast<UnaryOperator>(expr)) {
+    return static_cast<CXUnaryOperatorKind>(op->getOpcode() + 1);
+  }
+
+  if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(expr)) {
+    const OverloadedOperatorKind Kind = OCE->getOperator();
+    bool isPostfixOp = (OCE->getNumArgs() == 2 &&
+                    (Kind == OO_PlusPlus || Kind == OO_MinusMinus));
+    if (OCE->getNumArgs() == 1 || isPostfixOp) {
+      auto opcode = UnaryOperator::getOverloadedOpcode(Kind, isPostfixOp);
+      return static_cast<CXUnaryOperatorKind>(opcode + 1);
+    }
   }
 
   return CXUnaryOperator_Invalid;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to