https://github.com/Serafean created https://github.com/llvm/llvm-project/pull/216553
Whether a declaration is overloading an operator or not is interesting information. Extend clang_getCursorUnaryOperatorKind and clang_getCursorBinaryOperatorKind to allow querying on declarations. From f7eb6614f43a9e3724c0567e254c54e0181c8114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bedn=C3=A1r?= <[email protected]> Date: Sun, 16 Aug 2026 00:00:07 +0200 Subject: [PATCH 1/2] Report operator kind for Declarations --- clang/docs/ReleaseNotes.md | 1 + clang/tools/libclang/CIndex.cpp | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index c348ddaf23017..b312bde887615 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -476,6 +476,7 @@ features cannot lower the translation-unit ABI level; ### libclang - visit identifier initializers in lambda capture as VarDecl instead of VariableRef. Warning: this changes behaviour. +- Allow querying Unary and Binary operator types on declaration cursors. ### Code Completion diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 7c9da867909f5..5fc9e92441caf 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -10234,6 +10234,23 @@ enum CXBinaryOperatorKind clang_getCursorBinaryOperatorKind(CXCursor cursor) { return static_cast<CXBinaryOperatorKind>(op->getOpcode() + 1); } + if (clang_isDeclaration(cursor.kind)) { + const auto *decl = getCursorDecl(cursor); + + const auto *funcDecl = dyn_cast<FunctionDecl>(decl); + if (!funcDecl || + ((funcDecl->isCXXClassMember() && funcDecl->getNumParams() != 1) && + funcDecl->getNumParams() != 2)) + return CXBinaryOperator_Invalid; + + const auto op = funcDecl->getOverloadedOperator(); + + if (op == OO_None || op == OO_PlusPlus || op == OO_MinusMinus) + return CXBinaryOperator_Invalid; + + const auto bop = BinaryOperator::getOverloadedOpcode(op); + return static_cast<CXBinaryOperatorKind>(bop + 1); + } return CXBinaryOperator_Invalid; } @@ -10253,5 +10270,25 @@ enum CXUnaryOperatorKind clang_getCursorUnaryOperatorKind(CXCursor cursor) { return static_cast<CXUnaryOperatorKind>(op->getOpcode() + 1); } + if (clang_isDeclaration(cursor.kind)) { + const auto *decl = getCursorDecl(cursor); + + const auto *funcDecl = dyn_cast<FunctionDecl>(decl); + if (!funcDecl || + ((funcDecl->isCXXClassMember() && funcDecl->getNumParams() > 1) || + funcDecl->getNumParams() > 2)) + return CXUnaryOperator_Invalid; + + const auto op = funcDecl->getOverloadedOperator(); + if (op == OO_None) + return CXUnaryOperator_Invalid; + + const bool postfix = + (funcDecl->isCXXClassMember() && funcDecl->getNumParams() == 1) || + funcDecl->getNumParams() == 2; + const auto uop = UnaryOperator::getOverloadedOpcode(op, postfix); + return static_cast<CXUnaryOperatorKind>(uop + 1); + } + return CXUnaryOperator_Invalid; } From 412ac07bc8df91ddca9d8c584491790e132a2918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bedn=C3=A1r?= <[email protected]> Date: Sun, 16 Aug 2026 00:01:02 +0200 Subject: [PATCH 2/2] tests --- clang/test/Index/binop.cpp | 160 ++++++++++++++++++++++++ clang/test/Index/unop.cpp | 86 +++++++++++++ clang/tools/c-index-test/c-index-test.c | 21 +++- 3 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 clang/test/Index/unop.cpp diff --git a/clang/test/Index/binop.cpp b/clang/test/Index/binop.cpp index 576fd73cc2abf..55b15d760f397 100644 --- a/clang/test/Index/binop.cpp +++ b/clang/test/Index/binop.cpp @@ -90,3 +90,163 @@ 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;} + int& operator->*(int D::*i){return this->i;} + 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&); + 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;} + + // Negative test of --/++ + D& operator++(int){return *this;}; + D& operator++(){return *this;}; + D& operator--(int){return *this;}; + D& operator--(){return *this;}; + void foo(); + int i; +}; + +// CHECK: CXXMethod=operator+:96:6 (Definition) BinOp= 0 +// CHECK: CXXMethod=operator-:97:6 (Definition) BinOp= 0 +// CHECK: CXXMethod=operator->*:98:8 (Definition) BinOp=->* 2 +// CHECK: CXXMethod=operator*:99:6 (Definition) BinOp=* 3 +// CHECK: CXXMethod=operator/:100:6 (Definition) BinOp=/ 4 +// CHECK: CXXMethod=operator%:101:6 (Definition) BinOp=% 5 +// CHECK: CXXMethod=operator+:102:6 (Definition) BinOp=+ 6 +// CHECK: CXXMethod=operator-:103:6 (Definition) BinOp=- 7 +// CHECK: CXXMethod=operator<<:104:6 (Definition) BinOp=<< 8 +// CHECK: CXXMethod=operator>>:105:6 (Definition) BinOp=>> 9 +// CHECK: CXXMethod=operator<:106:8 (Definition) BinOp=< 11 +// CHECK: CXXMethod=operator>:107:8 (Definition) BinOp=> 12 +// CHECK: CXXMethod=operator<=:108:8 (Definition) BinOp=<= 13 +// CHECK: CXXMethod=operator>=:109:8 (Definition) BinOp=>= 14 +// CHECK: CXXMethod=operator==:110:8 (Definition) BinOp=== 15 +// CHECK: CXXMethod=operator!=:111:8 (Definition) BinOp=!= 16 +// CHECK: CXXMethod=operator&:112:6 (Definition) BinOp=& 17 +// CHECK: CXXMethod=operator^:113:6 (Definition) BinOp=^ 18 +// CHECK: CXXMethod=operator|:114:6 (Definition) BinOp=| 19 +// CHECK: CXXMethod=operator&&:115:8 (Definition) BinOp=&& 20 +// CHECK: CXXMethod=operator||:116:8 (Definition) BinOp=|| 21 +// CHECK: CXXMethod=operator=:117:6 (copy-assignment operator) BinOp== 22 +// CHECK: CXXMethod=operator*=:118:6 (Definition) BinOp=*= 23 +// CHECK: CXXMethod=operator/=:119:6 (Definition) BinOp=/= 24 +// CHECK: CXXMethod=operator%=:120:6 (Definition) BinOp=%= 25 +// CHECK: CXXMethod=operator+=:121:6 (Definition) BinOp=+= 26 +// CHECK: CXXMethod=operator-=:122:6 (Definition) BinOp=-= 27 +// CHECK: CXXMethod=operator<<=:123:6 (Definition) BinOp=<<= 28 +// CHECK: CXXMethod=operator>>=:124:6 (Definition) BinOp=>>= 29 +// CHECK: CXXMethod=operator&=:125:6 (Definition) BinOp=&= 30 +// CHECK: CXXMethod=operator^=:126:6 (Definition) BinOp=^= 31 +// CHECK: CXXMethod=operator|=:127:6 (Definition) BinOp=|= 32 +// CHECK: CXXMethod=operator,:128:6 (Definition) BinOp=, 33 +// CHECK: CXXMethod=operator++:131:6 (Definition) BinOp= 0 +// CHECK: CXXMethod=operator++:132:6 (Definition) BinOp= 0 +// CHECK: CXXMethod=operator--:133:6 (Definition) BinOp= 0 +// CHECK: CXXMethod=operator--:134:6 (Definition) BinOp= 0 +// CHECK: CXXMethod=foo:135:8 BinOp= 0 + +struct E{ + int i; +}; + +int& operator->*(const E&, int E::*i); +E operator*(const E&, const E&); +E operator/(const E&, const E&); +E operator%(const E&, const E&); +E operator+(const E&, const E&); +E operator-(const E&, const E&); +E operator<<(const E&, const E&); +E operator>>(const E&, const E&); +bool operator<(const E&, const E&); +bool operator>(const E&, const E&); +bool operator<=(const E&, const E&); +bool operator>=(const E&, const E&); +bool operator==(const E&, const E&); +bool operator!=(const E&, const E&); +E operator&(const E&, const E&); +E operator^(const E&, const E&); +E operator|(const E&, const E&); +bool operator&&(const E&, const E&); +bool operator||(const E&, const E&); +E operator*=(const E&, const E&); +E operator/=(const E&, const E&); +E operator%=(const E&, const E&); +E operator+=(const E&, const E&); +E operator-=(const E&, const E&); +E operator<<=(const E&, const E&); +E operator>>=(const E&, const E&); +E operator&=(const E&, const E&); +E operator^=(const E&, const E&); +E operator|=(const E&, const E&); +E operator,(const E&, const E&); +E operator++(const E&a, int); +E operator++(const E&a ); +E operator--(const E&a, int); +E operator--(const E&a); +void foo(const E&, const E&); + +// CHECK: FunctionDecl=operator->*:182:6 BinOp=->* 2 +// CHECK: FunctionDecl=operator*:183:3 BinOp=* 3 +// CHECK: FunctionDecl=operator/:184:3 BinOp=/ 4 +// CHECK: FunctionDecl=operator%:185:3 BinOp=% 5 +// CHECK: FunctionDecl=operator+:186:3 BinOp=+ 6 +// CHECK: FunctionDecl=operator-:187:3 BinOp=- 7 +// CHECK: FunctionDecl=operator<<:188:3 BinOp=<< 8 +// CHECK: FunctionDecl=operator>>:189:3 BinOp=>> 9 +// CHECK: FunctionDecl=operator<:190:6 BinOp=< 11 +// CHECK: FunctionDecl=operator>:191:6 BinOp=> 12 +// CHECK: FunctionDecl=operator<=:192:6 BinOp=<= 13 +// CHECK: FunctionDecl=operator>=:193:6 BinOp=>= 14 +// CHECK: FunctionDecl=operator==:194:6 BinOp=== 15 +// CHECK: FunctionDecl=operator!=:195:6 BinOp=!= 16 +// CHECK: FunctionDecl=operator&:196:3 BinOp=& 17 +// CHECK: FunctionDecl=operator^:197:3 BinOp=^ 18 +// CHECK: FunctionDecl=operator|:198:3 BinOp=| 19 +// CHECK: FunctionDecl=operator&&:199:6 BinOp=&& 20 +// CHECK: FunctionDecl=operator||:200:6 BinOp=|| 21 +// CHECK: FunctionDecl=operator*=:201:3 BinOp=*= 23 +// CHECK: FunctionDecl=operator/=:202:3 BinOp=/= 24 +// CHECK: FunctionDecl=operator%=:203:3 BinOp=%= 25 +// CHECK: FunctionDecl=operator+=:204:3 BinOp=+= 26 +// CHECK: FunctionDecl=operator-=:205:3 BinOp=-= 27 +// CHECK: FunctionDecl=operator<<=:206:3 BinOp=<<= 28 +// CHECK: FunctionDecl=operator>>=:207:3 BinOp=>>= 29 +// CHECK: FunctionDecl=operator&=:208:3 BinOp=&= 30 +// CHECK: FunctionDecl=operator^=:209:3 BinOp=^= 31 +// CHECK: FunctionDecl=operator|=:210:3 BinOp=|= 32 +// CHECK: FunctionDecl=operator,:211:3 BinOp=, 33 +// CHECK: FunctionDecl=operator++:212:3 BinOp= 0 +// CHECK: FunctionDecl=operator++:213:3 BinOp= 0 +// CHECK: FunctionDecl=operator--:214:3 BinOp= 0 +// CHECK: FunctionDecl=operator--:215:3 BinOp= 0 +// CHECK: FunctionDecl=foo:216:6 BinOp= 0 diff --git a/clang/test/Index/unop.cpp b/clang/test/Index/unop.cpp new file mode 100644 index 0000000000000..51bde889e1d58 --- /dev/null +++ b/clang/test/Index/unop.cpp @@ -0,0 +1,86 @@ +// RUN: c-index-test -test-print-unops -std=c++20 %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++(int); + C& operator++(); + C& operator--(int); + C& operator--(); + C& operator*(); + C* operator&(); + C& operator+(); + C& operator-(); + C& operator!(); + C& operator~(); + void operator co_await(); + void foo(); +}; + +// CHECK: CXXMethod=operator++:31:8 UnOp=++ 1 +// CHECK: CXXMethod=operator++:32:8 UnOp=++ 3 +// CHECK: CXXMethod=operator--:33:8 UnOp=-- 2 +// CHECK: CXXMethod=operator--:34:8 UnOp=-- 4 +// CHECK: CXXMethod=operator*:35:8 UnOp=* 6 +// CHECK: CXXMethod=operator&:36:8 UnOp=& 5 +// CHECK: CXXMethod=operator+:37:8 UnOp=+ 7 +// CHECK: CXXMethod=operator-:38:8 UnOp=- 8 +// CHECK: CXXMethod=operator!:39:8 UnOp=! 10 +// CHECK: CXXMethod=operator~:40:8 UnOp=~ 9 +// CHECK: CXXMethod=operator co_await:41:10 UnOp=co_await 14 +// CHECK: CXXMethod=foo:42:10 UnOp= 0 + +struct D { + +}; + +D operator++(const D&a, int); +D operator++(const D&a ); +D operator--(const D&a, int); +D operator--(const D&a); +D operator*(const D&a); +D operator&(const D&a); +D operator+(const D&a); +D operator-(const D&a); +D operator!(const D&a); +D operator~(const D&a); +void operator co_await(const D &d); +void foo(const D&); + +// CHECK: FunctionDecl=operator++:62:3 UnOp=++ 1 +// CHECK: FunctionDecl=operator++:63:3 UnOp=++ 3 +// CHECK: FunctionDecl=operator--:64:3 UnOp=-- 2 +// CHECK: FunctionDecl=operator--:65:3 UnOp=-- 4 +// CHECK: FunctionDecl=operator*:66:3 UnOp=* 6 +// CHECK: FunctionDecl=operator&:67:3 UnOp=& 5 +// CHECK: FunctionDecl=operator+:68:3 UnOp=+ 7 +// CHECK: FunctionDecl=operator-:69:3 UnOp=- 8 +// CHECK: FunctionDecl=operator!:70:3 UnOp=! 10 +// CHECK: FunctionDecl=operator~:71:3 UnOp=~ 9 +// CHECK: FunctionDecl=operator co_await:72:6 UnOp=co_await 14 +// CHECK: FunctionDecl=foo:73:6 UnOp= 0 diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 4b3e105aa7aff..2b699dce07ac9 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_CXXMethod && ck != CXCursor_FunctionDecl) 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 uok; + CXString opstr; + if (ck != CXCursor_UnaryOperator && ck != CXCursor_CXXMethod && + ck != CXCursor_FunctionDecl) + return CXChildVisit_Recurse; + + PrintCursor(C, NULL); + uok = clang_getCursorUnaryOperatorKind(C); + opstr = clang_getUnaryOperatorKindSpelling(uok); + printf(" UnOp=%s %d\n", clang_getCString(opstr), uok); + clang_disposeString(opstr); + return CXChildVisit_Recurse; +} /******************************************************************************/ /* Mangling testing. */ /******************************************************************************/ @@ -5177,6 +5194,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) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
