GCC Code Coverage Report


src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
434 / 439
98.9%
Branches:
198 / 280, 58 excl
70.7%
Functions:
101 / 105
96.2%

symboltablebuilder/qual-type.spice
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 // Std imports
4 import "std/data/vector";
5 import "std/text/stringstream";
6 import "std/bindings/llvm/llvm" as llvm;
7
8 // Own imports
9 import "@/source-file";
10 import "@/ast/ast-nodes";
11 import "@/symboltablebuilder/super-type";
12 import "@/symboltablebuilder/type" as symboltable; // Aliased, because Type clashes with llvm::Type
13 import "@/symboltablebuilder/type-chain";
14 import "@/global/type-registry";
15 import "@/symboltablebuilder/type-qualifiers";
16 import "@/symboltablebuilder/scope";
17 import "@/symboltablebuilder/symbol-table-entry";
18 import "@/model/struct";
19 import "@/model/interface";
20 import "@/model/union";
21 import "@/model/generic-type";
22 import "@/typechecker/function-manager";
23 import "@/typechecker/interface-manager";
24 import "@/typechecker/struct-manager";
25 import "@/typechecker/union-manager";
26
27 // Constants
28 public const string STROBJ_NAME = "String";
29 public const string RESULTOBJ_NAME = "Result";
30 public const string ERROBJ_NAME = "Error";
31 public const string TIOBJ_NAME = "TypeInfo";
32 public const string IITERATOR_NAME = "IIterator";
33 public const string ARRAY_ITERATOR_NAME = "ArrayIterator";
34 public const unsigned long TYPE_ID_ITERATOR_INTERFACE = 255ul;
35 public const string ALIAS_CONTAINER_SUFFIX = ".container";
36 public const unsigned long TYPE_ID_ITERABLE_INTERFACE = 256ul;
37
38 /**
39 * Check if the given name is a reserved type name, which may only be used by the std
40 *
41 * @param typeName Type name to check
42 * @return Reserved or not
43 */
44 1405 public f<bool> isReservedTypeName(const String& typeName) {
45
5/8
✓ Branch 0 taken 1405 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1404 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1404 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1404 times.
✗ Branch 7 not taken.
2809 return typeName == STROBJ_NAME || typeName == RESULTOBJ_NAME || typeName == ERROBJ_NAME || typeName == TIOBJ_NAME
46
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1404 times.
1405 || typeName == IITERATOR_NAME || typeName == ARRAY_ITERATOR_NAME;
47 }
48
49 /**
50 * QualType pairs an interned, immutable type with a set of qualifiers. It is a small value type that is copied
51 * around freely; the rawType pointer is owned by the type registry.
52 */
53 public type QualType struct {
54 28929932 public const symboltable::Type* rawType = nil<const symboltable::Type*>
55 public TypeQualifiers qualifiers
56 }
57
58 public type QualTypeList alias Vector<QualType>;
59
60 // The context-free QualType(SuperType) ctors intern into the active type registry (see type-registry.spice). Without an
61 // active registry, rawType stays nil.
62 4148054 public p QualType.ctor(SuperType superType) {
63 4148054 TypeRegistry* registry = getActiveTypeRegistry();
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4148054 times.
4148054 if registry != nil<TypeRegistry*> {
65 4148054 this.rawType = registry.getOrInsert(superType);
66 4148054 }
67 4148054 this.qualifiers = getTypeQualifiersOf(superType);
68 4148054 }
69
70 6445 public p QualType.ctor(SuperType superType, const String& subType) {
71 6445 TypeRegistry* registry = getActiveTypeRegistry();
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6445 times.
6445 if registry != nil<TypeRegistry*> {
73 6445 this.rawType = registry.getOrInsertSub(superType, subType);
74 6445 }
75 6445 this.qualifiers = getTypeQualifiersOf(superType);
76 6445 }
77
78 274432 public p QualType.ctor(const symboltable::Type* rawType, TypeQualifiers qualifiers) {
79 274432 this.rawType = rawType;
80 274432 this.qualifiers = qualifiers;
81 274432 }
82
83 24501001 public p QualType.ctor(const QualType& other) {
84 24501001 this.rawType = other.rawType;
85 24501001 this.qualifiers = other.qualifiers;
86 24501001 }
87
88 3552895 public p operator=(QualType& this, const QualType& other) {
89 3552895 this.rawType = other.rawType;
90 3552895 this.qualifiers = other.qualifiers;
91 3552895 }
92
93 /**
94 * Get the underlying raw type
95 *
96 * @return Underlying raw type
97 */
98 568097 public f<const symboltable::Type*> QualType.getType() {
99 568097 return this.rawType;
100 }
101
102 /**
103 * Get the super type of the underlying type
104 *
105 * @return Super type
106 */
107 3695291 public f<SuperType> QualType.getSuperType() {
108 3695291 return this.rawType.getSuperType();
109 }
110
111 /**
112 * Get the subtype of the underlying type
113 *
114 * @return Subtype
115 */
116 1290372 public f<const String&> QualType.getSubType() {
117 1290372 return this.rawType.getSubType();
118 }
119
120 /**
121 * Get the array size of the underlying type
122 *
123 * @return Array size
124 */
125 5815 public f<unsigned int> QualType.getArraySize() {
126 5815 return this.rawType.getArraySize();
127 }
128
129 /**
130 * Get the body scope of the underlying type
131 *
132 * @return Body scope
133 */
134 564807 public f<Scope*> QualType.getBodyScope() {
135 564807 return this.rawType.getBodyScope();
136 }
137
138 /**
139 * Get the function return type of the underlying type
140 *
141 * @return Function return type
142 */
143 142 public f<QualType> QualType.getFunctionReturnType() {
144 142 return this.rawType.getFunctionReturnType();
145 }
146
147 /**
148 * Get the function parameter types of the underlying type
149 *
150 * @return Function parameter types
151 */
152 570 public f<QualTypeList> QualType.getFunctionParamTypes() {
153 570 return this.rawType.getFunctionParamTypes();
154 }
155
156 /**
157 * Get the function parameter and return types of the underlying type
158 *
159 * @return Function parameter and return types
160 */
161 598 public f<QualTypeList> QualType.getFunctionParamAndReturnTypes() {
162 598 return this.rawType.getFunctionParamAndReturnTypes();
163 }
164
165 /**
166 * Check if the underlying type has lambda captures
167 *
168 * @return Has lambda captures or not
169 */
170 533 public f<bool> QualType.hasLambdaCaptures() {
171 533 return this.rawType.hasLambdaCaptures();
172 }
173
174 /**
175 * Get the template types of the underlying type
176 *
177 * @return Template types
178 */
179 738872 public f<QualTypeList> QualType.getTemplateTypes() {
180 738872 return this.rawType.getTemplateTypes();
181 }
182
183 /**
184 * Get the struct instance for a struct type
185 *
186 * @param node Accessing AST node
187 * @param templateTypes Custom set of template types
188 * @return Struct instance
189 */
190 317933 public f<Struct*> QualType.getStruct(const ASTNode* node, const QualTypeList &templateTypes) {
191 317933 assert this.is(SuperType::TY_STRUCT);
192 317933 Scope* bodyScope = this.getBodyScope();
193 317933 Scope* structDefScope = bodyScope.parent;
194 317933 const String& structName = this.getSubType();
195 317933 return matchStruct(structDefScope, structName, templateTypes, node);
196 }
197
198 /**
199 * Get the struct instance for a struct type
200 *
201 * @param node Accessing AST node
202 * @return Struct instance
203 */
204 287190 public f<Struct*> QualType.getStruct(const ASTNode* node) {
205 574380 return this.getStruct(node, this.getTemplateTypes());
206 287190 }
207
208 /**
209 * Get the struct instance for a struct type
210 * Adopt information from the struct to this type.
211 *
212 * @param node Accessing AST node
213 * @param templateTypes Custom set of template types
214 * @return Struct instance
215 */
216 1735 public f<Struct*> QualType.getStructAndAdjustType(const ASTNode* node, const QualTypeList& templateTypes) {
217 1735 Struct* spiceStruct = this.getStruct(node, templateTypes);
218
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1734 times.
1735 if spiceStruct != nil<Struct*> {
219 1734 const symboltable::Type* typeWithBodyScope = this.rawType.getWithBodyScope(spiceStruct.scope);
220 1734 this.rawType = typeWithBodyScope.getWithTemplateTypes(spiceStruct.structBase.getTemplateTypes());
221 1734 }
222 1735 return spiceStruct;
223 }
224
225 /**
226 * Get the interface instance for an interface type
227 *
228 * @param node Accessing AST node
229 * @param templateTypes Custom set of template types
230 * @return Interface instance
231 */
232 5475 public f<Interface*> QualType.getInterface(const ASTNode* node, const QualTypeList& templateTypes) {
233 5475 assert this.is(SuperType::TY_INTERFACE);
234 5475 Scope* bodyScope = this.getBodyScope();
235 5475 Scope* interfaceDefScope = bodyScope.parent;
236 5475 const String structName = this.getSubType();
237 10950 return matchInterface(interfaceDefScope, structName, templateTypes, node);
238 5475 }
239
240 /**
241 * Get the interface instance for an interface type
242 *
243 * @param node Accessing AST node
244 * @return Interface instance
245 */
246 3250 public f<Interface*> QualType.getInterface(const ASTNode* node) {
247 6500 return this.getInterface(node, this.getTemplateTypes());
248 3250 }
249
250 /**
251 * Get the union instance for a union type
252 *
253 * @param node Accessing AST node
254 * @param templateTypes Custom set of template types
255 * @return Union instance
256 */
257 31 public f<Union*> QualType.getUnion(const ASTNode* node, const QualTypeList& templateTypes) {
258 31 assert this.is(SuperType::TY_UNION);
259 31 Scope* bodyScope = this.getBodyScope();
260 31 Scope* unionDefScope = bodyScope.parent;
261 31 const String& unionName = this.getSubType();
262 31 return matchUnion(unionDefScope, unionName, templateTypes, node);
263 }
264
265 /**
266 * Get the union instance for a union type
267 *
268 * @param node Accessing AST node
269 * @return Union instance
270 */
271 31 public f<Union*> QualType.getUnion(const ASTNode* node) {
272 62 return this.getUnion(node, this.getTemplateTypes());
273 31 }
274
275 /**
276 * Check if the underlying type is of a certain super type
277 *
278 * @param superType Super type
279 * @return Is of super type or not
280 */
281 16450115 public f<bool> QualType.is(SuperType superType) {
282 16450115 return this.rawType.is(superType);
283 }
284
285 /**
286 * Check if the underlying type is one of a list of super types
287 *
288 * @param superTypes List of super types
289 * @return Is one of the super types or not
290 */
291 2326940 public f<bool> QualType.isOneOf(SuperType[] superTypes, unsigned long superTypesSize) {
292 2326940 return this.rawType.isOneOf(superTypes, superTypesSize);
293 }
294
295 /**
296 * Check if the base type of the underlying type is a certain super type
297 *
298 * @param superType Super type
299 * @return Is base type or not
300 */
301 773077 public f<bool> QualType.isBase(SuperType superType) {
302 773077 return this.rawType.isBase(superType);
303 }
304
305 /**
306 * Check if the underlying type is a primitive type
307 * Note: enum types are mapped to int, so they are also count as primitive types.
308 *
309 * @return Primitive or not
310 */
311 154379 public f<bool> QualType.isPrimitive() {
312 154379 return this.rawType.isPrimitive();
313 }
314
315 /**
316 * Check if the underlying type is an extended primitive type
317 * The definition of extended primitive types contains all primitive types plus the following:
318 * - structs
319 * - interfaces
320 * - functions/procedures
321 *
322 * @return Extended primitive or not
323 */
324 494659 public f<bool> QualType.isExtendedPrimitive() {
325 494659 return this.rawType.isExtendedPrimitive();
326 }
327
328 /**
329 * Check if the underlying type is a pointer
330 *
331 * @return Pointer or not
332 */
333 2032580 public f<bool> QualType.isPtr() {
334 2032580 return this.rawType.isPtr();
335 }
336
337 /**
338 * Check if the underlying type is a pointer to a certain super type
339 *
340 * @param superType Super type
341 * @return Pointer to super type or not
342 */
343 690099 public f<bool> QualType.isPtrTo(SuperType superType) {
344
2/2
✓ Branch 0 taken 613453 times.
✓ Branch 1 taken 76646 times.
690099 if !this.isPtr() { return false; }
345 76646 const QualType contained = this.getContained();
346 76646 return contained.is(superType);
347 }
348
349 /**
350 * Check if the underlying type is a reference
351 *
352 * @return Reference or not
353 */
354 3132291 public f<bool> QualType.isRef() {
355 3132291 return this.rawType.isRef();
356 }
357
358 /**
359 * Check if the underlying type is an array
360 *
361 * @return Array or not
362 */
363 690960 public f<bool> QualType.isArray() {
364 690960 return this.rawType.isArray();
365 }
366
367 /**
368 * Check if the underlying type is an array of a certain super type
369 *
370 * @param superType Super type
371 * @return Array of super type or not
372 */
373 1 public f<bool> QualType.isArrayOf(SuperType superType) {
374
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if !this.isArray() { return false; }
375 ✗ const QualType contained = this.getContained();
376 ✗ return contained.is(superType);
377 }
378
379 /**
380 * Check if the underlying type is a const reference
381 *
382 * @return Const reference or not
383 */
384 63296 public f<bool> QualType.isConstRef() {
385
2/2
✓ Branch 0 taken 3602 times.
✓ Branch 1 taken 59694 times.
63296 return this.qualifiers.isConst && this.rawType.isRef();
386 }
387
388 /**
389 * Check if the type is an array with a known size, which decays to a pointer, when it is passed to a function
390 *
391 * @return Decayed array or not
392 */
393 321600 public f<bool> QualType.isDecayedArray() {
394
2/2
✓ Branch 0 taken 320697 times.
✓ Branch 1 taken 903 times.
321600 return this.isArray() && cast<unsigned long>(this.getArraySize()) != ARRAY_SIZE_UNKNOWN;
395 }
396
397 /**
398 * Check if the current type is an iterator
399 *
400 * @param node ASTNode
401 * @return Iterator or not
402 */
403 445 public f<bool> QualType.isIterator(const ASTNode* node) {
404 // The type must be a struct that implements the iterator interface
405
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 444 times.
445 if !this.is(SuperType::TY_STRUCT) { return false; }
406
407 444 return this.doesImplement(getIteratorInterfaceType(TYPE_ID_ITERATOR_INTERFACE), node);
408 }
409
410 /**
411 * Check if the current type is an iterable
412 * - Arrays are always considered iterable
413 * - Otherwise the type must be a struct that implements the iterator interface
414 *
415 * @param node ASTNode
416 * @return Iterable or not
417 */
418 447 public f<bool> QualType.isIterable(const ASTNode* node) {
419 // Arrays are always considered iterable
420
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 439 times.
447 if this.isArray() { return true; }
421 // Otherwise the type must be a struct that implements the iterator interface
422
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 438 times.
439 if !this.is(SuperType::TY_STRUCT) { return false; }
423
424 438 return this.doesImplement(getIteratorInterfaceType(TYPE_ID_ITERABLE_INTERFACE), node);
425 }
426
427 /**
428 * Build the interface type IIterator<T> with the given type id. Interface types are compared by their type id only,
429 * so this is used for the IIterable interface as well (with the type id of IIterable).
430 *
431 * @param typeId Type id of the interface
432 * @return Interface type
433 */
434 882 f<QualType> getIteratorInterfaceType(unsigned long typeId) {
435 882 TypeRegistry* registry = getActiveTypeRegistry();
436 882 assert registry != nil<TypeRegistry*>;
437 882 const QualType genericType = QualType(SuperType::TY_GENERIC, String("T"));
438 882 const TypeChainElementData data; // No body scope
439 882 QualTypeList templateTypes;
440 882 templateTypes.pushBack(genericType);
441 882 const symboltable::Type* itType = registry.getOrInsert(SuperType::TY_INTERFACE, String(IITERATOR_NAME), typeId, data, templateTypes);
442 1764 return QualType(itType, getTypeQualifiersOf(SuperType::TY_INTERFACE));
443 882 }
444
445 /**
446 * Check if the current type is a string object
447 *
448 * @return String object or not
449 */
450 2164 public f<bool> QualType.isStringObj() {
451
2/2
✓ Branch 0 taken 1948 times.
✓ Branch 1 taken 216 times.
2164 if !this.is(SuperType::TY_STRUCT) { return false; }
452
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if this.getSubType() != STROBJ_NAME { return false; }
453 216 const Scope* bodyScope = this.getBodyScope();
454 216 const SourceFile* sourceFile = bodyScope.getSourceFile();
455 216 return sourceFile.isStdFile;
456 }
457
458 /**
459 * Check if the current type is an error object
460 *
461 * @return Error object or not
462 */
463 3033 public f<bool> QualType.isErrorObj() {
464
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3032 times.
3033 if !this.is(SuperType::TY_STRUCT) { return false; }
465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3032 times.
3032 if this.getSubType() != ERROBJ_NAME { return false; }
466 3032 const Scope* bodyScope = this.getBodyScope();
467 3032 const SourceFile* sourceFile = bodyScope.getSourceFile();
468 3032 return sourceFile.isStdFile;
469 }
470
471 /**
472 * Check if the current type is a result object
473 *
474 * @return Result object or not
475 */
476 193 public f<bool> QualType.isResultObj() {
477
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 190 times.
193 if !this.is(SuperType::TY_STRUCT) { return false; }
478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if this.getSubType() != RESULTOBJ_NAME { return false; }
479 190 const Scope* bodyScope = this.getBodyScope();
480 190 const SourceFile* sourceFile = bodyScope.getSourceFile();
481 190 return sourceFile.isStdFile;
482 }
483
484 /**
485 * Check if the current type has any generic parts
486 *
487 * @return Generic parts or not
488 */
489 1469036 public f<bool> QualType.hasAnyGenericParts() {
490 1469036 return this.rawType.hasAnyGenericParts();
491 }
492
493 /**
494 * Check if constructing an instance of the current type would require calling a ctor.
495 * If this function return true, the type does not need to be constructed.
496 *
497 * @param node Accessing ASTNode
498 * @return Trivially constructible or not
499 */
500 1750 public f<bool> QualType.isTriviallyConstructible(const ASTNode* node) {
501 // References can't be default initialized
502
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1746 times.
1750 if this.isRef() { return false; }
503
504 // In case of an array, the item type is determining the construction triviality
505
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1744 times.
1746 if this.isArray() {
506 2 const QualType baseType = this.getBase();
507 2 return baseType.isTriviallyConstructible(node);
508 }
509
510 // In case of a struct, the member types determine the construction triviality
511
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 1466 times.
1744 if !this.is(SuperType::TY_STRUCT) { return true; }
512
513 // If the struct has a ctor, it is a non-trivially constructible one
514 1466 const Struct* spiceStruct = this.getStruct(node);
515 1466 assert spiceStruct != nil<const Struct*>; // Callers must ensure the struct is manifested (see structFullyManifested)
516
2/2
✓ Branch 0 taken 1295 times.
✓ Branch 1 taken 171 times.
1466 if hasAnyNonCopyCtor(spiceStruct.scope) { return false; }
517
518 // If the struct emits a vtable, it is non-trivially constructible, because the vtable needs to be initialized in the ctor
519 171 const ASTStructDefNode* structDefNode = downcast<ASTStructDefNode>(spiceStruct.declNode);
520
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 170 times.
171 if structDefNode.emitVTable { return false; }
521
522 // If any field has a default value, the struct is non-trivially constructible
523
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 164 times.
435 foreach IVisitable* field : structDefNode.fields {
524 271 const ASTFieldNode* fieldNode = downcast<ASTFieldNode>(field);
525
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 265 times.
271 if fieldNode.defaultValue != nil<IVisitable*> { return false; }
526 265 }
527
528 // Check if all member types are trivially constructible
529
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 155 times.
418 foreach const QualType& fieldType : spiceStruct.fieldTypes {
530
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 254 times.
263 if !fieldType.isTriviallyConstructible(node) { return false; }
531 254 }
532 155 return true;
533 }
534
535 /**
536 * Check if copying an instance of the current type would require a call to the copy ctor.
537 * If this function return true, the type can be copied by calling memcpy.
538 *
539 * @param node Accessing ASTNode
540 * @return Trivially copyable or not
541 */
542 139881 public f<bool> QualType.isTriviallyCopyable(const ASTNode* node) {
543 // In case of an array, the item type is determining the copy triviality
544
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 139680 times.
139881 if this.isArray() {
545 201 const QualType baseType = this.getBase();
546 201 return baseType.isTriviallyCopyable(node);
547 }
548
549 // In case of a struct, the member types determine the copy triviality
550 // Only structs can own a copy ctor
551
2/2
✓ Branch 0 taken 91816 times.
✓ Branch 1 taken 47864 times.
139680 if !this.is(SuperType::TY_STRUCT) { return true; }
552
553 // If the struct has a copy ctor, it is a non-trivially copyable one
554 47864 const Struct* spiceStruct = this.getStruct(node);
555 47864 assert spiceStruct != nil<const Struct*>;
556
2/2
✓ Branch 0 taken 22759 times.
✓ Branch 1 taken 25105 times.
47864 if hasCopyCtor(spiceStruct.scope) { return false; }
557
558 // Check if all member types are trivially copyable
559
2/2
✓ Branch 0 taken 46277 times.
✓ Branch 1 taken 25105 times.
71382 foreach const QualType& fieldType : spiceStruct.fieldTypes {
560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46277 times.
46277 if !fieldType.isTriviallyCopyable(node) { return false; }
561 46277 }
562 25105 return true;
563 }
564
565 /**
566 * Check if a by-value parameter of the current type owns its argument. In this case, the caller passes a copy, that it does
567 * not destruct, and the called function destructs the parameter when it goes out of scope. Arguments of trivially copyable
568 * types are passed as bitwise copies and stay owned by the caller, so that handle types without copy ctor can be passed by
569 * value without the called function disposing the handle.
570 *
571 * @param node Accessing ASTNode
572 * @return Owned by the callee or not
573 */
574 164461 public f<bool> QualType.isOwnedByValueParam(const ASTNode* node) {
575
2/2
✓ Branch 0 taken 163123 times.
✓ Branch 1 taken 1338 times.
164461 return this.is(SuperType::TY_STRUCT) && !this.isTriviallyCopyable(node);
576 }
577
578 /**
579 * Check if destructing an instance of the current type would require calling a dtor.
580 * If this function return true, the type does not need to be destructed.
581 *
582 * @param node Accessing ASTNode
583 * @return Trivially destructible or not
584 */
585 95097 public f<bool> QualType.isTriviallyDestructible(const ASTNode* node) {
586 // In case of an array, the item type is determining the destructing triviality
587
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 94985 times.
95097 if this.isArray() {
588 112 const QualType baseType = this.getBase();
589 112 return baseType.isTriviallyDestructible(node);
590 }
591
592 // Only structs can own a dtor
593
2/2
✓ Branch 0 taken 53614 times.
✓ Branch 1 taken 41371 times.
94985 if !this.is(SuperType::TY_STRUCT) { return true; }
594
595 // If the struct has a dtor, it is a non-trivially destructible one
596 41371 const Struct* spiceStruct = this.getStruct(node);
597 41371 assert spiceStruct != nil<const Struct*>;
598
2/2
✓ Branch 0 taken 9547 times.
✓ Branch 1 taken 31824 times.
41371 if hasDtor(spiceStruct.scope) { return false; }
599
600 // Check if all member types are trivially destructible
601
2/2
✓ Branch 0 taken 63801 times.
✓ Branch 1 taken 31824 times.
95625 foreach const QualType& fieldType : spiceStruct.fieldTypes {
602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63801 times.
63801 if !fieldType.isTriviallyDestructible(node) { return false; }
603 63801 }
604 31824 return true;
605 }
606
607 /**
608 * Check if the current type implements the given interface type
609 *
610 * @param implementedInterfaceType Interface type
611 * @param node Accessing ASTNode
612 * @return Struct implements interface or not
613 */
614 885 public f<bool> QualType.doesImplement(const QualType& implementedInterfaceType, const ASTNode* node) {
615 885 assert this.is(SuperType::TY_STRUCT) && implementedInterfaceType.is(SuperType::TY_INTERFACE);
616 885 const Struct* spiceStruct = this.getStruct(node);
617 885 assert spiceStruct != nil<Struct*>;
618
2/2
✓ Branch 0 taken 885 times.
✓ Branch 1 taken 41 times.
926 foreach const QualType& interfaceType : spiceStruct.interfaceTypes {
619 885 assert interfaceType.is(SuperType::TY_INTERFACE);
620
2/2
✓ Branch 0 taken 844 times.
✓ Branch 1 taken 41 times.
885 if implementedInterfaceType.matches(interfaceType, false, false, true) { return true; }
621 41 }
622 41 return false;
623 }
624
625 /**
626 * Check if a certain input type can be bound (assigned) to the current type.
627 *
628 * @param inputType Qualified type, which should be bound to the current type
629 * @param isTemporary Is the input type a temporary type
630 * @return Can be bound or not
631 */
632 62138 public f<bool> QualType.canBind(const QualType& inputType, bool isTemporary) {
633
6/6
✓ Branch 0 taken 18561 times.
✓ Branch 1 taken 43577 times.
✓ Branch 2 taken 17958 times.
✓ Branch 3 taken 603 times.
✓ Branch 4 taken 16315 times.
✓ Branch 5 taken 1643 times.
62138 return !isTemporary || inputType.rawType.isRef() || !this.rawType.isRef() || this.isConstRef();
634 }
635
636 /**
637 * Check for the matching compatibility of two types.
638 * Useful for struct and function matching as well as assignment type validation and function arg matching.
639 *
640 * @param otherType Type to compare against
641 * @param ignoreArraySize Ignore array sizes
642 * @param ignoreQualifiers Ignore qualifiers, except for pointer and reference types
643 * @param allowConstify Match when the types are the same, but the lhs type is more const restrictive than the rhs type
644 * @return Matching or not
645 */
646 499273 public f<bool> QualType.matches(const QualType& otherType, bool ignoreArraySize, bool ignoreQualifiers, bool allowConstify) {
647 // Special case: string is equivalent to const char*
648
5/6
✓ Branch 0 taken 52777 times.
✓ Branch 1 taken 446496 times.
✓ Branch 2 taken 49897 times.
✓ Branch 3 taken 2880 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 499273 times.
499273 if this.is(SuperType::TY_STRING) && otherType.isPtrTo(SuperType::TY_CHAR) && otherType.isConst() { return true; }
649
4/6
✓ Branch 0 taken 26454 times.
✓ Branch 1 taken 472819 times.
✓ Branch 2 taken 26454 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 499273 times.
499273 if this.isPtrTo(SuperType::TY_CHAR) && this.isConst() && otherType.is(SuperType::TY_STRING) { return true; }
650
651 // Compare type
652
2/2
✓ Branch 0 taken 169115 times.
✓ Branch 1 taken 330158 times.
499273 if !this.rawType.matches(otherType.rawType, ignoreArraySize) {
653 169115 return false;
654 }
655
656 // Ignore or compare qualifiers
657
2/2
✓ Branch 0 taken 274467 times.
✓ Branch 1 taken 55691 times.
330158 return ignoreQualifiers || this.qualifiers.match(otherType.qualifiers, allowConstify);
658 }
659
660 /**
661 * Check for the matching compatibility of two types in terms of interface implementation.
662 * Useful for function matching as well as assignment type validation and function arg matching.
663 *
664 * @param structType Type to compare against
665 * @return Matching or not
666 */
667 177314 public f<bool> QualType.matchesInterfaceImplementedByStruct(const QualType& structType) {
668
4/4
✓ Branch 0 taken 176378 times.
✓ Branch 1 taken 936 times.
✓ Branch 2 taken 176482 times.
✓ Branch 3 taken 832 times.
177314 if !this.is(SuperType::TY_INTERFACE) || !structType.is(SuperType::TY_STRUCT) { return false; }
669 // Check if the rhs is a struct type that implements the lhs interface type
670 832 const Struct* spiceStruct = structType.getStruct(nil<const ASTNode*>);
671 832 assert spiceStruct != nil<Struct*>;
672
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 7 times.
832 foreach const QualType& interfaceType : spiceStruct.interfaceTypes {
673
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 if this.matches(interfaceType, false, false, true) { return true; }
674 ✗ }
675 7 return false;
676 }
677
678 /**
679 * Check if the current (struct) type is a base of the given struct type, embedded via the 'compose'
680 * qualifier. Only first-field compositions are considered, because only those sit at offset 0 and can
681 * therefore be reached without adjusting the pointer value. The check follows the chain of first-field
682 * compositions transitively, so a base that is composed several levels deep is still matched.
683 */
684 4273 public f<bool> QualType.matchesComposedBaseOfStruct(const QualType& structType) {
685
4/4
✓ Branch 0 taken 3190 times.
✓ Branch 1 taken 1083 times.
✓ Branch 2 taken 4255 times.
✓ Branch 3 taken 18 times.
4273 if !this.is(SuperType::TY_STRUCT) || !structType.is(SuperType::TY_STRUCT) { return false; }
686
687 18 const Struct* spiceStruct = structType.getStruct(nil<const ASTNode*>);
688
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
18 if spiceStruct == nil<Struct*> || spiceStruct.fieldTypes.isEmpty() { return false; }
689
690 // Only the first field can be a composed base that is reachable along the first-field chain
691 18 const QualType& firstFieldType = spiceStruct.fieldTypes.front();
692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if !firstFieldType.isComposition() { return false; }
693 // The composed field matches the requested base directly (qualifiers like 'compose' are ignored)
694
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 if this.matches(firstFieldType, false, true, true) { return true; }
695 // Otherwise follow the composition chain further down
696 6 return this.matchesComposedBaseOfStruct(firstFieldType);
697 }
698
699 /**
700 * Check if the current type is the same container type as another type.
701 * Container types include arrays, pointers, and references.
702 *
703 * @param other Other type
704 * @return Same container type or not
705 */
706 12175 public f<bool> QualType.isSameContainerTypeAs(const QualType& other) {
707 12175 return this.rawType.isSameContainerTypeAs(other.rawType);
708 }
709
710 /**
711 * Check if the current type is a self-referencing struct type
712 *
713 * @param typeToCompareWith Type to compare with (nil on the first iteration)
714 * @return Self-referencing struct type or not
715 */
716 116133 public f<bool> QualType.isSelfReferencingStructType(const QualType* typeToCompareWith) {
717
2/2
✓ Branch 0 taken 85941 times.
✓ Branch 1 taken 30192 times.
116133 if !this.is(SuperType::TY_STRUCT) { return false; }
718
719 // If no type was set by a previous iteration, we set it to the current type
720
2/2
✓ Branch 0 taken 9268 times.
✓ Branch 1 taken 20924 times.
30192 if typeToCompareWith == nil<const QualType*> {
721 20924 typeToCompareWith = this;
722 20924 }
723
724 30192 Scope* baseTypeBodyScope = this.getBodyScope();
725
2/2
✓ Branch 0 taken 94752 times.
✓ Branch 1 taken 29115 times.
123867 for unsigned long i = 0l; i < baseTypeBodyScope.getFieldCount(); i++ {
726 94752 const SymbolTableEntry* field = baseTypeBodyScope.lookupField(cast<unsigned int>(i));
727 94752 const QualType& fieldType = field.getQualType();
728 // Check if the base type of the field matches with the current type, which is also a base type
729 // If yes, this is a self-referencing struct type
730 94752 const QualType fieldBaseType = fieldType.getBase();
731
2/2
✓ Branch 0 taken 1077 times.
✓ Branch 1 taken 93675 times.
94752 if fieldBaseType == *typeToCompareWith { return true; }
732
733 // If the field is a struct, check if it is a self-referencing struct type
734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93675 times.
93675 if fieldType.isSelfReferencingStructType(typeToCompareWith) { return true; }
735 93675 }
736 29115 return false;
737 }
738
739 /**
740 * Check if the given generic type list has a substantiation for the current (generic) type
741 *
742 * @param genericTypeList Generic type list
743 * @return Has substantiation or not
744 */
745 99725 public f<bool> QualType.isCoveredByGenericTypeList(Vector<GenericType>& genericTypeList) {
746 99725 const QualType baseType = this.getBase();
747 // Check if the symbol type itself is generic
748
2/2
✓ Branch 0 taken 18189 times.
✓ Branch 1 taken 81536 times.
99725 if baseType.is(SuperType::TY_GENERIC) {
749
2/2
✓ Branch 0 taken 21346 times.
✓ Branch 1 taken 10 times.
21356 foreach GenericType& genericType : genericTypeList {
750
2/2
✓ Branch 0 taken 18179 times.
✓ Branch 1 taken 3167 times.
21346 if baseType.matches(genericType.qualType, true, true, true) {
751 18179 genericType.used = true;
752 18179 return true;
753 }
754 3167 }
755 10 return false;
756 }
757
758 // If the type is non-generic check template types
759 81536 bool covered = true;
760 // Check template types
761 81536 const QualTypeList baseTemplateTypes = baseType.getTemplateTypes();
762
2/2
✓ Branch 0 taken 81535 times.
✓ Branch 1 taken 8384 times.
89919 foreach const QualType& templateType : baseTemplateTypes {
763
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 8383 times.
8384 if !templateType.isCoveredByGenericTypeList(genericTypeList) {
764 1 covered = false;
765 1 break;
766 }
767 8383 }
768
769 // If function/procedure, check param and return types
770 81536 const dyn functionTypes = [SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE];
771
2/2
✓ Branch 0 taken 81054 times.
✓ Branch 1 taken 482 times.
81536 if baseType.isOneOf(functionTypes, len(functionTypes)) {
772 482 const QualTypeList paramAndReturnTypes = baseType.getFunctionParamAndReturnTypes();
773
2/2
✓ Branch 0 taken 482 times.
✓ Branch 1 taken 903 times.
1385 foreach const QualType& paramType : paramAndReturnTypes {
774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 903 times.
903 if !paramType.isCoveredByGenericTypeList(genericTypeList) {
775 ✗ covered = false;
776 ✗ break;
777 }
778 903 }
779 482 }
780
781 163072 return covered;
782 81536 }
783
784 /**
785 * Check if the current type needs de-allocation
786 *
787 * @return Needs de-allocation or not
788 */
789 12727 public f<bool> QualType.needsDeAllocation() {
790
2/2
✓ Branch 0 taken 12001 times.
✓ Branch 1 taken 726 times.
12727 if !this.isHeap() { return false; }
791 // We only need de-allocation, if we directly point to a heap-allocated type
792 // e.g. for heap TestStruct** we don't need to de-allocate, since it is a non-owning pointer to an owning pointer
793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 726 times.
726 return this.isPtr() && !this.isPtrTo(SuperType::TY_PTR);
794 }
795
796 /**
797 * Get the name of the symbol type as a string
798 *
799 * @param name Name stream
800 * @param withSize Include the array size for sized types
801 * @param ignorePublic Ignore any potential public qualifier
802 * @param withAliases Print aliases as is and not decompose them
803 */
804 1466400 public p QualType.getName(StringStream& name, bool withSize = false, bool ignorePublic = false, bool withAliases = true) {
805 // Append the qualifiers
806 1466400 const QualType baseType = this.getBase();
807 1466400 const SuperType baseSuperType = baseType.getSuperType();
808 1466400 const TypeQualifiers defaultForSuperType = getTypeQualifiersOf(baseSuperType);
809
12/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 258653 times.
✓ Branch 13 taken 219561 times.
✓ Branch 14 taken 216135 times.
✓ Branch 15 taken 42518 times.
✓ Branch 16 taken 435696 times.
✓ Branch 17 taken 42518 times.
✓ Branch 18 taken 376123 times.
✓ Branch 19 taken 612063 times.
✓ Branch 20 taken 196183 times.
✓ Branch 21 taken 179940 times.
✓ Branch 22 taken 808246 times.
✓ Branch 23 taken 179940 times.
1466400 if !ignorePublic && this.qualifiers.isPublic && !defaultForSuperType.isPublic {
810 222458 name << "public ";
811 222458 }
812
6/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 478214 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 478214 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 988171 times.
✓ Branch 13 taken 15 times.
✓ Branch 14 taken 988171 times.
✓ Branch 15 taken 15 times.
1466400 if this.qualifiers.isComposition && !defaultForSuperType.isComposition {
813 15 name << "compose ";
814 15 }
815
11/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 53833 times.
✓ Branch 13 taken 424381 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 53833 times.
✓ Branch 16 taken 430113 times.
✓ Branch 17 taken 48101 times.
✓ Branch 18 taken 129934 times.
✓ Branch 19 taken 858252 times.
✓ Branch 20 taken 3075 times.
✓ Branch 21 taken 126859 times.
✓ Branch 22 taken 902217 times.
✓ Branch 23 taken 85969 times.
1466400 if this.qualifiers.isConst && !defaultForSuperType.isConst && this.rawType.getTypeChainDepth() > 1 {
816 134070 name << "const ";
817 134070 }
818
8/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 452103 times.
✓ Branch 9 taken 26111 times.
✓ Branch 10 taken 452103 times.
✓ Branch 11 taken 26111 times.
✓ Branch 12 taken 942665 times.
✓ Branch 13 taken 45521 times.
✓ Branch 14 taken 942665 times.
✓ Branch 15 taken 45521 times.
1466400 if this.qualifiers.isHeap && !defaultForSuperType.isHeap {
819 71632 name << "heap ";
820 71632 }
821
7/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 407139 times.
✓ Branch 9 taken 71075 times.
✓ Branch 10 taken 478214 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 871572 times.
✓ Branch 13 taken 116614 times.
✓ Branch 14 taken 988185 times.
✓ Branch 15 taken 1 time.
1466400 if this.qualifiers.isSigned && !defaultForSuperType.isSigned {
822 1 name << "signed ";
823 1 }
824
8/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 71075 times.
✓ Branch 9 taken 407139 times.
✓ Branch 10 taken 434299 times.
✓ Branch 11 taken 43915 times.
✓ Branch 12 taken 116614 times.
✓ Branch 13 taken 871572 times.
✓ Branch 14 taken 876689 times.
✓ Branch 15 taken 111497 times.
1466400 if !this.qualifiers.isSigned && defaultForSuperType.isSigned {
825 155412 name << "unsigned ";
826 155412 }
827
828 // Loop through all chain elements
829 1466400 this.rawType.getName(name, withSize, ignorePublic, withAliases);
830 1466400 }
831
832 /**
833 * Get the name of the symbol type as a string
834 *
835 * @param withSize Include the array size for sized types
836 * @param ignorePublic Ignore any potential public qualifier
837 * @param withAliases Print aliases as is and not decompose them
838 * @return Symbol type name
839 */
840 376169 public f<String> QualType.getName(bool withSize = false, bool ignorePublic = false, bool withAliases = true) {
841 376169 StringStream name;
842 376169 this.getName(name, withSize, ignorePublic, withAliases);
843 752338 return name.str();
844 376169 }
845
846 /**
847 * Convert the type to an LLVM type
848 *
849 * @param sourceFile Source file
850 * @return LLVM type
851 */
852 1678998 public f<llvm::Type> QualType.toLLVMType(SourceFile* sourceFile) {
853 1678998 return sourceFile.getLLVMType(this.rawType);
854 }
855
856 /**
857 * Convert the type to the LLVM type to use for a parameter of this type in a function signature
858 *
859 * @param sourceFile Source file
860 * @return LLVM type
861 */
862 73804 public f<llvm::Type> QualType.getParamLLVMType(SourceFile* sourceFile) {
863 // Take the context from the source file, so that we always end up in the same context as toLLVMType()
864 73804 const llvm::Type llvmType = this.toLLVMType(sourceFile);
865
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 73780 times.
73804 return this.isDecayedArray() ? llvm::getPtrTy(sourceFile.getLLVMContext()) : llvmType;
866 }
867
868 /**
869 * Retrieve the pointer type to this type
870 *
871 * @param node ASTNode
872 * @return New type
873 */
874 117140 public f<QualType> QualType.toPtr(const ASTNode* node) {
875 117140 QualType newType = *this;
876 117140 newType.rawType = this.rawType.toPtr(node);
877 117140 return newType;
878 }
879
880 /**
881 * Retrieve the reference type to this type
882 *
883 * @param node ASTNode
884 * @return New type
885 */
886 56652 public f<QualType> QualType.toRef(const ASTNode* node) {
887 56652 QualType newType = *this;
888 56652 newType.rawType = this.rawType.toRef(node);
889 56652 return newType;
890 }
891
892 /**
893 * Retrieve the const reference type of this type
894 *
895 * @param node ASTNode
896 * @return New type
897 */
898 17897 public f<QualType> QualType.toConstRef(const ASTNode* node) {
899 17897 QualType newType = this.toRef(node);
900 17897 newType.makeConst();
901 17897 return newType;
902 }
903
904 /**
905 * Retrieve the array type of this type
906 *
907 * @param node ASTNode
908 * @param size Array size
909 * @param skipDynCheck Skip dynamic check
910 * @return New type
911 */
912 1032 public f<QualType> QualType.toArr(const ASTNode* node, unsigned int size, bool skipDynCheck = false) {
913 1032 QualType newType = *this;
914 1032 newType.rawType = this.rawType.toArr(node, size, skipDynCheck);
915 1032 return newType;
916 }
917
918 /**
919 * Retrieve the non-const type of this type
920 *
921 * @return New type
922 */
923 31522 public f<QualType> QualType.toNonConst() {
924 31522 QualType newType = *this;
925 31522 newType.qualifiers.isConst = false;
926 31522 return newType;
927 }
928
929 /**
930 * Retrieve the contained type of this type
931 * This works on pointers, arrays, references and strings (which alias with char*)
932 *
933 * @return New type
934 */
935 486557 public f<QualType> QualType.getContained() {
936 486557 const dyn options = [SuperType::TY_PTR, SuperType::TY_REF, SuperType::TY_ARRAY, SuperType::TY_STRING];
937 486557 assert this.isOneOf(options, len(options));
938 486557 QualType newType = *this;
939 486557 newType.rawType = this.rawType.getContained();
940 486557 return newType;
941 }
942
943 /**
944 * Retrieve the base type of this type
945 *
946 * @return New type
947 */
948 2832962 public f<QualType> QualType.getBase() {
949 2832962 QualType newType = *this;
950 2832962 newType.rawType = this.rawType.getBase();
951 2832962 return newType;
952 }
953
954 /**
955 * Get the type, that is aliased by this alias type
956 *
957 * @param aliasEntry Symbol table entry of the alias
958 * @return Aliased type
959 */
960 3862 public f<QualType> QualType.getAliased(const SymbolTableEntry* aliasEntry) {
961 3862 assert this.is(SuperType::TY_ALIAS);
962 // Get type of aliased type container entry
963 3862 const String aliasedContainerEntryName = aliasEntry.name + ALIAS_CONTAINER_SUFFIX;
964 3862 const SymbolTableEntry* aliasedTypeContainerEntry = aliasEntry.scope.lookupStrict(aliasedContainerEntryName);
965 3862 assert aliasedTypeContainerEntry != nil<SymbolTableEntry*>;
966 7724 return aliasedTypeContainerEntry.getQualType();
967 3862 }
968
969 /**
970 * Remove reference of this type, if it is a reference
971 *
972 * @return New type
973 */
974 1305439 public f<QualType> QualType.removeReferenceWrapper() {
975
2/2
✓ Branch 0 taken 73001 times.
✓ Branch 1 taken 1232438 times.
1305439 return this.isRef() ? this.getContained() : *this;
976 }
977
978 /**
979 * Auto-dereference the given symbol type (peeling off all ptr/ref wrappers).
980 * This process is NOT equivalent with getBase() because getBase() also removes e.g. array wrappers
981 *
982 * @return New type
983 */
984 112666 public f<QualType> QualType.autoDereference() {
985 112666 QualType newType = *this;
986
4/4
✓ Branch 0 taken 79715 times.
✓ Branch 1 taken 131796 times.
✓ Branch 2 taken 98845 times.
✓ Branch 3 taken 112666 times.
211511 while newType.isPtr() || newType.isRef() {
987 98845 newType = newType.getContained();
988 98845 }
989 112666 return newType;
990 }
991
992 /**
993 * Replace the base type with another one
994 *
995 * @param newBaseType New base type
996 * @return The new type
997 */
998 70541 public f<QualType> QualType.replaceBaseType(const QualType& newBaseType) {
999 // Create new type
1000 70541 const symboltable::Type* newType = this.rawType.replaceBase(newBaseType.rawType);
1001 // Create new qualifiers
1002 70541 const TypeQualifiers newQualifiers = this.qualifiers.merge(newBaseType.qualifiers);
1003 // Return the new qualified type
1004 70541 return QualType(newType, newQualifiers);
1005 }
1006
1007 /**
1008 * Retrieve the same type, but with lambda captures enabled
1009 *
1010 * @return Same type with lambda captures
1011 */
1012 223 public f<QualType> QualType.getWithLambdaCaptures(bool enabled = true) {
1013 // Create new type
1014 223 const symboltable::Type* newType = this.rawType.getWithLambdaCaptures(enabled);
1015 // Return the new qualified type
1016 223 return QualType(newType, this.qualifiers);
1017 }
1018
1019 /**
1020 * Retrieve the same type, but with a new body scope
1021 *
1022 * @return Same type with body scope
1023 */
1024 104682 public f<QualType> QualType.getWithBodyScope(Scope* bodyScope) {
1025 // Create new type
1026 104682 const symboltable::Type* newType = this.rawType.getWithBodyScope(bodyScope);
1027 // Return the new qualified type
1028 104682 return QualType(newType, this.qualifiers);
1029 }
1030
1031 /**
1032 * Retrieve the same type, but with new template types
1033 *
1034 * @param templateTypes New template types
1035 * @return Same type with new template types
1036 */
1037 17726 public f<QualType> QualType.getWithTemplateTypes(const QualTypeList& templateTypes) {
1038 // Create new type
1039 17726 const symboltable::Type* newType = this.rawType.getWithTemplateTypes(templateTypes);
1040 // Return the new qualified type
1041 17726 return QualType(newType, this.qualifiers);
1042 }
1043
1044 /**
1045 * Retrieve the same type, but with new base template types
1046 *
1047 * @param templateTypes New base template types
1048 * @return Same type with new base template types
1049 */
1050 22458 public f<QualType> QualType.getWithBaseTemplateTypes(const QualTypeList& templateTypes) {
1051 // Create new type
1052 22458 const symboltable::Type* newType = this.rawType.getWithBaseTemplateTypes(templateTypes);
1053 // Return the new qualified type
1054 22458 return QualType(newType, this.qualifiers);
1055 }
1056
1057 /**
1058 * Retrieve the same type, but with new function parameter and return types
1059 *
1060 * @param paramAndReturnTypes New parameter types
1061 * @return Same type with new parameter types
1062 */
1063 53723 public f<QualType> QualType.getWithFunctionParamAndReturnTypes(const QualTypeList& paramAndReturnTypes) {
1064 // Create new type
1065 53723 const symboltable::Type* newType = this.rawType.getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
1066 // Return the new qualified type
1067 53723 return QualType(newType, this.qualifiers);
1068 }
1069
1070 /**
1071 * Retrieve the same type, but with new function parameter and return types
1072 *
1073 * @param returnType New return type
1074 * @param paramTypes New parameter types
1075 * @return Same type with new parameter types
1076 */
1077 53651 public f<QualType> QualType.getWithFunctionParamAndReturnTypes(const QualType& returnType, const QualTypeList& paramTypes) {
1078 53651 QualTypeList paramAndReturnTypes = paramTypes;
1079 53651 paramAndReturnTypes.insertAt(0ul, returnType);
1080 107302 return this.getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
1081 53651 }
1082
1083 /**
1084 * Check if the current type is const
1085 *
1086 * Examples for const types:
1087 * - const int
1088 * - const TestStruct
1089 * - const string
1090 *
1091 * Examples for non-const types:
1092 * - double (reason: not marked const)
1093 * - const int* (reason: pointer to const int is not const itself)
1094 * - const TestStruct& (reason: reference to const TestStruct is not const itself)
1095 *
1096 * @return Is const or not
1097 */
1098 250436 public f<bool> QualType.isConst() {
1099
2/2
✓ Branch 0 taken 43485 times.
✓ Branch 1 taken 206951 times.
250436 return this.isExtendedPrimitive() && this.qualifiers.isConst;
1100 }
1101
1102 /**
1103 * Check if the current type is marked signed
1104 *
1105 * @return Is signed or not
1106 */
1107 104750 public f<bool> QualType.isSigned() {
1108 104750 const dyn options = [SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BYTE, SuperType::TY_CHAR, SuperType::TY_BOOL];
1109 104750 assert this.isOneOf(options, len(options));
1110 104750 return this.qualifiers.isSigned;
1111 }
1112
1113 /**
1114 * Check if the current type is marked unsigned
1115 *
1116 * @return Is unsigned or not
1117 */
1118 45922 public f<bool> QualType.isUnsigned() {
1119 45922 const dyn options = [SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BYTE, SuperType::TY_CHAR, SuperType::TY_BOOL];
1120 45922 assert this.isOneOf(options, len(options));
1121 45922 return this.qualifiers.isUnsigned;
1122 }
1123
1124 /**
1125 * Check if the current type is marked inline
1126 *
1127 * @return Is inline or not
1128 */
1129 43130 public f<bool> QualType.isInline() {
1130 43130 const dyn options = [SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE];
1131 43130 assert this.isOneOf(options, len(options));
1132 43130 return this.qualifiers.isInline;
1133 }
1134
1135 /**
1136 * Check if the current type is marked public
1137 *
1138 * @return Is public or not
1139 */
1140 148350 public f<bool> QualType.isPublic() {
1141 148350 const dyn options = [SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE, SuperType::TY_ENUM, SuperType::TY_STRUCT, SuperType::TY_INTERFACE, SuperType::TY_UNION];
1142 148350 assert this.isPrimitive() || this.isPtr() /* Global variables */ || this.isOneOf(options, len(options));
1143 148350 return this.qualifiers.isPublic;
1144 }
1145
1146 /**
1147 * Check if the current type is marked heap
1148 *
1149 * @return Is heap or not
1150 */
1151 71722 public f<bool> QualType.isHeap() {
1152 71722 return this.qualifiers.isHeap;
1153 }
1154
1155 /**
1156 * Check if the current type is marked as composition
1157 *
1158 * @return Is composition or not
1159 */
1160 118 public f<bool> QualType.isComposition() {
1161 118 return this.qualifiers.isComposition;
1162 }
1163
1164 /**
1165 * Make the current type const
1166 *
1167 * @param isConst Is const or not
1168 */
1169 63235 public p QualType.makeConst(bool isConst = true) {
1170 63235 this.qualifiers.isConst = isConst;
1171 63235 }
1172
1173 /**
1174 * Make the current type unsigned
1175 *
1176 * @param isUnsigned Is unsigned or not
1177 */
1178 30243 public p QualType.makeUnsigned(bool isUnsigned = true) {
1179 30243 const dyn options = [SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BYTE, SuperType::TY_CHAR, SuperType::TY_BOOL];
1180 30243 assert this.isOneOf(options, len(options));
1181 30243 this.qualifiers.isSigned = !isUnsigned;
1182 30243 this.qualifiers.isUnsigned = isUnsigned;
1183 30243 }
1184
1185 /**
1186 * Make the current type public
1187 *
1188 * @param isPublic Is public or not
1189 */
1190 1752 public p QualType.makePublic(bool isPublic = true) {
1191 1752 const dyn options = [SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE, SuperType::TY_ENUM, SuperType::TY_STRUCT, SuperType::TY_INTERFACE, SuperType::TY_UNION];
1192 1752 assert this.isPrimitive() || this.isPtr() /* Global variables */ || this.isOneOf(options, len(options));
1193 1752 this.qualifiers.isPublic = isPublic;
1194 1752 }
1195
1196 /**
1197 * Make the current type heap
1198 *
1199 * @param isHeap Is heap or not
1200 */
1201 1554 public p QualType.makeHeap(bool isHeap = true) {
1202 1554 this.qualifiers.isHeap = isHeap;
1203 1554 }
1204
1205 /**
1206 * Get the qualifiers of the current type
1207 *
1208 * @return Qualifiers
1209 */
1210 208081 public f<TypeQualifiers&> QualType.getQualifiers() {
1211 208081 return this.qualifiers;
1212 }
1213
1214 /**
1215 * Set the qualifiers of the current type
1216 *
1217 * @param newQualifiers New qualifiers
1218 */
1219 128635 public p QualType.setQualifiers(TypeQualifiers newQualifiers) {
1220 128635 this.qualifiers = newQualifiers;
1221 128635 }
1222
1223 /**
1224 * Check if two types are equal
1225 *
1226 * @param lhs Left-hand side type
1227 * @param rhs Right-hand side type
1228 * @return Equal or not
1229 */
1230 951760 public f<bool> operator==(const QualType& lhs, const QualType& rhs) {
1231 // Only compare the types, not the qualifiers
1232 951760 return lhs.rawType == rhs.rawType;
1233 }
1234
1235 /**
1236 * Check if two types are not equal
1237 *
1238 * @param lhs Left-hand side type
1239 * @param rhs Right-hand side type
1240 * @return Not equal or not
1241 */
1242 838823 public f<bool> operator!=(const QualType& lhs, const QualType& rhs) {
1243 838823 return !(lhs == rhs);
1244 }
1245
1246 /**
1247 * Remove pointers / arrays / references if both types have them as far as possible.
1248 *
1249 * @param typeA Candidate type
1250 * @param typeB Requested type
1251 */
1252 7445 public p unwrapBoth(QualType& typeA, QualType& typeB) {
1253 // Unwrap the raw types via locals, the fields cannot be bound to the 'const Type*&' params directly
1254 7445 const symboltable::Type* rawTypeA = typeA.rawType;
1255 7445 const symboltable::Type* rawTypeB = typeB.rawType;
1256 7445 symboltable::unwrapBothTypes(rawTypeA, rawTypeB);
1257 7445 typeA.rawType = rawTypeA;
1258 7445 typeB.rawType = rawTypeB;
1259 7445 }
1260
1261 /**
1262 * Remove pointers / arrays / references if both types have them as far as possible.
1263 * Furthermore, remove reference wrappers if possible.
1264 *
1265 * @param typeA Candidate type
1266 * @param typeB Requested type
1267 */
1268 253544 public p unwrapBothWithRefWrappers(QualType& typeA, QualType& typeB) {
1269 // Unwrap the raw types via locals, the fields cannot be bound to the 'const Type*&' params directly
1270 253544 const symboltable::Type* rawTypeA = typeA.rawType;
1271 253544 const symboltable::Type* rawTypeB = typeB.rawType;
1272 253544 symboltable::unwrapBothWithReferenceWrappers(rawTypeA, rawTypeB);
1273 253544 typeA.rawType = rawTypeA;
1274 253544 typeB.rawType = rawTypeB;
1275 253544 }
1276