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