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 }