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..c18bc9c420e3c 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,54 @@ 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 + + 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): 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);