[clang] Add retrieval of unary operator spelling and python bindings (PR #219983)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 28 05:39:37 PDT 2026
https://github.com/ItsRumo updated https://github.com/llvm/llvm-project/pull/219983
>From 2f1765a4ec1890c933924548b83d5f13861d663b Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Mon, 31 Aug 2026 14:39:48 +0200
Subject: [PATCH 01/14] Add retrieval of unary operator spelling and python
bindings
---
clang/bindings/python/clang/cindex.py | 44 +++++++++++++++++++
.../python/tests/cindex/test_cursor.py | 42 ++++++++++++++++++
.../python/tests/cindex/test_enums.py | 2 +
clang/docs/ReleaseNotes.md | 4 ++
clang/test/Index/annotate-tokens-pp.c | 2 +-
clang/test/Index/annotate-tokens.c | 4 +-
clang/test/Index/blocks.c | 2 +-
clang/test/Index/load-stmts.cpp | 6 +--
clang/test/Index/print-type.c | 2 +-
.../test/Index/recursive-cxx-member-calls.cpp | 8 ++--
clang/test/Index/unaryop.cpp | 38 ++++++++++++++++
clang/tools/libclang/CIndex.cpp | 5 +++
12 files changed, 147 insertions(+), 12 deletions(-)
create mode 100644 clang/test/Index/unaryop.cpp
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index bc00dd770ce3b..9e01b0d88951d 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2036,6 +2036,19 @@ def binary_operator(self) -> BinaryOperator:
return BinaryOperator.from_id(self._binopcode)
+ @property
+ @cursor_null_guard
+ def unary_operator(self) -> UnaryOperator:
+ """
+ Retrieves the opcode if this cursor points to a unary operator
+ :return:
+ """
+
+ if not hasattr(self, "_binopcode"):
+ self._binopcode = conf.lib.clang_getCursorUnaryOperatorKind(self)
+
+ return UnaryOperator.from_id(self._binopcode)
+
@property
@cursor_null_guard
def access_specifier(self) -> AccessSpecifier:
@@ -2474,6 +2487,35 @@ def is_assignment(self):
Comma = 33
+class UnaryOperator(BaseEnumeration):
+ """
+ Describes the UnaryOperator of a declaration
+ """
+
+ def __nonzero__(self):
+ """Allows checks of the kind ```if cursor.unary_operator:```"""
+ return self.value != 0
+
+ def is_postfix(self):
+ return self == UnaryOperator.PostDec or self == UnaryOperator.PostInc
+
+ Invalid = 0
+ PostInc = 1
+ PostDec = 2
+ PreInc = 3
+ PreDec = 4
+ AddrOf = 5
+ Deref = 6
+ Plus = 7
+ Minus = 8
+ Not = 9
+ LNot = 10
+ Real = 11
+ Imag = 12
+ Extension = 13
+ CoAwait = 14
+
+
class StorageClass(BaseEnumeration):
"""
Describes the storage class of a declaration
@@ -4345,6 +4387,7 @@ def set_property(self, property, value):
("clang_Cursor_getTemplateArgumentValue", [Cursor, c_uint], c_longlong),
("clang_Cursor_getTemplateArgumentUnsignedValue", [Cursor, c_uint], c_ulonglong),
("clang_getCursorBinaryOperatorKind", [Cursor], c_int),
+ ("clang_getCursorUnaryOperatorKind", [Cursor], c_int),
("clang_Cursor_getBriefCommentText", [Cursor], _CXString),
("clang_Cursor_getRawCommentText", [Cursor], _CXString),
("clang_Cursor_getOffsetOfField", [Cursor], c_longlong),
@@ -4550,4 +4593,5 @@ def get_clang_version(self) -> str:
"TranslationUnit",
"TypeKind",
"Type",
+ "UnaryOperator",
]
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index 76680e576b307..e8a77371f88e2 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -9,6 +9,7 @@
TemplateArgumentKind,
TranslationUnit,
TypeKind,
+ UnaryOperator,
conf,
)
@@ -986,6 +987,47 @@ def test_binop(self):
c = get_cursor(tu, op)
assert c.binary_operator == typ
+ def test_unaryop(self):
+ tu = get_tu("""
+ void func(void) {
+ int a = 0;
+ a++;
+ ++a;
+ a--;
+ --a;
+ *(&a);
+ +a;
+ -a;
+ !a;
+ ~a;
+ float _Complex b;
+ __real b;
+ __imag b;
+ __extension__ a;
+ }
+ """, lang="cpp")
+
+ operators = {
+ "&": UnaryOperator.AddrOf,
+ "*": UnaryOperator.Deref,
+ "+": UnaryOperator.Plus,
+ "-": UnaryOperator.Minus,
+ "~": UnaryOperator.Not,
+ "!": UnaryOperator.LNot,
+ "__real": UnaryOperator.Real,
+ "__imag": UnaryOperator.Imag,
+ "__extension__": UnaryOperator.Extension,
+ }
+
+ for op, typ in operators.items():
+ c = get_cursor(tu, op)
+ assert c.unary_operator == typ
+
+ for should_be, has in zip(
+ (UnaryOperator.PostInc, UnaryOperator.PreInc, UnaryOperator.PostDec, UnaryOperator.PreDec),
+ list(next(tu.cursor.get_children()).get_children())[1:]):
+ assert should_be == has
+
def test_from_result_null(self):
tu = get_tu("int a = 1+2;", lang="cpp")
op = next(next(tu.cursor.get_children()).get_children())
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index 09f346ee6e11f..f926e75309b35 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -20,6 +20,7 @@
TypeKind,
PrintingPolicyProperty,
BaseEnumeration,
+ UnaryOperator,
)
@@ -56,6 +57,7 @@ def test_all_variants(self):
"CXTLSKind": TLSKind,
"CXTokenKind": TokenKind,
"CXTypeKind": TypeKind,
+ "CXUnaryOperatorKind": UnaryOperator,
}
indexheader = (
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index dd3dfdc5ad8d7..d23eacffd9f9f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -705,6 +705,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.
+- add unary operator handling to clang_getCursorSpelling()
### Code Completion
@@ -740,6 +741,9 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was renamed to `alpha.core.Use
### Python Binding Changes
+- Add support for retrieving unary operator information through
+ Cursor.unary_operator().
+
### OpenMP Support
- Added parsing and semantic support for `dims` modifier in `num_teams`,
diff --git a/clang/test/Index/annotate-tokens-pp.c b/clang/test/Index/annotate-tokens-pp.c
index 7da2d6f5823aa..16248bb403b35 100644
--- a/clang/test/Index/annotate-tokens-pp.c
+++ b/clang/test/Index/annotate-tokens-pp.c
@@ -197,7 +197,7 @@ struct A
// CHECK: Punctuation: "=" [25:36 - 25:37] VarDecl=z:25:34 (Definition)
// CHECK: Identifier: "x" [25:38 - 25:39] DeclRefExpr=x:24:7
// CHECK: Punctuation: ";" [25:39 - 25:40] DeclStmt=
-// CHECK: Punctuation: "++" [25:41 - 25:43] UnaryOperator=
+// CHECK: Punctuation: "++" [25:41 - 25:43] UnaryOperator=++
// CHECK: Identifier: "z" [25:43 - 25:44] DeclRefExpr=z:25:3
// CHECK: Punctuation: ";" [25:44 - 25:45] CompoundStmt=
// CHECK: Punctuation: "}" [25:46 - 25:47] CompoundStmt=
diff --git a/clang/test/Index/annotate-tokens.c b/clang/test/Index/annotate-tokens.c
index 08e7a9a02f8f2..34f50da877575 100644
--- a/clang/test/Index/annotate-tokens.c
+++ b/clang/test/Index/annotate-tokens.c
@@ -106,7 +106,7 @@ void test() {
// CHECK: Identifier: "ptr" [8:14 - 8:17] DeclRefExpr=ptr:3:14
// CHECK: Punctuation: "?" [8:18 - 8:19] UnexposedExpr=
// CHECK: Punctuation: ":" [8:20 - 8:21] UnexposedExpr=
-// CHECK: Punctuation: "&" [8:22 - 8:23] UnaryOperator=
+// CHECK: Punctuation: "&" [8:22 - 8:23] UnaryOperator=&
// CHECK: Identifier: "x" [8:23 - 8:24] DeclRefExpr=x:7:12
// CHECK: Punctuation: ";" [8:24 - 8:25] DeclStmt=
// CHECK: Keyword: "const" [9:3 - 9:8] VarDecl=hello:9:16 (Definition)
@@ -130,7 +130,7 @@ void test() {
// CHECK: Identifier: "x" [20:5 - 20:6] DeclRefExpr=x:18:12
// CHECK: Punctuation: "." [20:6 - 20:7] MemberRefExpr=a:2:16
// CHECK: Identifier: "a" [20:7 - 20:8] MemberRefExpr=a:2:16
-// CHECK: Punctuation: "++" [20:8 - 20:10] UnaryOperator=
+// CHECK: Punctuation: "++" [20:8 - 20:10] UnaryOperator=++
// CHECK: Punctuation: ";" [20:10 - 20:11] CompoundStmt=
// CHECK: Punctuation: "}" [21:3 - 21:4] CompoundStmt=
// CHECK: Keyword: "while" [21:5 - 21:10] DoStmt=
diff --git a/clang/test/Index/blocks.c b/clang/test/Index/blocks.c
index 304c7800cb700..882ca40459acc 100644
--- a/clang/test/Index/blocks.c
+++ b/clang/test/Index/blocks.c
@@ -29,5 +29,5 @@ void test() {
// CHECK: blocks.c:9:50: MemberRefExpr=x:4:19 SingleRefName=[9:50 - 9:51] RefName=[9:50 - 9:51] Extent=[9:45 - 9:51]
// CHECK: blocks.c:9:45: DeclRefExpr=foo:9:23 Extent=[9:45 - 9:48]
// CHECK: blocks.c:9:54: DeclRefExpr=i:8:11 Extent=[9:54 - 9:55]
-// CHECK: blocks.c:9:59: UnaryOperator= Extent=[9:59 - 9:64]
+// CHECK: blocks.c:9:59: UnaryOperator=& Extent=[9:59 - 9:64]
// CHECK: blocks.c:9:60: DeclRefExpr=_foo:7:21 Extent=[9:60 - 9:64]
diff --git a/clang/test/Index/load-stmts.cpp b/clang/test/Index/load-stmts.cpp
index 0bfaf51daa259..c65c2295ca3d9 100644
--- a/clang/test/Index/load-stmts.cpp
+++ b/clang/test/Index/load-stmts.cpp
@@ -132,17 +132,17 @@ void casts(int *ip) {
// CHECK: load-stmts.cpp:4:23: DeclRefExpr=x:3:12 Extent=[4:23 - 4:24]
// CHECK: load-stmts.cpp:4:19: UnexposedExpr=z:4:19 Extent=[4:19 - 4:20]
// CHECK: load-stmts.cpp:4:19: DeclRefExpr=z:4:19 Extent=[4:19 - 4:20]
-// CHECK: load-stmts.cpp:4:26: UnaryOperator= Extent=[4:26 - 4:29]
+// CHECK: load-stmts.cpp:4:26: UnaryOperator=++ Extent=[4:26 - 4:29]
// CHECK: load-stmts.cpp:4:28: DeclRefExpr=x:3:12 Extent=[4:28 - 4:29]
// CHECK: load-stmts.cpp:6:10: VarDecl=z2:6:10 (Definition) Extent=[6:7 - 6:17]
// CHECK: load-stmts.cpp:6:7: TypeRef=T:1:13 Extent=[6:7 - 6:8]
-// CHECK: load-stmts.cpp:6:15: UnaryOperator= Extent=[6:15 - 6:17]
+// CHECK: load-stmts.cpp:6:15: UnaryOperator=& Extent=[6:15 - 6:17]
// CHECK: load-stmts.cpp:6:16: DeclRefExpr=x:3:12 Extent=[6:16 - 6:17]
// CHECK: load-stmts.cpp:6:10: UnexposedExpr=z2:6:10 Extent=[6:10 - 6:12]
// CHECK: load-stmts.cpp:6:10: DeclRefExpr=z2:6:10 Extent=[6:10 - 6:12]
// CHECK: load-stmts.cpp:7:13: VarDecl=z3:7:13 (Definition) Extent=[7:10 - 7:20]
// CHECK: load-stmts.cpp:7:10: TypeRef=T:1:13 Extent=[7:10 - 7:11]
-// CHECK: load-stmts.cpp:7:18: UnaryOperator= Extent=[7:18 - 7:20]
+// CHECK: load-stmts.cpp:7:18: UnaryOperator=& Extent=[7:18 - 7:20]
// CHECK: load-stmts.cpp:7:19: DeclRefExpr=x:3:12 Extent=[7:19 - 7:20]
// CHECK: load-stmts.cpp:7:13: UnexposedExpr=z3:7:13 Extent=[7:13 - 7:15]
// CHECK: load-stmts.cpp:7:13: DeclRefExpr=z3:7:13 Extent=[7:13 - 7:15]
diff --git a/clang/test/Index/print-type.c b/clang/test/Index/print-type.c
index 3ceecbd90b250..aa74b24d6c9a4 100644
--- a/clang/test/Index/print-type.c
+++ b/clang/test/Index/print-type.c
@@ -44,7 +44,7 @@ _Atomic(unsigned long) aul;
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: CallExpr=fn:3:55 [type=void] [typekind=Void] [args= [int] [Int]] [isPOD=0]
// CHECK: DeclRefExpr=fn:3:55 [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=void (int)] [pointeekind=FunctionProto]
-// CHECK: UnaryOperator= [type=int] [typekind=Int] [isPOD=1]
+// CHECK: UnaryOperator=* [type=int] [typekind=Int] [isPOD=1]
// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: VarDecl=w:5:17 (Definition) [type=const FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1]
diff --git a/clang/test/Index/recursive-cxx-member-calls.cpp b/clang/test/Index/recursive-cxx-member-calls.cpp
index c7f0053500c60..184ae07a19616 100644
--- a/clang/test/Index/recursive-cxx-member-calls.cpp
+++ b/clang/test/Index/recursive-cxx-member-calls.cpp
@@ -438,7 +438,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "size_t" [41:16 - 41:22] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "npos" [41:23 - 41:27] VarDecl=npos:41:23
// CHECK-tokens: Punctuation: "=" [41:28 - 41:29] VarDecl=npos:41:23
-// CHECK-tokens: Punctuation: "~" [41:30 - 41:31] UnaryOperator=
+// CHECK-tokens: Punctuation: "~" [41:30 - 41:31] UnaryOperator=~
// CHECK-tokens: Identifier: "size_t" [41:31 - 41:37] TypeRef=size_t:2:25
// CHECK-tokens: Punctuation: "(" [41:37 - 41:38] CXXFunctionalCastExpr=
// CHECK-tokens: Literal: "0" [41:38 - 41:39] IntegerLiteral=
@@ -867,7 +867,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [89:62 - 89:63] FunctionTemplate=Case:88:42 (Definition)
// CHECK-tokens: Punctuation: "{" [89:64 - 89:65] CompoundStmt=
// CHECK-tokens: Keyword: "return" [90:5 - 90:11] ReturnStmt=
-// CHECK-tokens: Punctuation: "*" [90:12 - 90:13] UnaryOperator=
+// CHECK-tokens: Punctuation: "*" [90:12 - 90:13] UnaryOperator=*
// CHECK-tokens: Keyword: "this" [90:13 - 90:17] CXXThisExpr=
// CHECK-tokens: Punctuation: ";" [90:17 - 90:18] CompoundStmt=
// CHECK-tokens: Punctuation: "}" [91:3 - 91:4] CompoundStmt=
@@ -1629,7 +1629,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 40:23: TypedefDecl=iterator:40:23 (Definition) Extent=[40:3 - 40:31]
// CHECK: 41:23: VarDecl=npos:41:23 Extent=[41:3 - 41:40]
// CHECK: 41:16: TypeRef=size_t:2:25 Extent=[41:16 - 41:22]
-// CHECK: 41:30: UnaryOperator= Extent=[41:30 - 41:40]
+// CHECK: 41:30: UnaryOperator=~ Extent=[41:30 - 41:40]
// CHECK: 41:31: CXXFunctionalCastExpr= Extent=[41:31 - 41:40]
// CHECK: 41:31: TypeRef=size_t:2:25 Extent=[41:31 - 41:37]
// CHECK: 41:38: UnexposedExpr= Extent=[41:38 - 41:39]
@@ -1856,7 +1856,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 89:57: ParmDecl=Value:89:57 (Definition) Extent=[89:47 - 89:62]
// CHECK: 89:64: CompoundStmt= Extent=[89:64 - 91:4]
// CHECK: 90:5: ReturnStmt= Extent=[90:5 - 90:17]
-// CHECK: 90:12: UnaryOperator= Extent=[90:12 - 90:17]
+// CHECK: 90:12: UnaryOperator=* Extent=[90:12 - 90:17]
// CHECK: 90:13: CXXThisExpr= Extent=[90:13 - 90:17]
// CHECK: 92:5: CXXMethod=Default:92:5 (Definition) (const) Extent=[92:3 - 94:4] [access=public]
// CHECK: 92:23: ParmDecl=Value:92:23 (Definition) Extent=[92:13 - 92:28]
diff --git a/clang/test/Index/unaryop.cpp b/clang/test/Index/unaryop.cpp
new file mode 100644
index 0000000000000..db0a617b294f1
--- /dev/null
+++ b/clang/test/Index/unaryop.cpp
@@ -0,0 +1,38 @@
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+
+void func(void) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-value"
+ int a = 0;
+ int *b = &a;
+ *b;
+ a++;
+ a--;
+ ++a;
+ --a;
+ +a;
+ -a;
+ !a;
+ ~a;
+
+ float _Complex c = 0;
+ __real c;
+ __imag c;
+
+ __extension__ a;
+#pragma clang diagnostic pop
+}
+
+// CHECK: unaryop.cpp:7:14: UnaryOperator=& Extent=[7:14 - 7:16]
+// CHECK: unaryop.cpp:8:5: UnaryOperator=* Extent=[8:5 - 8:7]
+// CHECK: unaryop.cpp:9:5: UnaryOperator=++ Extent=[9:5 - 9:8]
+// CHECK: unaryop.cpp:10:5: UnaryOperator=-- Extent=[10:5 - 10:8]
+// CHECK: unaryop.cpp:11:5: UnaryOperator=++ Extent=[11:5 - 11:8]
+// CHECK: unaryop.cpp:12:5: UnaryOperator=-- Extent=[12:5 - 12:8]
+// CHECK: unaryop.cpp:13:5: UnaryOperator=+ Extent=[13:5 - 13:7]
+// CHECK: unaryop.cpp:14:5: UnaryOperator=- Extent=[14:5 - 14:7]
+// CHECK: unaryop.cpp:15:5: UnaryOperator=! Extent=[15:5 - 15:7]
+// CHECK: unaryop.cpp:16:5: UnaryOperator=~ Extent=[16:5 - 16:7]
+// CHECK: unaryop.cpp:19:5: UnaryOperator=__real Extent=[19:5 - 19:13]
+// CHECK: unaryop.cpp:20:5: UnaryOperator=__imag Extent=[20:5 - 20:13]
+// CHECK: unaryop.cpp:22:5: UnaryOperator=__extension__ Extent=[22:5 - 22:20]
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 39e9e89b1ff00..fa3cce6a36708 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -5483,6 +5483,11 @@ CXString clang_getCursorSpelling(CXCursor C) {
clang_getCursorBinaryOperatorKind(C));
}
+ if (C.kind == CXCursor_UnaryOperator) {
+ return clang_getUnaryOperatorKindSpelling(
+ clang_getCursorUnaryOperatorKind(C));
+ }
+
const Decl *D = getDeclFromExpr(getCursorExpr(C));
if (D)
return getDeclSpelling(D);
>From 27192c5839682bbfb9fb27d4ef54029225fe88c7 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Mon, 31 Aug 2026 18:23:05 +0200
Subject: [PATCH 02/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
.../python/tests/cindex/test_cursor.py | 21 ++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index e8a77371f88e2..c18bc9c420e3c 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -988,8 +988,9 @@ def test_binop(self):
assert c.binary_operator == typ
def test_unaryop(self):
- tu = get_tu("""
- void func(void) {
+ tu = get_tu(
+ """
+ void func(void) {
int a = 0;
a++;
++a;
@@ -1004,8 +1005,9 @@ def test_unaryop(self):
__real b;
__imag b;
__extension__ a;
- }
- """, lang="cpp")
+ }""",
+ lang="cpp",
+ )
operators = {
"&": UnaryOperator.AddrOf,
@@ -1023,9 +1025,14 @@ def test_unaryop(self):
c = get_cursor(tu, op)
assert c.unary_operator == typ
- for should_be, has in zip(
- (UnaryOperator.PostInc, UnaryOperator.PreInc, UnaryOperator.PostDec, UnaryOperator.PreDec),
- list(next(tu.cursor.get_children()).get_children())[1:]):
+ shoulds = (
+ UnaryOperator.PostInc,
+ UnaryOperator.PreInc,
+ UnaryOperator.PostDec,
+ UnaryOperator.PreDec,
+ )
+ haves = list(next(tu.cursor.get_children()).get_children())[1:]
+ for should_be, has in zip(shoulds, haves):
assert should_be == has
def test_from_result_null(self):
>From 67fac6dcd259087e718b8f3d7ed3847e27b902c9 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Tue, 15 Sep 2026 12:04:27 +0200
Subject: [PATCH 03/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/clang/cindex.py | 6 +--
.../python/tests/cindex/test_cursor.py | 53 ++++++++++---------
2 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 9e01b0d88951d..6564e8eed47bd 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2044,10 +2044,10 @@ def unary_operator(self) -> UnaryOperator:
:return:
"""
- if not hasattr(self, "_binopcode"):
+ if not hasattr(self, "_unopcode"):
self._binopcode = conf.lib.clang_getCursorUnaryOperatorKind(self)
- return UnaryOperator.from_id(self._binopcode)
+ return UnaryOperator.from_id(self._unopcode)
@property
@cursor_null_guard
@@ -2513,7 +2513,7 @@ def is_postfix(self):
Real = 11
Imag = 12
Extension = 13
- CoAwait = 14
+ Coawait = 14
class StorageClass(BaseEnumeration):
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index c18bc9c420e3c..ec6b261d3f0bf 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -990,11 +990,9 @@ def test_binop(self):
def test_unaryop(self):
tu = get_tu(
"""
- void func(void) {
+ void prefix_func(void) {
int a = 0;
- a++;
++a;
- a--;
--a;
*(&a);
+a;
@@ -1005,35 +1003,40 @@ def test_unaryop(self):
__real b;
__imag b;
__extension__ a;
+ }
+ void postfix_func(void) {
+ int a = 0;
+ a++;
+ a--;
}""",
lang="cpp",
)
operators = {
- "&": UnaryOperator.AddrOf,
- "*": UnaryOperator.Deref,
- "+": UnaryOperator.Plus,
- "-": UnaryOperator.Minus,
- "~": UnaryOperator.Not,
- "!": UnaryOperator.LNot,
- "__real": UnaryOperator.Real,
- "__imag": UnaryOperator.Imag,
- "__extension__": UnaryOperator.Extension,
+ "prefix": {
+ "&": UnaryOperator.AddrOf,
+ "*": UnaryOperator.Deref,
+ "+": UnaryOperator.Plus,
+ "-": UnaryOperator.Minus,
+ "~": UnaryOperator.Not,
+ "!": UnaryOperator.LNot,
+ "++": UnaryOperator.PreInc,
+ "--": UnaryOperator.PreDec,
+ "__real": UnaryOperator.Real,
+ "__imag": UnaryOperator.Imag,
+ "__extension__": UnaryOperator.Extension,
+ },
+ "postfix": {
+ "++": UnaryOperator.PostInc,
+ "--": UnaryOperator.PostDec,
+ }
}
- for op, typ in operators.items():
- c = get_cursor(tu, op)
- assert c.unary_operator == typ
-
- shoulds = (
- UnaryOperator.PostInc,
- UnaryOperator.PreInc,
- UnaryOperator.PostDec,
- UnaryOperator.PreDec,
- )
- haves = list(next(tu.cursor.get_children()).get_children())[1:]
- for should_be, has in zip(shoulds, haves):
- assert should_be == has
+ for operator_type, ops in operators.items():
+ root = get_cursor(tu, f"{operator_type}_func")
+ for spelling, operator in ops.items():
+ c = get_cursor(root, spelling)
+ assert c is not None and c.unary_operator == operator
def test_from_result_null(self):
tu = get_tu("int a = 1+2;", lang="cpp")
>From cb2581b5240c9e92e9de18e467602612c1e6c701 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Tue, 15 Sep 2026 12:16:07 +0200
Subject: [PATCH 04/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/clang/cindex.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 6564e8eed47bd..563aa65208fa3 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2045,7 +2045,7 @@ def unary_operator(self) -> UnaryOperator:
"""
if not hasattr(self, "_unopcode"):
- self._binopcode = conf.lib.clang_getCursorUnaryOperatorKind(self)
+ self._unopcode = conf.lib.clang_getCursorUnaryOperatorKind(self)
return UnaryOperator.from_id(self._unopcode)
>From f660e0b2570d179c5ff44ffb6106a968bfffc688 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Tue, 15 Sep 2026 12:38:47 +0200
Subject: [PATCH 05/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/clang/cindex.py | 5 ++++-
clang/bindings/python/tests/cindex/test_cursor.py | 5 +++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 563aa65208fa3..be89d97287a94 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2497,7 +2497,10 @@ def __nonzero__(self):
return self.value != 0
def is_postfix(self):
- return self == UnaryOperator.PostDec or self == UnaryOperator.PostInc
+ return self in {
+ UnaryOperator.PostDec,
+ UnaryOperator.PostInc,
+ }
Invalid = 0
PostInc = 1
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index ec6b261d3f0bf..2b305b38094d1 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -1038,6 +1038,11 @@ def test_unaryop(self):
c = get_cursor(root, spelling)
assert c is not None and c.unary_operator == operator
+ for prefix in operators["prefix"].values():
+ assert not prefix.is_postfix()
+ for postfix in operators["postfix"].values():
+ assert postfix.is_postfix()
+
def test_from_result_null(self):
tu = get_tu("int a = 1+2;", lang="cpp")
op = next(next(tu.cursor.get_children()).get_children())
>From a845a13709576a0fafedfbe75e43047fa276a8bc Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Tue, 15 Sep 2026 13:47:09 +0200
Subject: [PATCH 06/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/include/clang-c/Index.h | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 1c8d097f1beab..3337c8c845614 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -6916,35 +6916,35 @@ clang_getCursorBinaryOperatorKind(CXCursor cursor);
*/
enum CXUnaryOperatorKind {
/** This value describes cursors which are not unary operators. */
- CXUnaryOperator_Invalid,
+ CXUnaryOperator_Invalid = 0,
/** Postfix increment operator. */
- CXUnaryOperator_PostInc,
+ CXUnaryOperator_PostInc = 1,
/** Postfix decrement operator. */
- CXUnaryOperator_PostDec,
+ CXUnaryOperator_PostDec = 2,
/** Prefix increment operator. */
- CXUnaryOperator_PreInc,
+ CXUnaryOperator_PreInc = 3,
/** Prefix decrement operator. */
- CXUnaryOperator_PreDec,
+ CXUnaryOperator_PreDec = 4,
/** Address of operator. */
- CXUnaryOperator_AddrOf,
+ CXUnaryOperator_AddrOf = 5,
/** Dereference operator. */
- CXUnaryOperator_Deref,
+ CXUnaryOperator_Deref = 6,
/** Plus operator. */
- CXUnaryOperator_Plus,
+ CXUnaryOperator_Plus = 7,
/** Minus operator. */
- CXUnaryOperator_Minus,
+ CXUnaryOperator_Minus = 8,
/** Not operator. */
- CXUnaryOperator_Not,
+ CXUnaryOperator_Not = 9,
/** LNot operator. */
- CXUnaryOperator_LNot,
+ CXUnaryOperator_LNot = 10,
/** "__real expr" operator. */
- CXUnaryOperator_Real,
+ CXUnaryOperator_Real = 11,
/** "__imag expr" operator. */
- CXUnaryOperator_Imag,
+ CXUnaryOperator_Imag = 12,
/** __extension__ marker operator. */
- CXUnaryOperator_Extension,
+ CXUnaryOperator_Extension = 13,
/** C++ co_await operator. */
- CXUnaryOperator_Coawait,
+ CXUnaryOperator_Coawait = 14,
CXUnaryOperator_Last = CXUnaryOperator_Coawait
};
>From 8985b776480a07af639c6170568418118555f102 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Tue, 15 Sep 2026 15:11:09 +0200
Subject: [PATCH 07/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/tests/cindex/test_cursor.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index 2b305b38094d1..5345645dc516e 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -1029,7 +1029,7 @@ def test_unaryop(self):
"postfix": {
"++": UnaryOperator.PostInc,
"--": UnaryOperator.PostDec,
- }
+ },
}
for operator_type, ops in operators.items():
>From 3d5b66962bff1daaee58b0c5e24fcbf42add4df9 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Wed, 16 Sep 2026 10:50:33 +0200
Subject: [PATCH 08/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/tests/cindex/test_cursor.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index 5345645dc516e..0a4081d918f44 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -1032,8 +1032,8 @@ def test_unaryop(self):
},
}
- for operator_type, ops in operators.items():
- root = get_cursor(tu, f"{operator_type}_func")
+ for operator_position, ops in operators.items():
+ root = get_cursor(tu, f"{operator_position}_func")
for spelling, operator in ops.items():
c = get_cursor(root, spelling)
assert c is not None and c.unary_operator == operator
>From 2bc2e02022bd0287174fedcf6adb999d630591e4 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Wed, 16 Sep 2026 10:56:12 +0200
Subject: [PATCH 09/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/docs/ReleaseNotes.md | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index d23eacffd9f9f..41bd7750b9f7a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -705,7 +705,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.
-- add unary operator handling to clang_getCursorSpelling()
+- add unary operator handling to `clang_getCursorSpelling()`.
### Code Completion
@@ -741,8 +741,7 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was renamed to `alpha.core.Use
### Python Binding Changes
-- Add support for retrieving unary operator information through
- Cursor.unary_operator().
+- Add support for retrieving unary operator information through `Cursor.unary_operator()`.
### OpenMP Support
>From f033db8c393c43162cfda83c89b85dfa2d6c8959 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Thu, 17 Sep 2026 00:15:10 +0200
Subject: [PATCH 10/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/clang/cindex.py | 4 ++--
clang/bindings/python/tests/cindex/test_cursor.py | 6 ++++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index be89d97287a94..ca10aec5d7c7a 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2492,8 +2492,8 @@ class UnaryOperator(BaseEnumeration):
Describes the UnaryOperator of a declaration
"""
- def __nonzero__(self):
- """Allows checks of the kind ```if cursor.unary_operator:```"""
+ def __bool__(self):
+ """Indicates whether this object is a valid UnaryOperator."""
return self.value != 0
def is_postfix(self):
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index 0a4081d918f44..18ddaf5e76ec4 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -1043,6 +1043,12 @@ def test_unaryop(self):
for postfix in operators["postfix"].values():
assert postfix.is_postfix()
+ for operator in UnaryOperator:
+ if operator:
+ assert operator is not UnaryOperator.Invalid
+ else:
+ assert operator is UnaryOperator.Invalid
+
def test_from_result_null(self):
tu = get_tu("int a = 1+2;", lang="cpp")
op = next(next(tu.cursor.get_children()).get_children())
>From 4285bcc75bde7932bc1294754a831e4838c9815a Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Thu, 17 Sep 2026 00:21:44 +0200
Subject: [PATCH 11/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/clang/cindex.py | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index ca10aec5d7c7a..03b7eb47c3467 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2039,10 +2039,7 @@ def binary_operator(self) -> BinaryOperator:
@property
@cursor_null_guard
def unary_operator(self) -> UnaryOperator:
- """
- Retrieves the opcode if this cursor points to a unary operator
- :return:
- """
+ """Retrieves the unary operator if this cursor has one."""
if not hasattr(self, "_unopcode"):
self._unopcode = conf.lib.clang_getCursorUnaryOperatorKind(self)
@@ -2488,9 +2485,7 @@ def is_assignment(self):
class UnaryOperator(BaseEnumeration):
- """
- Describes the UnaryOperator of a declaration
- """
+ """A UnaryOperator describes an expression's of unary operator kind."""
def __bool__(self):
"""Indicates whether this object is a valid UnaryOperator."""
>From d81c34707ac1ebfe416fee3fcc7840d0b409b44f Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Thu, 17 Sep 2026 00:50:16 +0200
Subject: [PATCH 12/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/include/clang-c/Index.h | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 3337c8c845614..1c8d097f1beab 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -6916,35 +6916,35 @@ clang_getCursorBinaryOperatorKind(CXCursor cursor);
*/
enum CXUnaryOperatorKind {
/** This value describes cursors which are not unary operators. */
- CXUnaryOperator_Invalid = 0,
+ CXUnaryOperator_Invalid,
/** Postfix increment operator. */
- CXUnaryOperator_PostInc = 1,
+ CXUnaryOperator_PostInc,
/** Postfix decrement operator. */
- CXUnaryOperator_PostDec = 2,
+ CXUnaryOperator_PostDec,
/** Prefix increment operator. */
- CXUnaryOperator_PreInc = 3,
+ CXUnaryOperator_PreInc,
/** Prefix decrement operator. */
- CXUnaryOperator_PreDec = 4,
+ CXUnaryOperator_PreDec,
/** Address of operator. */
- CXUnaryOperator_AddrOf = 5,
+ CXUnaryOperator_AddrOf,
/** Dereference operator. */
- CXUnaryOperator_Deref = 6,
+ CXUnaryOperator_Deref,
/** Plus operator. */
- CXUnaryOperator_Plus = 7,
+ CXUnaryOperator_Plus,
/** Minus operator. */
- CXUnaryOperator_Minus = 8,
+ CXUnaryOperator_Minus,
/** Not operator. */
- CXUnaryOperator_Not = 9,
+ CXUnaryOperator_Not,
/** LNot operator. */
- CXUnaryOperator_LNot = 10,
+ CXUnaryOperator_LNot,
/** "__real expr" operator. */
- CXUnaryOperator_Real = 11,
+ CXUnaryOperator_Real,
/** "__imag expr" operator. */
- CXUnaryOperator_Imag = 12,
+ CXUnaryOperator_Imag,
/** __extension__ marker operator. */
- CXUnaryOperator_Extension = 13,
+ CXUnaryOperator_Extension,
/** C++ co_await operator. */
- CXUnaryOperator_Coawait = 14,
+ CXUnaryOperator_Coawait,
CXUnaryOperator_Last = CXUnaryOperator_Coawait
};
>From e596325eec0974885f4b9855bf191891136812ef Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Mon, 21 Sep 2026 10:31:21 +0200
Subject: [PATCH 13/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/clang/cindex.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 03b7eb47c3467..f41fbcd62e3fe 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2485,7 +2485,7 @@ def is_assignment(self):
class UnaryOperator(BaseEnumeration):
- """A UnaryOperator describes an expression's of unary operator kind."""
+ """Describes the kind of unary operators."""
def __bool__(self):
"""Indicates whether this object is a valid UnaryOperator."""
>From ebdd7d85b3377978df6bc36c8614268fd5f2edb6 Mon Sep 17 00:00:00 2001
From: Erik Julian Radermacher <erik.radermacher at uni-osnabrueck.de>
Date: Mon, 21 Sep 2026 10:48:34 +0200
Subject: [PATCH 14/14] fixup! Add retrieval of unary operator spelling and
python bindings
---
clang/bindings/python/clang/cindex.py | 4 ----
clang/bindings/python/tests/cindex/test_cursor.py | 6 ------
2 files changed, 10 deletions(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index f41fbcd62e3fe..a0107b730f3a1 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2487,10 +2487,6 @@ def is_assignment(self):
class UnaryOperator(BaseEnumeration):
"""Describes the kind of unary operators."""
- def __bool__(self):
- """Indicates whether this object is a valid UnaryOperator."""
- return self.value != 0
-
def is_postfix(self):
return self in {
UnaryOperator.PostDec,
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index 18ddaf5e76ec4..0a4081d918f44 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -1043,12 +1043,6 @@ def test_unaryop(self):
for postfix in operators["postfix"].values():
assert postfix.is_postfix()
- for operator in UnaryOperator:
- if operator:
- assert operator is not UnaryOperator.Invalid
- else:
- assert operator is UnaryOperator.Invalid
-
def test_from_result_null(self):
tu = get_tu("int a = 1+2;", lang="cpp")
op = next(next(tu.cursor.get_children()).get_children())
More information about the cfe-commits
mailing list