1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This file uses the same license as the C++ source code. 7 */ 8 module dextool.clang_extensions; 9 10 import clang.c.Index; 11 12 extern (C++,dextool_clang_extension) { 13 extern (C++,McCabe) { 14 extern (C++) struct Result { 15 /// Only valid values if true. 16 bool hasValue; 17 /// McCabe complexity 18 int value; 19 } 20 21 /** Calculate the McCabe complexity. 22 * 23 * Valid cursors are those with a body. 24 * decl.isDefinition must be true. 25 * 26 * Tested CXCursor kinds that are definitions: 27 * - FunctionDecl 28 * - ConversionFunction 29 * - Constructor 30 * - Destructor 31 * - CXXMethod 32 */ 33 extern (C++) Result calculate(CXCursor decl); 34 } 35 36 /// Represent the operator of an expression that contains an operator (binary or unary). 37 extern (C++) struct DXOperator { 38 /// Only valid values if true. 39 bool hasValue; 40 OpKind kind; 41 42 /// The location of the operator 43 CXSourceLocation location; 44 /// Character length of the operator 45 byte opLength; 46 47 /// The cursor for the operator. 48 CXCursor cursor; 49 } 50 51 enum ValueKind { 52 unknown, 53 lvalue, 54 rvalue, 55 xvalue, 56 glvalue 57 } 58 59 enum OpKind { 60 // See: include/clang/AST/OperationKinds.def under section Binary Operations 61 62 // [C++ 5.5] Pointer-to-member operators. 63 PtrMemD, // ".*" 64 PtrMemI, // "->*" 65 // [C99 6.5.5] Multiplicative operators. 66 Mul, // "*" 67 Div, // "/" 68 Rem, // "%" 69 // [C99 6.5.6] Additive operators. 70 Add, // "+" 71 Sub, // "-" 72 // [C99 6.5.7] Bitwise shift operators. 73 Shl, // "<<" 74 Shr, // ">>" 75 // [C99 6.5.8] Relational operators. 76 LT, // "<" 77 GT, // ">" 78 LE, // "<=" 79 GE, // ">=" 80 // [C99 6.5.9] Equality operators. 81 EQ, // "==" 82 NE, // "!=" 83 // [C99 6.5.10] Bitwise AND operator. 84 And, // "&" 85 // [C99 6.5.11] Bitwise XOR operator. 86 Xor, // "^" 87 // [C99 6.5.12] Bitwise OR operator. 88 Or, // "|" 89 // [C99 6.5.13] Logical AND operator. 90 LAnd, // "&&" 91 // [C99 6.5.14] Logical OR operator. 92 LOr, // "||" 93 // [C99 6.5.16] Assignment operators. 94 Assign, // "=" 95 MulAssign, // "*=" 96 DivAssign, // "/=" 97 RemAssign, // "%=" 98 AddAssign, // "+=" 99 SubAssign, // "-=" 100 ShlAssign, // "<<=" 101 ShrAssign, // ">>=" 102 AndAssign, // "&=" 103 XorAssign, // "^=" 104 OrAssign, // "|=" 105 // [C99 6.5.17] Comma operator. 106 Comma, // "," 107 108 // See: include/clang/AST/OperationKinds.def under section Unary Operations 109 // [C99 6.5.2.4] Postfix increment and decrement 110 PostInc, // "++" 111 PostDec, // "--" 112 // [C99 6.5.3.1] Prefix increment and decrement 113 PreInc, // "++" 114 PreDec, // "--" 115 // [C99 6.5.3.2] Address and indirection 116 AddrOf, // "&" 117 Deref, // "*" 118 // [C99 6.5.3.3] Unary arithmetic 119 Plus, // "+" 120 Minus, // "-" 121 Not, // "~" 122 LNot, // "!" 123 // "__real expr"/"__imag expr" Extension. 124 Real, // "__real" 125 Imag, // "__imag" 126 // __extension__ marker. 127 Extension, // "__extension__" 128 // [C++ Coroutines] co_await operator 129 Coawait, // "co_await" 130 131 // See: include/clang/Basic/OperationKinds.def 132 // CXXOperatorCallExpr->getOperator kinds 133 OO_New, // "new" 134 OO_Delete, // "delete" 135 OO_Array_New, // "new[] 136 OO_Array_Delete, // "delete[] 137 OO_Plus, // "+" 138 OO_Minus, // "-" 139 OO_Star, // "*" 140 OO_Slash, // "/" 141 OO_Percent, // "%" 142 OO_Caret, // "^" 143 OO_Amp, // "&" 144 OO_Pipe, // "|" 145 OO_Tilde, // "~" 146 OO_Exclaim, // "!" 147 OO_Equal, // "=" 148 OO_Less, // "<" 149 OO_Greater, // ">" 150 OO_PlusEqual, // "+=" 151 OO_MinusEqual, // "-=" 152 OO_StarEqual, // "*=" 153 OO_SlashEqual, // "/=" 154 OO_PercentEqual, // "%=" 155 OO_CaretEqual, // "^=" 156 OO_AmpEqual, // "&=" 157 OO_PipeEqual, // "|=" 158 OO_LessLess, // "<<" 159 OO_GreaterGreater, // ">>" 160 OO_LessLessEqual, // "<<=" 161 OO_GreaterGreaterEqual, // ">>=" 162 OO_EqualEqual, // "==" 163 OO_ExclaimEqual, // "!=" 164 OO_LessEqual, // "<=" 165 OO_GreaterEqual, // ">=" 166 OO_AmpAmp, // "&&" 167 OO_PipePipe, // "||" 168 OO_PlusPlus, // "++" 169 OO_MinusMinus, // "--" 170 OO_Comma, // "," 171 OO_ArrowStar, // "->*" 172 OO_Arrow, // "->" 173 OO_Call, // "()" 174 OO_Subscript, // "[]" 175 OO_Conditional, // "?" 176 OO_Coawait, // "co_await" 177 } 178 179 /** Retrieve the operator of an expression. 180 * 181 * Acceptable CXCursor kinds are: 182 * - binaryOperator 183 * - unaryOperator 184 * - callExpr 185 */ 186 extern (C++) DXOperator dex_getExprOperator(const CXCursor expr); 187 188 /// The sub-expressions of an operator expression. 189 extern (C++) struct DXOperatorExprs { 190 CXCursor lhs; 191 CXCursor rhs; 192 } 193 194 /** Retrieve the left and right side of an operator expression. 195 * 196 * Acceptable CXCursor kinds are: 197 * - binaryOperator 198 * - unaryOperator 199 * - callExpr 200 */ 201 extern (C++) DXOperatorExprs dex_getOperatorExprs(const CXCursor expr); 202 203 /// Retrieve the value kind of the expression. 204 extern (C++) ValueKind dex_getExprValueKind(const CXCursor expr); 205 206 /// Get the first node after the expressions. 207 extern (C++) CXCursor dex_getUnderlyingExprNode(const CXCursor expr); 208 209 /// The cursors that make up the inside of the if statement. 210 extern (C++) struct DXIfStmt { 211 CXCursor init_; 212 CXCursor cond; 213 CXCursor then; 214 CXCursor else_; 215 } 216 217 extern (C++) DXIfStmt dex_getIfStmt(const CXCursor cx); 218 219 extern (C++) struct DXCaseStmt { 220 bool hasValue; 221 CXSourceLocation colonLoc; 222 CXCursor subStmt; 223 CXSourceLocation beginLoc; 224 CXSourceLocation endLoc; 225 } 226 227 extern (C++) DXCaseStmt dex_getCaseStmt(const CXCursor cx); 228 } 229 230 Operator getExprOperator(const CXCursor expr) @trusted { 231 import std.algorithm : among; 232 233 // This check is technically not needed because the C++ source code try to 234 // do a dynamic cast. But by having a check here it is easier to review 235 // that THIS function is correctly implemented. 236 // This function is safe for all possible inputs. 237 // Note: CXXOperatorCallExpr is denoted callExpr in the C API. 238 if (clang_getCursorKind(expr).among(CXCursorKind.binaryOperator, 239 CXCursorKind.unaryOperator, CXCursorKind.callExpr)) { 240 return Operator(dex_getExprOperator(expr)); 241 } 242 243 return Operator(); 244 } 245 246 /** 247 * trusted: the C++ impl check that the node is an expression. 248 * It can handle any CursorKind. 249 */ 250 ValueKind exprValueKind(const CXCursor expr) @trusted { 251 return dex_getExprValueKind(expr); 252 } 253 254 /** 255 * trusted: the C++ impl check that the node is an expression. 256 * It can handle any CursorKind. 257 */ 258 auto getUnderlyingExprNode(const CXCursor expr) @trusted { 259 return dex_getUnderlyingExprNode(expr); 260 } 261 262 @safe struct OperatorSubExprs { 263 import clang.Cursor; 264 265 Cursor lhs, rhs; 266 } 267 268 @safe struct Operator { 269 import std.format : FormatSpec; 270 import clang.Cursor; 271 import clang.SourceLocation; 272 273 private DXOperator dx; 274 275 this(DXOperator v) { 276 dx = v; 277 } 278 279 bool isValid() const { 280 return dx.hasValue; 281 } 282 283 auto kind() const { 284 return dx.kind; 285 } 286 287 /// Cursor for the expression that the operator reside in. 288 Cursor cursor() const { 289 return Cursor(dx.cursor); 290 } 291 292 /** Retrieve the sub expressions of an operator expressions. 293 * 294 * rhs is the null cursor for unary operators. 295 * 296 * Returns: The sides of the expression. 297 * 298 * trusted: 299 * dex_getOperatorExprs is limited to only being able to handle operator 300 * expressions. 301 * getExprOperator only processes binary, unary and callExpr cursors. 302 * This lead to isValid only returning true when the cursor is of that type. 303 * Thus the limitation of dex_getOperatorExprs is fulfilled. 304 * 305 * TODO Further audit of the C++ implementation of dex_getOperatorExprs is 306 * needed. 307 */ 308 OperatorSubExprs sides() const @trusted { 309 OperatorSubExprs r; 310 311 if (isValid) { 312 auto sub_exprs = dex_getOperatorExprs(dx.cursor); 313 r = OperatorSubExprs(Cursor(sub_exprs.lhs), Cursor(sub_exprs.rhs)); 314 } 315 316 return r; 317 } 318 319 SourceLocation location() const { 320 return SourceLocation(dx.location); 321 } 322 323 /// The character length of the operator. 324 size_t length() const { 325 return dx.opLength; 326 } 327 328 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 329 import std.format : formatValue, formattedWrite; 330 import std.range.primitives : put; 331 332 put(w, "Operator("); 333 formatValue(w, kind, fmt); 334 put(w, " len:"); 335 formatValue(w, length, fmt); 336 put(w, " "); 337 formatValue(w, location, fmt); 338 put(w, ")"); 339 } 340 } 341 342 IfStmt getIfStmt(const CXCursor cx) @trusted { 343 if (clang_getCursorKind(cx) == CXCursorKind.ifStmt) 344 return IfStmt(cx, dex_getIfStmt(cx)); 345 346 return IfStmt(); 347 } 348 349 @safe struct IfStmt { 350 import std.format : FormatSpec; 351 import clang.Cursor; 352 353 private Cursor cx; 354 private DXIfStmt stmt; 355 356 this(const CXCursor parent_, DXIfStmt stmt) { 357 this.cx = Cursor(parent_); 358 this.stmt = stmt; 359 } 360 361 Cursor cursor() const { 362 return cx; 363 } 364 365 Cursor init_() const { 366 return Cursor(stmt.init_); 367 } 368 369 Cursor cond() const { 370 return Cursor(stmt.cond); 371 } 372 373 Cursor then() const { 374 return Cursor(stmt.then); 375 } 376 377 Cursor else_() const { 378 return Cursor(stmt.else_); 379 } 380 381 string toString() const { 382 import std.exception : assumeUnique; 383 import std.format : FormatSpec; 384 385 char[] buf; 386 buf.reserve(100); 387 auto fmt = FormatSpec!char("%s"); 388 toString((const(char)[] s) { buf ~= s; }, fmt); 389 auto trustedUnique(T)(T t) @trusted { 390 return assumeUnique(t); 391 } 392 393 return trustedUnique(buf); 394 } 395 396 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 397 import std.algorithm : copy, map, joiner, filter; 398 import std.range : put; 399 400 put(w, "if ("); 401 if (init_.isValid) { 402 () @trusted { 403 init_.tokens.map!(a => a.spelling).joiner(" ").copy(w); 404 }(); 405 put(w, "; "); 406 } 407 () @trusted { cond.tokens.map!(a => a.spelling).joiner(" ").copy(w); }(); 408 put(w, ") "); 409 410 foreach (c; [then, else_].filter!(a => a.isValid)) { 411 () @trusted { 412 auto toks = c.tokens; 413 // only one case here and that is a `return foo;`. The trailing 414 // `;` is not part of the token range so an extra has to be 415 // appended at the end. 416 bool is_keyword = toks.length > 0 && toks[0].kind == CXTokenKind.keyword; 417 c.tokens.map!(a => a.spelling).joiner(" ").copy(w); 418 if (is_keyword) 419 put(w, "; "); 420 }(); 421 } 422 } 423 } 424 425 @safe struct CaseStmt { 426 import std.format : FormatSpec; 427 import clang.Cursor; 428 import clang.SourceLocation; 429 430 private DXCaseStmt dx; 431 432 this(DXCaseStmt dx) { 433 this.dx = dx; 434 } 435 436 bool isValid() const { 437 return dx.hasValue; 438 } 439 440 /// Cursor for the sub-stmt that reside inside the case. 441 Cursor subStmt() const { 442 return Cursor(dx.subStmt); 443 } 444 445 SourceLocation colonLocation() const { 446 return SourceLocation(dx.colonLoc); 447 } 448 449 SourceLocation beginLocation() const { 450 return SourceLocation(dx.beginLoc); 451 } 452 453 SourceLocation endLocation() const { 454 return SourceLocation(dx.endLoc); 455 } 456 457 string toString() @safe const { 458 import std.array : appender; 459 460 auto buf = appender!string; 461 toString(buf); 462 return buf.data; 463 } 464 465 void toString(Writer)(scope Writer w) const { 466 import std.format : formattedWrite; 467 import std.range.primitives : put; 468 469 put(w, "CaseStmt("); 470 formattedWrite(w, "colon:%s begin:%s end:%s", colonLocation, beginLocation, endLocation); 471 put(w, " subStmt:"); 472 put(w, subStmt.spelling); 473 put(w, ")"); 474 } 475 } 476 477 CaseStmt getCaseStmt(const CXCursor c) @trusted { 478 // This check is technically not needed because the C++ source code perform a dynamic cast. 479 // But extra safety can't hurt? 480 if (clang_getCursorKind(c) == CXCursorKind.caseStmt) { 481 return CaseStmt(dex_getCaseStmt(c)); 482 } 483 484 return CaseStmt(); 485 }