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 CXCursor condVar; 216 CXCursor condVarDeclStmt; 217 } 218 219 extern (C++) DXIfStmt dex_getIfStmt(const CXCursor cx); 220 221 extern (C++) struct DXCaseStmt { 222 bool hasValue; 223 CXSourceLocation colonLoc; 224 CXCursor subStmt; 225 CXSourceLocation beginLoc; 226 CXSourceLocation endLoc; 227 } 228 229 extern (C++) DXCaseStmt dex_getCaseStmt(const CXCursor cx); 230 231 /// Returns whether Loc is expanded from a macro in a system header. 232 extern (C++) bool dex_isInSystemMacro(const CXSourceLocation location); 233 234 /** Tests whether the given source location represents a macro argument's 235 * expansion into the function-like macro definition. 236 * 237 * Such source locations only appear inside of the expansion locations 238 * representing where a particular function-like macro was expanded. 239 */ 240 extern (C++) bool dex_isMacroArgExpansion(const CXSourceLocation location); 241 242 /** Tests whether the given source location represents the expansion of a macro body. 243 * 244 * This is equivalent to testing whether the location is part of a macro 245 * expansion but not the expansion of an argument to a function-like macro. 246 */ 247 extern (C++) bool dex_isMacroBodyExpansion(const CXSourceLocation location); 248 249 /// If the location is in any type of macro. 250 extern (C++) bool dex_isAnyMacro(const CXSourceLocation location); 251 252 /// Whether this is a (C++11) constexpr function or constexpr constructor. 253 extern (C++) bool dex_isPotentialConstExpr(const CXCursor cx); 254 } 255 256 Operator getExprOperator(scope const CXCursor expr) @trusted { 257 import std.algorithm : among; 258 259 // This check is technically not needed because the C++ source code try to 260 // do a dynamic cast. But by having a check here it is easier to review 261 // that THIS function is correctly implemented. 262 // This function is safe for all possible inputs. 263 // Note: CXXOperatorCallExpr is denoted callExpr in the C API. 264 if (clang_getCursorKind(expr).among(CXCursorKind.binaryOperator, 265 CXCursorKind.unaryOperator, CXCursorKind.callExpr)) { 266 return Operator(dex_getExprOperator(expr)); 267 } 268 269 return Operator(); 270 } 271 272 /** 273 * trusted: the C++ impl check that the node is an expression. 274 * It can handle any CursorKind. 275 */ 276 ValueKind exprValueKind(scope const CXCursor expr) @trusted { 277 return dex_getExprValueKind(expr); 278 } 279 280 /** 281 * trusted: the C++ impl check that the node is an expression. 282 * It can handle any CursorKind. 283 */ 284 auto getUnderlyingExprNode(scope const CXCursor expr) @trusted { 285 return dex_getUnderlyingExprNode(expr); 286 } 287 288 @safe struct OperatorSubExprs { 289 import clang.Cursor; 290 291 Cursor lhs, rhs; 292 } 293 294 @safe struct Operator { 295 import std.format : FormatSpec; 296 import clang.Cursor; 297 import clang.SourceLocation; 298 299 private DXOperator dx; 300 301 this(DXOperator v) { 302 dx = v; 303 } 304 305 bool isValid() const { 306 return dx.hasValue; 307 } 308 309 auto kind() const { 310 return dx.kind; 311 } 312 313 /// Cursor for the expression that the operator reside in. 314 Cursor cursor() const { 315 return Cursor(dx.cursor); 316 } 317 318 /** Retrieve the sub expressions of an operator expressions. 319 * 320 * rhs is the null cursor for unary operators. 321 * 322 * Returns: The sides of the expression. 323 * 324 * trusted: 325 * dex_getOperatorExprs is limited to only being able to handle operator 326 * expressions. 327 * getExprOperator only processes binary, unary and callExpr cursors. 328 * This lead to isValid only returning true when the cursor is of that type. 329 * Thus the limitation of dex_getOperatorExprs is fulfilled. 330 * 331 * TODO Further audit of the C++ implementation of dex_getOperatorExprs is 332 * needed. 333 */ 334 OperatorSubExprs sides() const @trusted { 335 OperatorSubExprs r; 336 337 if (isValid) { 338 auto sub_exprs = dex_getOperatorExprs(dx.cursor); 339 r = OperatorSubExprs(Cursor(sub_exprs.lhs), Cursor(sub_exprs.rhs)); 340 } 341 342 return r; 343 } 344 345 SourceLocation location() const { 346 return SourceLocation(dx.location); 347 } 348 349 /// The character length of the operator. 350 size_t length() const { 351 return dx.opLength; 352 } 353 354 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 355 import std.format : formatValue, formattedWrite; 356 import std.range.primitives : put; 357 358 put(w, "Operator("); 359 formatValue(w, kind, fmt); 360 put(w, " len:"); 361 formatValue(w, length, fmt); 362 put(w, " "); 363 formatValue(w, location, fmt); 364 put(w, ")"); 365 } 366 } 367 368 IfStmt getIfStmt(scope const CXCursor cx) @trusted { 369 if (clang_getCursorKind(cx) == CXCursorKind.ifStmt) 370 return IfStmt(cx, dex_getIfStmt(cx)); 371 372 return IfStmt(); 373 } 374 375 @safe struct IfStmt { 376 import std.format : FormatSpec; 377 import clang.Cursor; 378 379 private Cursor cx; 380 private DXIfStmt stmt; 381 382 this(const CXCursor parent_, DXIfStmt stmt) { 383 this.cx = Cursor(parent_); 384 this.stmt = stmt; 385 } 386 387 Cursor cursor() const { 388 return cx; 389 } 390 391 Cursor init_() const { 392 return Cursor(stmt.init_); 393 } 394 395 Cursor cond() const { 396 return Cursor(stmt.cond); 397 } 398 399 /** Retrieve the variable declared in this "if" statement, if any. 400 * 401 * Kind VarDecl. 402 * 403 * In the following example, "x" is the condition variable. 404 * ```c++ 405 * if (int x = foo()) { 406 * printf("x is %d", x); 407 * } 408 * ``` 409 */ 410 Cursor conditionVariable() const { 411 return Cursor(stmt.condVar); 412 } 413 414 /** If this IfStmt has a condition variable, return the faux DeclStmt 415 * associated with the creation of that condition variable. 416 */ 417 Cursor conditionVariableDeclStmt() const { 418 return Cursor(stmt.condVarDeclStmt); 419 } 420 421 Cursor then() const { 422 return Cursor(stmt.then); 423 } 424 425 Cursor else_() const { 426 return Cursor(stmt.else_); 427 } 428 429 string toString() const { 430 import std.exception : assumeUnique; 431 import std.format : FormatSpec; 432 433 char[] buf; 434 buf.reserve(100); 435 auto fmt = FormatSpec!char("%s"); 436 toString((const(char)[] s) { buf ~= s; }, fmt); 437 auto trustedUnique(T)(T t) @trusted { 438 return assumeUnique(t); 439 } 440 441 return trustedUnique(buf); 442 } 443 444 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 445 import std.algorithm : copy, map, joiner, filter; 446 import std.range : put; 447 448 put(w, "if ("); 449 if (init_.isValid) { 450 () @trusted { 451 init_.tokens.map!(a => a.spelling).joiner(" ").copy(w); 452 }(); 453 put(w, "; "); 454 } 455 () @trusted { cond.tokens.map!(a => a.spelling).joiner(" ").copy(w); }(); 456 put(w, ") "); 457 458 foreach (c; [then, else_].filter!(a => a.isValid)) { 459 () @trusted { 460 auto toks = c.tokens; 461 // only one case here and that is a `return foo;`. The trailing 462 // `;` is not part of the token range so an extra has to be 463 // appended at the end. 464 bool is_keyword = toks.length > 0 && toks[0].kind == CXTokenKind.keyword; 465 c.tokens.map!(a => a.spelling).joiner(" ").copy(w); 466 if (is_keyword) 467 put(w, "; "); 468 }(); 469 } 470 } 471 } 472 473 @safe struct CaseStmt { 474 import std.format : FormatSpec; 475 import clang.Cursor; 476 import clang.SourceLocation; 477 478 private DXCaseStmt dx; 479 480 this(DXCaseStmt dx) { 481 this.dx = dx; 482 } 483 484 bool isValid() const { 485 return dx.hasValue; 486 } 487 488 /// Cursor for the sub-stmt that reside inside the case. 489 Cursor subStmt() const { 490 return Cursor(dx.subStmt); 491 } 492 493 SourceLocation colonLocation() const { 494 return SourceLocation(dx.colonLoc); 495 } 496 497 SourceLocation beginLocation() const { 498 return SourceLocation(dx.beginLoc); 499 } 500 501 SourceLocation endLocation() const { 502 return SourceLocation(dx.endLoc); 503 } 504 505 string toString() @safe const { 506 import std.array : appender; 507 508 auto buf = appender!string; 509 toString(buf); 510 return buf.data; 511 } 512 513 void toString(Writer)(scope Writer w) const { 514 import std.format : formattedWrite; 515 import std.range.primitives : put; 516 517 put(w, "CaseStmt("); 518 formattedWrite(w, "colon:%s begin:%s end:%s", colonLocation, beginLocation, endLocation); 519 put(w, " subStmt:"); 520 put(w, subStmt.spelling); 521 put(w, ")"); 522 } 523 } 524 525 CaseStmt getCaseStmt(const CXCursor c) @trusted { 526 // This check is technically not needed because the C++ source code perform a dynamic cast. 527 // But extra safety can't hurt? 528 if (clang_getCursorKind(c) == CXCursorKind.caseStmt) { 529 return CaseStmt(dex_getCaseStmt(c)); 530 } 531 532 return CaseStmt(); 533 }