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 }