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