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