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 } 224 225 extern (C++) DXCaseStmt dex_getCaseStmt(const CXCursor cx); 226 } 227 228 Operator getExprOperator(const CXCursor expr) @trusted { 229 import std.algorithm : among; 230 231 // This check is technically not needed because the C++ source code try to do a dynamic cast. 232 // But by having a check here it is easier to review that THIS function is correctly implemented. 233 // This function is safe for all possible inputs. 234 // Note: CXXOperatorCallExpr is denoted callExpr in the C API. 235 if (clang_getCursorKind(expr).among(CXCursorKind.binaryOperator, 236 CXCursorKind.unaryOperator, CXCursorKind.callExpr)) { 237 return Operator(dex_getExprOperator(expr)); 238 } 239 240 return Operator(); 241 } 242 243 /** 244 * trusted: the C++ impl check that the node is an expression. 245 * It can handle any CursorKind. 246 */ 247 ValueKind exprValueKind(const CXCursor expr) @trusted { 248 return dex_getExprValueKind(expr); 249 } 250 251 /** 252 * trusted: the C++ impl check that the node is an expression. 253 * It can handle any CursorKind. 254 */ 255 auto getUnderlyingExprNode(const CXCursor expr) @trusted { 256 return dex_getUnderlyingExprNode(expr); 257 } 258 259 @safe struct OperatorSubExprs { 260 import clang.Cursor; 261 262 Cursor lhs, rhs; 263 } 264 265 @safe struct Operator { 266 import std.format : FormatSpec; 267 import clang.Cursor; 268 import clang.SourceLocation; 269 270 private DXOperator dx; 271 272 this(DXOperator v) { 273 dx = v; 274 } 275 276 bool isValid() const { 277 return dx.hasValue; 278 } 279 280 auto kind() const { 281 return dx.kind; 282 } 283 284 /// Cursor for the expression that the operator reside in. 285 Cursor cursor() const { 286 return Cursor(dx.cursor); 287 } 288 289 /** Retrieve the sub expressions of an operator expressions. 290 * 291 * rhs is the null cursor for unary operators. 292 * 293 * Returns: The sides of the expression. 294 * 295 * trusted: 296 * dex_getOperatorExprs is limited to only being able to handle operator 297 * expressions. 298 * getExprOperator only processes binary, unary and callExpr cursors. 299 * This lead to isValid only returning true when the cursor is of that type. 300 * Thus the limitation of dex_getOperatorExprs is fulfilled. 301 * 302 * TODO Further audit of the C++ implementation of dex_getOperatorExprs is 303 * needed. 304 */ 305 OperatorSubExprs sides() const @trusted { 306 OperatorSubExprs r; 307 308 if (isValid) { 309 auto sub_exprs = dex_getOperatorExprs(dx.cursor); 310 r = OperatorSubExprs(Cursor(sub_exprs.lhs), Cursor(sub_exprs.rhs)); 311 } 312 313 return r; 314 } 315 316 SourceLocation location() const { 317 return SourceLocation(dx.location); 318 } 319 320 /// The character length of the operator. 321 size_t length() const { 322 return dx.opLength; 323 } 324 325 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 326 import std.format : formatValue, formattedWrite; 327 import std.range.primitives : put; 328 329 put(w, "Operator("); 330 formatValue(w, kind, fmt); 331 put(w, " len:"); 332 formatValue(w, length, fmt); 333 put(w, " "); 334 formatValue(w, location, fmt); 335 put(w, ")"); 336 } 337 } 338 339 IfStmt getIfStmt(const CXCursor cx) @trusted { 340 if (clang_getCursorKind(cx) == CXCursorKind.ifStmt) 341 return IfStmt(cx, dex_getIfStmt(cx)); 342 343 return IfStmt(); 344 } 345 346 @safe struct IfStmt { 347 import std.format : FormatSpec; 348 import clang.Cursor; 349 350 private Cursor cx; 351 private DXIfStmt stmt; 352 353 this(const CXCursor parent_, DXIfStmt stmt) { 354 this.cx = Cursor(parent_); 355 this.stmt = stmt; 356 } 357 358 Cursor cursor() const { 359 return cx; 360 } 361 362 Cursor init_() const { 363 return Cursor(stmt.init_); 364 } 365 366 Cursor cond() const { 367 return Cursor(stmt.cond); 368 } 369 370 Cursor then() const { 371 return Cursor(stmt.then); 372 } 373 374 Cursor else_() const { 375 return Cursor(stmt.else_); 376 } 377 378 string toString() const { 379 import std.exception : assumeUnique; 380 import std.format : FormatSpec; 381 382 char[] buf; 383 buf.reserve(100); 384 auto fmt = FormatSpec!char("%s"); 385 toString((const(char)[] s) { buf ~= s; }, fmt); 386 auto trustedUnique(T)(T t) @trusted { 387 return assumeUnique(t); 388 } 389 390 return trustedUnique(buf); 391 } 392 393 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 394 import std.algorithm : copy, map, joiner, filter; 395 import std.range : put; 396 397 put(w, "if ("); 398 if (init_.isValid) { 399 () @trusted{ init_.tokens.map!(a => a.spelling).joiner(" ").copy(w); }(); 400 put(w, "; "); 401 } 402 () @trusted{ cond.tokens.map!(a => a.spelling).joiner(" ").copy(w); }(); 403 put(w, ") "); 404 405 foreach (c; [then, else_].filter!(a => a.isValid)) { 406 () @trusted{ 407 auto toks = c.tokens; 408 // only one case here and that is a `return foo;`. The trailing 409 // `;` is not part of the token range so an extra has to be 410 // appended at the end. 411 bool is_keyword = toks.length > 0 && toks[0].kind == CXTokenKind.keyword; 412 c.tokens.map!(a => a.spelling).joiner(" ").copy(w); 413 if (is_keyword) 414 put(w, "; "); 415 }(); 416 } 417 } 418 } 419 420 @safe struct CaseStmt { 421 import std.format : FormatSpec; 422 import clang.Cursor; 423 import clang.SourceLocation; 424 425 private DXCaseStmt dx; 426 427 this(DXCaseStmt dx) { 428 this.dx = dx; 429 } 430 431 bool isValid() const { 432 return dx.hasValue; 433 } 434 435 /// Cursor for the sub-stmt that reside inside the case. 436 Cursor subStmt() const { 437 return Cursor(dx.subStmt); 438 } 439 440 SourceLocation colonLocation() const { 441 return SourceLocation(dx.colonLoc); 442 } 443 444 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 445 import std.format : formatValue; 446 import std.range.primitives : put; 447 448 put(w, "CaseStmt(colon:"); 449 put(w, subStmt.spelling); 450 put(w, " colon:"); 451 formatValue(w, location, fmt); 452 put(w, ")"); 453 } 454 } 455 456 CaseStmt getCaseStmt(const CXCursor c) @trusted { 457 // This check is technically not needed because the C++ source code perform a dynamic cast. 458 // But extra safety can't hurt? 459 if (clang_getCursorKind(c) == CXCursorKind.caseStmt) { 460 return CaseStmt(dex_getCaseStmt(c)); 461 } 462 463 return CaseStmt(); 464 }