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() {
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         return kind == CXTypeKind.constantArray || kind == CXTypeKind.incompleteArray;
159     }
160 
161     @property bool isAnonymous() @safe {
162         return spelling.length == 0;
163     }
164 
165     /** Determine whether a CXType has the "volatile" qualifier set, without
166      * looking through aliases that may have added "volatile" at a different
167      * level.
168      */
169     @property bool isVolatile() {
170         return clang_isVolatileQualifiedType(cx) == 1;
171     }
172 
173     /** Determine whether a CXType has the "restrict" qualifier set, without
174      * looking through aliases that may have added "restrict" at a different
175      * level.
176      */
177     @property bool isRestrict() {
178         return clang_isRestrictQualifiedType(cx) == 1;
179     }
180 
181     /// Return: if the CXType is a POD (plain old data)
182     @property bool isPOD() {
183         return clang_isPODType(cx) == 1;
184     }
185 
186     @property bool isPointer() {
187         import std.algorithm : among;
188 
189         with (CXTypeKind) {
190             return kind.among(pointer, blockPointer, memberPointer,
191                     lValueReference, rValueReference) != 0;
192         }
193     }
194 
195 }
196 
197 struct FuncType {
198     Type type;
199     alias type this;
200 
201     @property Type resultType() {
202         auto r = clang_getResultType(type.cx);
203         return Type(type.cursor, r);
204     }
205 
206     @property Arguments arguments() {
207         return Arguments(this);
208     }
209 
210     @property bool isVariadic() {
211         return clang_isFunctionTypeVariadic(type.cx) == 1;
212     }
213 }
214 
215 struct ArrayType {
216     Type type;
217     alias type this;
218 
219     this(Type type)
220     in {
221         assert(type.isArray);
222     }
223     body {
224         this.type = type;
225     }
226 
227     /** Return the element type of an array, complex, or vector type.
228      *
229      * If a type is passed in that is not an array, complex, or vector type,
230      * an invalid type is returned.
231      */
232     @property Type elementType() {
233         auto r = clang_getElementType(cx);
234         return Type(type.cursor, r);
235     }
236 
237     /** Return: Number of dimensions the array consist of */
238     @property size_t numDimensions() {
239         size_t result = 1;
240         auto subtype = elementType();
241 
242         while (subtype.isArray) {
243             ++result;
244             subtype = subtype.array.elementType();
245         }
246 
247         return result;
248     }
249 
250     /** Return the number of elements of an array or vector type.
251      *
252      * If a type is passed in that is not an array or vector type,
253      * -1 is returned.
254      */
255     @property auto numElements() {
256         return clang_getNumElements(cx);
257     }
258 
259     /** Return the element type of an array type.
260      *
261      * If a non-array type is passed in, an invalid type is returned.
262      */
263     @property Type elementArrayType() {
264         auto r = clang_getArrayElementType(cx);
265         return Type(type.cursor, r);
266     }
267 
268     @property long size() {
269         return clang_getArraySize(cx);
270     }
271 }
272 
273 struct Arguments {
274     FuncType type;
275 
276     @property uint length() {
277         return clang_getNumArgTypes(type.type.cx);
278     }
279 
280     Type opIndex(uint i) {
281         auto r = clang_getArgType(type.type.cx, i);
282         return Type(type.cursor, r);
283     }
284 
285     int opApply(int delegate(ref Type) dg) {
286         foreach (i; 0 .. length) {
287             auto type = this[i];
288 
289             if (auto result = dg(type))
290                 return result;
291         }
292 
293         return 0;
294     }
295 }
296 
297 @property bool isUnsigned(CXTypeKind kind) {
298     switch (kind) with (CXTypeKind) {
299     case charU:
300         return true;
301     case uChar:
302         return true;
303     case uShort:
304         return true;
305     case uInt:
306         return true;
307     case uLong:
308         return true;
309     case uLongLong:
310         return true;
311     case uInt128:
312         return true;
313 
314     default:
315         return false;
316     }
317 }