1 /**
2  * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg, Joakim Brännström (joakim.brannstrom dottli gmx.com)
4  * Version: 1.1
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  * History:
7  *  1.0 initial release. 2012-01-29 $(BR)
8  *    Jacob Carlborg
9  *
10  *  1.1 additional features missing compared to cindex.py. 2015-03-07 $(BR)
11  *    Joakim Brännström
12  */
13 module clang.Type;
14 
15 import clang.c.Index;
16 
17 import clang.Cursor;
18 import clang.Util;
19 
20 struct Type {
21     mixin CX;
22 
23     Cursor cursor;
24 
25     this(Type type) {
26         cursor = type.cursor;
27         cx = type.cx;
28     }
29 
30     this(Cursor c, CXType cx) {
31         cursor = c;
32         this.cx = cx;
33     }
34 
35     /** Pretty-print the underlying type using the rules of the language of the
36      * translation unit from which it came.
37      *
38      * If the type is invalid, an empty string is returned.
39      */
40     @property string spelling() @trusted {
41         auto r = toD(clang_getTypeSpelling(cx));
42         return r;
43     }
44 
45     @property string typeKindSpelling() @trusted {
46         auto r = toD(clang_getTypeKindSpelling(cx.kind));
47         return r;
48     }
49 
50     /** Return the canonical type for a CXType.
51      *
52      * Clang's type system explicitly models aliases and all the ways a
53      * specific type can be represented.  The canonical type is the underlying
54      * type with all the "sugar" removed.  For example, if 'T' is a typedef for
55      * 'int', the canonical type for 'T' would be 'int'.
56      */
57     @property Type canonicalType() @trusted {
58         auto r = clang_getCanonicalType(cx);
59         return Type(cursor, r);
60     }
61 
62     /// For pointer types, returns the type of the pointee.
63     @property Type pointeeType() @trusted {
64         auto r = clang_getPointeeType(cx);
65         //TODO investigate if it is buggy behaviour to reuse THIS cursor.
66         // Shouldn't it be the pointee types cursor
67         return Type(cursor, r);
68     }
69 
70     /** Retrieve the type named by the qualified-id.
71      *
72      * If a non-elaborated type is passed in, an invalid type is returned.
73      */
74     @property Type elaboratedType() @trusted {
75         auto r = clang_Type_getNamedType(cx);
76         return Type(cursor, r);
77     }
78 
79     /// Return: the cursor for the declaration of the given type.
80     @property Cursor declaration() @trusted {
81         auto r = clang_getTypeDeclaration(cx);
82         return Cursor(r);
83     }
84 
85     @property FuncType func() {
86         return FuncType(this);
87     }
88 
89     @property ArrayType array() {
90         return ArrayType(this);
91     }
92 
93     /** Determine whether two CXTypes represent the same type.
94      *
95      * Returns:non-zero if the CXTypes represent the same type and zero otherwise.
96      */
97     equals_t opEquals(const ref Type type_) const {
98         return clang_equalTypes(cast(CXType) type_.cx, cast(CXType) cx) != 0;
99     }
100 
101     @property bool isTypedef() const @safe {
102         return kind == CXTypeKind.typedef_;
103     }
104 
105     @property bool isEnum() const @safe {
106         return kind == CXTypeKind.enum_;
107     }
108 
109     @property bool isValid() const @safe {
110         return kind != CXTypeKind.invalid;
111     }
112 
113     @property bool isFunctionType() @safe {
114         return canonicalType.kind == CXTypeKind.functionProto;
115     }
116 
117     @property bool isFunctionPointerType() @safe {
118         return kind == CXTypeKind.pointer && pointeeType.isFunctionType;
119     }
120 
121     @property bool isObjCIdType() @safe {
122         return isTypedef && canonicalType.kind == CXTypeKind.objCObjectPointer && spelling == "id";
123     }
124 
125     @property bool isObjCClassType() @safe {
126         return isTypedef && canonicalType.kind == CXTypeKind.objCObjectPointer && spelling == "Class";
127     }
128 
129     @property bool isObjCSelType() @safe {
130         if (isTypedef) {
131             auto c = canonicalType;
132             return c.kind == CXTypeKind.pointer && c.pointeeType.kind == CXTypeKind.objCSel;
133         } else
134             return false;
135     }
136 
137     @property bool isObjCBuiltinType() @safe {
138         return isObjCIdType || isObjCClassType || isObjCSelType;
139     }
140 
141     @property bool isWideCharType() const @safe {
142         return kind == CXTypeKind.wChar;
143     }
144 
145     /** Determine whether a CXType has the "const" qualifier set, without
146      * looking through aliases that may have added "const" at a different
147      * level.
148      */
149     @property bool isConst() @trusted {
150         return clang_isConstQualifiedType(cx) == 1;
151     }
152 
153     @property bool isExposed() const @safe {
154         return kind != CXTypeKind.unexposed;
155     }
156 
157     @property bool isArray() const @safe {
158         import std.algorithm : among;
159 
160         return kind.among(CXTypeKind.constantArray, CXTypeKind.incompleteArray) != 0;
161     }
162 
163     @property bool isAnonymous() @safe {
164         return spelling.length == 0;
165     }
166 
167     /** Determine whether a CXType has the "volatile" qualifier set, without
168      * looking through aliases that may have added "volatile" at a different
169      * level.
170      */
171     @property bool isVolatile() {
172         return clang_isVolatileQualifiedType(cx) == 1;
173     }
174 
175     /** Determine whether a CXType has the "restrict" qualifier set, without
176      * looking through aliases that may have added "restrict" at a different
177      * level.
178      */
179     @property bool isRestrict() {
180         return clang_isRestrictQualifiedType(cx) == 1;
181     }
182 
183     /// Return: if CXType is a POD (plain old data)
184     @property bool isPOD() {
185         return clang_isPODType(cx) == 1;
186     }
187 
188     @property bool isPointer() {
189         import std.algorithm : among;
190 
191         with (CXTypeKind) {
192             return kind.among(pointer, blockPointer, memberPointer,
193                     lValueReference, rValueReference) != 0;
194         }
195     }
196 
197     /// Return: if CXType is a signed type.
198     bool isSigned() const @trusted {
199         import std.algorithm : among;
200 
201         return kind.among(CXTypeKind.charU, CXTypeKind.char16, CXTypeKind.char32,
202                 CXTypeKind.charS, CXTypeKind.sChar, CXTypeKind.wChar, CXTypeKind.short_,
203                 CXTypeKind.int_, CXTypeKind.long_, CXTypeKind.longLong, CXTypeKind.int128) != 0;
204     }
205 }
206 
207 struct FuncType {
208     Type type;
209     alias type this;
210 
211     @property Type resultType() {
212         auto r = clang_getResultType(type.cx);
213         return Type(type.cursor, r);
214     }
215 
216     @property Arguments arguments() {
217         return Arguments(this);
218     }
219 
220     @property bool isVariadic() {
221         return clang_isFunctionTypeVariadic(type.cx) == 1;
222     }
223 }
224 
225 struct ArrayType {
226     Type type;
227     alias type this;
228 
229     this(Type type)
230     in {
231         assert(type.isArray);
232     }
233     do {
234         this.type = type;
235     }
236 
237     /** Return the element type of an array, complex, or vector type.
238      *
239      * If a type is passed in that is not an array, complex, or vector type,
240      * an invalid type is returned.
241      */
242     @property Type elementType() {
243         auto r = clang_getElementType(cx);
244         return Type(type.cursor, r);
245     }
246 
247     /** Return: Number of dimensions the array consist of */
248     @property size_t numDimensions() {
249         size_t result = 1;
250         auto subtype = elementType();
251 
252         while (subtype.isArray) {
253             ++result;
254             subtype = subtype.array.elementType();
255         }
256 
257         return result;
258     }
259 
260     /** Return the number of elements of an array or vector type.
261      *
262      * If a type is passed in that is not an array or vector type,
263      * -1 is returned.
264      */
265     @property auto numElements() {
266         return clang_getNumElements(cx);
267     }
268 
269     /** Return the element type of an array type.
270      *
271      * If a non-array type is passed in, an invalid type is returned.
272      */
273     @property Type elementArrayType() {
274         auto r = clang_getArrayElementType(cx);
275         return Type(type.cursor, r);
276     }
277 
278     @property long size() {
279         return clang_getArraySize(cx);
280     }
281 }
282 
283 struct Arguments {
284     FuncType type;
285 
286     @property uint length() {
287         return clang_getNumArgTypes(type.type.cx);
288     }
289 
290     Type opIndex(uint i) {
291         auto r = clang_getArgType(type.type.cx, i);
292         return Type(type.cursor, r);
293     }
294 
295     int opApply(int delegate(ref Type) dg) {
296         foreach (i; 0 .. length) {
297             auto type = this[i];
298 
299             if (auto result = dg(type))
300                 return result;
301         }
302 
303         return 0;
304     }
305 }
306 
307 @property bool isUnsigned(CXTypeKind kind) {
308     switch (kind) with (CXTypeKind) {
309     case charU:
310         return true;
311     case uChar:
312         return true;
313     case uShort:
314         return true;
315     case uInt:
316         return true;
317     case uLong:
318         return true;
319     case uLongLong:
320         return true;
321     case uInt128:
322         return true;
323 
324     default:
325         return false;
326     }
327 }