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 }