Index: bindings/python/clang/cindex.py =================================================================== --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1285,6 +1285,18 @@ return StorageClass.from_id(self._storage_class) @property + def binary_operator(self): + """ + Retrieves the opcode if this cursor points to a binary operator + :return: + """ + + if not hasattr(self, '_binopcode'): + self._binopcode = conf.lib.clang_Cursor_getBinaryOpcode(self) + + return BinaryOperator.from_id(self._binopcode) + + @property def access_specifier(self): """ Retrieves the access specifier (if any) of the entity pointed at by the @@ -1560,6 +1572,60 @@ res._tu = args[0]._tu return res +class BinaryOperator(BaseEnumeration): + """ + Describes the BinaryOperator of a declaration + """ + + # The unique kind objects, index by id. + _kinds = [] + _name_map = None + + def __nonzero__(self): + """ Allows checks of the kind ```if cursor.binary_operator:```""" + return self.value != 0 + + @property + def is_assignment(self): + return BinaryOperator.Assign.value <= self.value < BinaryOperator.Comma.value + + def __repr__(self): + return 'BinaryOperator.%s' % (self.name,) + +BinaryOperator.Invalid = BinaryOperator(0) +BinaryOperator.PtrMemD = BinaryOperator(1) +BinaryOperator.PtrMemI = BinaryOperator(2) +BinaryOperator.Mul = BinaryOperator(3) +BinaryOperator.Div = BinaryOperator(4) +BinaryOperator.Rem = BinaryOperator(5) +BinaryOperator.Add = BinaryOperator(6) +BinaryOperator.Sub = BinaryOperator(7) +BinaryOperator.Shl = BinaryOperator(8) +BinaryOperator.Shr = BinaryOperator(9) +BinaryOperator.LT = BinaryOperator(10) +BinaryOperator.GT = BinaryOperator(11) +BinaryOperator.LE = BinaryOperator(12) +BinaryOperator.GE = BinaryOperator(13) +BinaryOperator.EQ = BinaryOperator(14) +BinaryOperator.NE = BinaryOperator(15) +BinaryOperator.And = BinaryOperator(16) +BinaryOperator.Xor = BinaryOperator(17) +BinaryOperator.Or = BinaryOperator(18) +BinaryOperator.LAnd = BinaryOperator(19) +BinaryOperator.LOr = BinaryOperator(20) +BinaryOperator.Assign = BinaryOperator(21) +BinaryOperator.MulAssign = BinaryOperator(22) +BinaryOperator.DivAssign = BinaryOperator(23) +BinaryOperator.RemAssign = BinaryOperator(24) +BinaryOperator.AddAssign = BinaryOperator(25) +BinaryOperator.SubAssign = BinaryOperator(26) +BinaryOperator.ShlAssign = BinaryOperator(27) +BinaryOperator.ShrAssign = BinaryOperator(28) +BinaryOperator.AndAssign = BinaryOperator(29) +BinaryOperator.XorAssign = BinaryOperator(30) +BinaryOperator.OrAssign = BinaryOperator(31) +BinaryOperator.Comma = BinaryOperator(32) + class StorageClass(object): """ Describes the storage class of a declaration Index: bindings/python/tests/cindex/test_cursor.py =================================================================== --- bindings/python/tests/cindex/test_cursor.py +++ bindings/python/tests/cindex/test_cursor.py @@ -5,6 +5,7 @@ from clang.cindex import TemplateArgumentKind from clang.cindex import TranslationUnit from clang.cindex import TypeKind +from clang.cindex import BinaryOperator from .util import get_cursor from .util import get_cursors from .util import get_tu @@ -266,6 +267,109 @@ assert ham.kind == CursorKind.ENUM_CONSTANT_DECL assert ham.enum_value == 0x10000000000 +binops = """ +struct C { + int m; + }; + + void func(void){ + int a, b; + int C::* p = &C:: + + C c; + c.*p; + + C* pc; + pc->*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; + + } + """ + +def test_binop(): + tu = get_tu(binops, lang="cpp") + + operators = { + # not exposed yet + # ".*" : BinaryOperator.PtrMemD, + "->*" : BinaryOperator.PtrMemI, + "*" : BinaryOperator.Mul, + "/" : BinaryOperator.Div, + "%" : BinaryOperator.Rem, + "+" : BinaryOperator.Add, + "-" : BinaryOperator.Sub, + "<<" : BinaryOperator.Shl, + ">>" : BinaryOperator.Shr, + "<" : BinaryOperator.LT, + ">" : BinaryOperator.GT, + "<=" : BinaryOperator.LE, + ">=" : BinaryOperator.GE, + "==" : BinaryOperator.EQ, + "!=" : BinaryOperator.NE, + "&" : BinaryOperator.And, + "^" : BinaryOperator.Xor, + "|" : BinaryOperator.Or, + "&&" : BinaryOperator.LAnd, + "||" : BinaryOperator.LOr, + "=" : BinaryOperator.Assign, + "*=" : BinaryOperator.MulAssign, + "/=" : BinaryOperator.DivAssign, + "%=" : BinaryOperator.RemAssign, + "+=" : BinaryOperator.AddAssign, + "-=" : BinaryOperator.SubAssign, + "<<=" : BinaryOperator.ShlAssign, + ">>=" : BinaryOperator.ShrAssign, + "&=" : BinaryOperator.AndAssign, + "^=" : BinaryOperator.XorAssign, + "|=" : BinaryOperator.OrAssign, + "," : BinaryOperator.Comma, + } + + + for op, typ in operators.items(): + c = get_cursor(tu, op) + assert c.binary_operator == typ + + def test_annotation_attribute(): tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));') Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -3875,6 +3875,53 @@ */ CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C); +enum CX_BinaryOperatorKind { + CX_BO_Invalid = 0, + CX_BO_PtrMemD = 1, + CX_BO_PtrMemI = 2, + CX_BO_Mul = 3, + CX_BO_Div = 4, + CX_BO_Rem = 5, + CX_BO_Add = 6, + CX_BO_Sub = 7, + CX_BO_Shl = 8, + CX_BO_Shr = 9, + CX_BO_LT = 10, + CX_BO_GT = 11, + CX_BO_LE = 12, + CX_BO_GE = 13, + CX_BO_EQ = 14, + CX_BO_NE = 15, + CX_BO_And = 16, + CX_BO_Xor = 17, + CX_BO_Or = 18, + CX_BO_LAnd = 19, + CX_BO_LOr = 20, + CX_BO_Assign = 21, + CX_BO_MulAssign = 22, + CX_BO_DivAssign = 23, + CX_BO_RemAssign = 24, + CX_BO_AddAssign = 25, + CX_BO_SubAssign = 26, + CX_BO_ShlAssign = 27, + CX_BO_ShrAssign = 29, + CX_BO_AndAssign = 29, + CX_BO_XorAssign = 30, + CX_BO_OrAssign = 31, + CX_BO_Comma = 32, + CX_BO_LAST = CX_BO_Comma +}; + +/** + * \brief Returns the operator code for the binary operator. + */ +CINDEX_LINKAGE enum CX_BinaryOperatorKind clang_Cursor_getBinaryOpcode(CXCursor C); + +/** + * \brief Returns a string containing the spelling of the binary operator. + */ +CINDEX_LINKAGE CXString clang_Cursor_getBinaryOpcodeStr(enum CX_BinaryOperatorKind Op); + /** * \brief Given a cursor that represents a declaration, return the associated * comment's source range. The range may include multiple consecutive comments Index: include/clang/AST/OperationKinds.h =================================================================== --- include/clang/AST/OperationKinds.h +++ include/clang/AST/OperationKinds.h @@ -305,7 +305,8 @@ enum BinaryOperatorKind { // Operators listed in order of precedence. - // Note that additions to this should also update the StmtVisitor class. + // Note that additions to this should also update the StmtVisitor class + // and the C bindings in libclang. BO_PtrMemD, BO_PtrMemI, // [C++ 5.5] Pointer-to-member operators. BO_Mul, BO_Div, BO_Rem, // [C99 6.5.5] Multiplicative operators. BO_Add, BO_Sub, // [C99 6.5.6] Additive operators. Index: test/Index/binop.cpp =================================================================== --- /dev/null +++ test/Index/binop.cpp @@ -0,0 +1,90 @@ +// RUN: c-index-test -test-print-binops %s | FileCheck %s + +struct C { + int m; +}; + +void func(void){ + int a, b; + int C::* p = &C::m; + + C c; + c.*p; + + C* pc; + pc->*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; + +} + +// CHECK: BinaryOperator=.* BinOp=.* 1 +// CHECK: BinaryOperator=->* BinOp=->* 2 +// CHECK: BinaryOperator=* BinOp=* 3 +// CHECK: BinaryOperator=/ BinOp=/ 4 +// CHECK: BinaryOperator=% BinOp=% 5 +// CHECK: BinaryOperator=+ BinOp=+ 6 +// CHECK: BinaryOperator=- BinOp=- 7 +// CHECK: BinaryOperator=<< BinOp=<< 8 +// CHECK: BinaryOperator=>> BinOp=>> 9 +// CHECK: BinaryOperator=< BinOp=< 10 +// CHECK: BinaryOperator=> BinOp=> 11 +// CHECK: BinaryOperator=<= BinOp=<= 12 +// CHECK: BinaryOperator=>= BinOp=>= 13 +// CHECK: BinaryOperator=== BinOp=== 14 +// CHECK: BinaryOperator=!= BinOp=!= 15 +// CHECK: BinaryOperator=& BinOp=& 16 +// CHECK: BinaryOperator=^ BinOp=^ 17 +// CHECK: BinaryOperator=| BinOp=| 18 +// CHECK: BinaryOperator=&& BinOp=&& 19 +// CHECK: BinaryOperator=|| BinOp=|| 20 +// CHECK: BinaryOperator== BinOp== 21 +// CHECK: CompoundAssignOperator=*= BinOp=*= 22 +// CHECK: CompoundAssignOperator=/= BinOp=/= 23 +// CHECK: CompoundAssignOperator=%= BinOp=%= 24 +// CHECK: CompoundAssignOperator=+= BinOp=+= 25 +// CHECK: CompoundAssignOperator=-= BinOp=-= 26 +// CHECK: CompoundAssignOperator=<<= BinOp=<<= 27 +// CHECK: CompoundAssignOperator=>>= BinOp=>>= 28 +// CHECK: CompoundAssignOperator=&= BinOp=&= 29 +// CHECK: CompoundAssignOperator=^= BinOp=^= 30 +// CHECK: CompoundAssignOperator=|= BinOp=|= 31 +// CHECK: BinaryOperator=, BinOp=, 32 Index: tools/c-index-test/c-index-test.c =================================================================== --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -1451,6 +1451,20 @@ return CXChildVisit_Recurse; } +static enum CXChildVisitResult PrintBinOps(CXCursor C, CXCursor p, + CXClientData d){ + enum CXCursorKind ck = clang_getCursorKind(C); + if (ck != CXCursor_BinaryOperator && ck != CXCursor_CompoundAssignOperator) + return CXChildVisit_Recurse; + + PrintCursor(C, NULL); + enum CX_BinaryOperatorKind bok = clang_Cursor_getBinaryOpcode(C); + CXString opstr = clang_Cursor_getBinaryOpcodeStr(bok); + printf(" BinOp=%s %d\n", clang_getCString(opstr), bok); + + return CXChildVisit_Recurse; +} + /******************************************************************************/ /* Mangling testing. */ /******************************************************************************/ @@ -4114,6 +4128,7 @@ " c-index-test -test-print-type {}*\n" " c-index-test -test-print-type-size {}*\n" " c-index-test -test-print-bitwidth {}*\n" + " c-index-test -test-print-binops {}*\n" " c-index-test -print-usr [ {}]*\n" " c-index-test -print-usr-file \n" " c-index-test -write-pch \n"); @@ -4210,6 +4225,9 @@ else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", 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-mangle") == 0) return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL); else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0) Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -3799,6 +3799,11 @@ return cxstring::createDup(OS.str()); } + if (C.kind == CXCursor_BinaryOperator || + C.kind == CXCursor_CompoundAssignOperator) { + return clang_Cursor_getBinaryOpcodeStr(clang_Cursor_getBinaryOpcode(C)); + } + const Decl *D = getDeclFromExpr(getCursorExpr(C)); if (D) return getDeclSpelling(D); @@ -6892,6 +6897,29 @@ return 0; } +enum CX_BinaryOperatorKind clang_Cursor_getBinaryOpcode(CXCursor C) { + if (C.kind != CXCursor_BinaryOperator && + C.kind != CXCursor_CompoundAssignOperator) { + return CX_BO_Invalid; + } + + const Expr *D = getCursorExpr(C); + if (const BinaryOperator *BinOp = dyn_cast(D)) { + return static_cast(BinOp->getOpcode() + 1); + } + + return CX_BO_Invalid; +} + +CXString clang_Cursor_getBinaryOpcodeStr(enum CX_BinaryOperatorKind Op) { + if (Op > CX_BO_LAST) { + return cxstring::createEmpty(); + } + + return cxstring::createDup( + BinaryOperator::getOpcodeStr(static_cast(Op - 1))); +} + CXSourceRange clang_Cursor_getCommentRange(CXCursor C) { if (!clang_isDeclaration(C.kind)) return clang_getNullRange();