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 }