GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 95.9% 307 / 0 / 320
Functions: 95.9% 94 / 0 / 98
Branches: 63.1% 284 / 0 / 450

src/symboltablebuilder/QualType.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "QualType.h"
4
5 #include <sstream>
6
7 #include <SourceFile.h>
8 #include <ast/ASTNodes.h>
9 #include <global/TypeRegistry.h>
10 #include <model/GenericType.h>
11 #include <model/Struct.h>
12 #include <model/Union.h>
13 #include <symboltablebuilder/Scope.h>
14 #include <symboltablebuilder/SymbolTableBuilder.h>
15 #include <symboltablebuilder/Type.h>
16 #include <typechecker/FunctionManager.h>
17 #include <typechecker/InterfaceManager.h>
18 #include <typechecker/StructManager.h>
19 #include <typechecker/UnionManager.h>
20
21 namespace spice::compiler {
22
23 10230810 QualType::QualType(SuperType superType) : type(TypeRegistry::getOrInsert(superType)), qualifiers(TypeQualifiers::of(superType)) {}
24 12691 QualType::QualType(SuperType superType, const std::string &subType)
25 12691 : type(TypeRegistry::getOrInsert(superType, subType)), qualifiers(TypeQualifiers::of(superType)) {}
26 608385 QualType::QualType(const Type *type, TypeQualifiers qualifiers) : type(type), qualifiers(qualifiers) {}
27
28 /**
29 * Get the super type of the underlying type
30 *
31 * @return Super type
32 */
33 9069391 SuperType QualType::getSuperType() const { return type->getSuperType(); }
34
35 /**
36 * Get the subtype of the underlying type
37 *
38 * @return Subtype
39 */
40 2344763 const std::string &QualType::getSubType() const { return type->getSubType(); }
41
42 /**
43 * Get the array size of the underlying type
44 *
45 * @return Array size
46 */
47 8982 unsigned int QualType::getArraySize() const { return type->getArraySize(); }
48
49 /**
50 * Get the body scope of the underlying type
51 *
52 * @return Body scope
53 */
54 8721366 Scope *QualType::getBodyScope() const { return type->getBodyScope(); }
55
56 /**
57 * Get the function parameter types of the underlying type
58 *
59 * @return Function parameter types
60 */
61 156 const QualType &QualType::getFunctionReturnType() const { return type->getFunctionReturnType(); }
62
63 /**
64 * Get the function parameter types of the underlying type
65 *
66 * @return Function parameter types
67 */
68 824 QualTypeList QualType::getFunctionParamTypes() const { return type->getFunctionParamTypes(); }
69
70 /**
71 * Get the function parameter and return types of the underlying type
72 *
73 * @return Function parameter and return types
74 */
75 839 const QualTypeList &QualType::getFunctionParamAndReturnTypes() const { return type->getFunctionParamAndReturnTypes(); }
76
77 /**
78 * Check if the underlying type has lambda captures
79 *
80 * @return Has lambda captures or not
81 */
82 752 bool QualType::hasLambdaCaptures() const { return type->hasLambdaCaptures(); }
83
84 /**
85 * Get the template types of the underlying type
86 *
87 * @return Template types
88 */
89 1095169 const QualTypeList &QualType::getTemplateTypes() const { return type->getTemplateTypes(); }
90
91 /**
92 * Get the struct instance for a struct type
93 *
94 * @param node Accessing AST node
95 * @param templateTypes Custom set of template types
96 * @return Struct instance
97 */
98 210839 Struct *QualType::getStruct(const ASTNode *node, const QualTypeList &templateTypes) const {
99
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 210839 times.
210839 assert(is(TY_STRUCT));
100 210839 Scope *structDefScope = getBodyScope()->parent;
101 210839 const std::string &structName = getSubType();
102 210839 return StructManager::match(structDefScope, structName, templateTypes, node);
103 }
104
105 /**
106 * Get the struct instance for a struct type
107 *
108 * @param node Accessing AST node
109 * @return Struct instance
110 */
111 143536 Struct *QualType::getStruct(const ASTNode *node) const { return getStruct(node, type->getTemplateTypes()); }
112
113 /**
114 * Get the struct instance for a struct type
115 * Adopt information from the struct to this type.
116 *
117 * @param node Accessing AST node
118 * @param templateTypes Custom set of template types
119 * @return Struct instance
120 */
121 3597 Struct *QualType::getStructAndAdjustType(const ASTNode *node, const QualTypeList &templateTypes) {
122 3597 Struct *spiceStruct = getStruct(node, templateTypes);
123
2/2
✓ Branch 3 → 4 taken 3595 times.
✓ Branch 3 → 9 taken 2 times.
3597 if (spiceStruct != nullptr)
124
2/4
✓ Branch 5 → 6 taken 3595 times.
✗ Branch 5 → 13 not taken.
✓ Branch 6 → 7 taken 3595 times.
✗ Branch 6 → 11 not taken.
3595 type = type->getWithBodyScope(spiceStruct->scope)->getWithTemplateTypes(spiceStruct->getTemplateTypes());
125 3597 return spiceStruct;
126 }
127
128 /**
129 * Get the struct instance for a struct type
130 * Adopt information from the struct to this type.
131 *
132 * @param node Accessing AST node
133 * @return Struct instance
134 */
135 Struct *QualType::getStructAndAdjustType(const ASTNode *node) { return getStructAndAdjustType(node, type->getTemplateTypes()); }
136
137 /**
138 * Get the interface instance for an interface type
139 *
140 * @param node Accessing AST node
141 * @param templateTypes Custom set of template types
142 * @return Interface instance
143 */
144 14953 Interface *QualType::getInterface(const ASTNode *node, const QualTypeList &templateTypes) const {
145
2/4
✓ Branch 2 → 3 taken 14953 times.
✗ Branch 2 → 15 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 14953 times.
14953 assert(is(TY_INTERFACE));
146
1/2
✓ Branch 5 → 6 taken 14953 times.
✗ Branch 5 → 15 not taken.
14953 Scope *interfaceDefScope = getBodyScope()->parent;
147
2/4
✓ Branch 6 → 7 taken 14953 times.
✗ Branch 6 → 15 not taken.
✓ Branch 7 → 8 taken 14953 times.
✗ Branch 7 → 15 not taken.
14953 const std::string structName = getSubType();
148
1/2
✓ Branch 8 → 9 taken 14953 times.
✗ Branch 8 → 13 not taken.
29906 return InterfaceManager::match(interfaceDefScope, structName, templateTypes, node);
149 14953 }
150
151 /**
152 * Get the interface instance for an interface type
153 *
154 * @param node Accessing AST node
155 * @return Interface instance
156 */
157 9326 Interface *QualType::getInterface(const ASTNode *node) const { return getInterface(node, type->getTemplateTypes()); }
158
159 /**
160 * Get the union instance for a union type
161 *
162 * @param node Accessing AST node
163 * @param templateTypes Custom set of template types
164 * @return Union instance
165 */
166 94 Union *QualType::getUnion(const ASTNode *node, const QualTypeList &templateTypes) const {
167
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 94 times.
94 assert(is(TY_UNION));
168 94 Scope *unionDefScope = getBodyScope()->parent;
169 94 const std::string &unionName = getSubType();
170 94 return UnionManager::match(unionDefScope, unionName, templateTypes, node);
171 }
172
173 /**
174 * Get the union instance for a union type
175 *
176 * @param node Accessing AST node
177 * @return Union instance
178 */
179 94 Union *QualType::getUnion(const ASTNode *node) const { return getUnion(node, type->getTemplateTypes()); }
180
181 /**
182 * Get the union instance for a union type
183 * Adopt information from the union to this type.
184 *
185 * @param node Accessing AST node
186 * @param templateTypes Custom set of template types
187 * @return Union instance
188 */
189 Union *QualType::getUnionAndAdjustType(const ASTNode *node, const QualTypeList &templateTypes) {
190 Union *spiceUnion = getUnion(node, templateTypes);
191 if (spiceUnion != nullptr)
192 type = type->getWithBodyScope(spiceUnion->scope)->getWithTemplateTypes(spiceUnion->getTemplateTypes());
193 return spiceUnion;
194 }
195
196 /**
197 * Get the union instance for a union type
198 * Adopt information from the union to this type.
199 *
200 * @param node Accessing AST node
201 * @return Union instance
202 */
203 Union *QualType::getUnionAndAdjustType(const ASTNode *node) { return getUnionAndAdjustType(node, type->getTemplateTypes()); }
204
205 /**
206 * Check if the underlying type is of a certain super type
207 *
208 * @param superType Super type
209 * @return Is of super type or not
210 */
211 32349039 bool QualType::is(SuperType superType) const { return type->is(superType); }
212
213 /**
214 * Check if the underlying type is one of a list of super types
215 *
216 * @param superTypes List of super types
217 * @return Is one of the super types or not
218 */
219 6241476 bool QualType::isOneOf(const std::initializer_list<SuperType> &superTypes) const { return type->isOneOf(superTypes); }
220
221 /**
222 * Check if the base type of the underlying type is a certain super type
223 *
224 * @param superType Super type
225 * @return Is base type or not
226 */
227 41531103 bool QualType::isBase(SuperType superType) const { return type->isBase(superType); }
228
229 /**
230 * Check if the underlying type is a primitive type
231 * Note: enum types are mapped to int, so they are also count as primitive types.
232 *
233 * @return Primitive or not
234 */
235 6293 bool QualType::isPrimitive() const { return type->isPrimitive(); }
236
237 /**
238 * Check if the underlying type is an extended primitive type
239 * The definition of extended primitive types contains all primitive types plus the following:
240 * - structs
241 * - interfaces
242 * - functions/procedures
243 *
244 * @return Extended primitive or not
245 */
246 724445 bool QualType::isExtendedPrimitive() const { return type->isExtendedPrimitive(); }
247
248 /**
249 * Check if the underlying type is a pointer
250 *
251 * @return Pointer or not
252 */
253 2856354 bool QualType::isPtr() const { return type->isPtr(); }
254
255 /**
256 * Check if the underlying type is a pointer to a certain super type
257 *
258 * @param superType Super type
259 * @return Pointer to super type or not
260 */
261
7/10
✓ Branch 2 → 3 taken 1397614 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 150834 times.
✓ Branch 3 → 8 taken 1246780 times.
✓ Branch 4 → 5 taken 150834 times.
✗ Branch 4 → 11 not taken.
✓ Branch 5 → 6 taken 150834 times.
✗ Branch 5 → 11 not taken.
✓ Branch 6 → 7 taken 56752 times.
✓ Branch 6 → 8 taken 94082 times.
1397614 bool QualType::isPtrTo(SuperType superType) const { return isPtr() && getContained().is(superType); }
262
263 /**
264 * Check if the underlying type is a reference
265 *
266 * @return Reference or not
267 */
268 4173608 bool QualType::isRef() const { return type->isRef(); }
269
270 /**
271 * Check if the underlying type is a reference to a certain super type
272 *
273 * @param superType Super type
274 * @return Reference to super type or not
275 */
276 bool QualType::isRefTo(SuperType superType) const { return isRef() && getContained().is(superType); }
277
278 /**
279 * Check if the underlying type is an array
280 *
281 * @return Array or not
282 */
283 1123670 bool QualType::isArray() const { return type->isArray(); }
284
285 /**
286 * Check if the underlying type is an array of a certain super type
287 *
288 * @param superType Super type
289 * @return Array of super type or not
290 */
291
2/10
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 11 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 8 taken 2 times.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 11 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
2 bool QualType::isArrayOf(SuperType superType) const { return isArray() && getContained().is(superType); }
292
293 /**
294 * Check if the underlying type is an array that decays to a pointer to itself when passed to a function.
295 *
296 * Fixed-size arrays are the only aggregates that Spice used to hand to LLVM as first-class aggregate arguments. That
297 * left the ABI lowering of the individual elements to the backend, which is neither a stable contract nor efficient,
298 * because the whole array had to be loaded at the call site and stored again in the callee prologue. Instead, we now
299 * decay them to a pointer to the array, just like C/C++ frontends do. Arrays of unknown size are plain pointers
300 * already, so there is nothing to decay for them.
301 *
302 * @return Decays to a pointer or not
303 */
304
4/4
✓ Branch 3 → 4 taken 1422 times.
✓ Branch 3 → 7 taken 621719 times.
✓ Branch 5 → 6 taken 158 times.
✓ Branch 5 → 7 taken 1264 times.
623141 bool QualType::isDecayedArray() const { return isArray() && getArraySize() != ARRAY_SIZE_UNKNOWN; }
305
306 /**
307 * Check if the underlying type is a const reference
308 *
309 * @return Const reference or not
310 */
311
4/4
✓ Branch 2 → 3 taken 70997 times.
✓ Branch 2 → 6 taken 15076 times.
✓ Branch 4 → 5 taken 70247 times.
✓ Branch 4 → 6 taken 750 times.
86073 bool QualType::isConstRef() const { return qualifiers.isConst && isRef(); }
312
313 /**
314 * Check if the current type is an iterator
315 *
316 * @param node ASTNode
317 * @return Iterator or not
318 */
319 996 bool QualType::isIterator(const ASTNode *node) const {
320 // The type must be a struct that implements the iterator interface
321
3/4
✓ Branch 2 → 3 taken 996 times.
✗ Branch 2 → 47 not taken.
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 994 times.
996 if (!is(TY_STRUCT))
322 2 return false;
323
324
2/4
✓ Branch 7 → 8 taken 994 times.
✗ Branch 7 → 30 not taken.
✓ Branch 8 → 9 taken 994 times.
✗ Branch 8 → 28 not taken.
1988 const QualType genericType(TY_GENERIC, "T");
325 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
326
3/6
✓ Branch 13 → 14 taken 994 times.
✗ Branch 13 → 42 not taken.
✓ Branch 16 → 17 taken 994 times.
✗ Branch 16 → 36 not taken.
✓ Branch 17 → 18 taken 994 times.
✗ Branch 17 → 34 not taken.
3976 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERATOR_INTERFACE, data, {genericType});
327
1/2
✓ Branch 22 → 23 taken 994 times.
✗ Branch 22 → 47 not taken.
994 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
328
1/2
✓ Branch 24 → 25 taken 994 times.
✗ Branch 24 → 47 not taken.
994 return doesImplement(iteratorQualType, node);
329 }
330
331 /**
332 * Check if the current type is an iterable
333 * - Arrays are always considered iterable
334 * - Otherwise the type must be a struct that implements the iterator interface
335 *
336 * @param node ASTNode
337 * @return Iterable or not
338 */
339 1000 bool QualType::isIterable(const ASTNode *node) const {
340 // Arrays are always considered iterable
341
3/4
✓ Branch 2 → 3 taken 1000 times.
✗ Branch 2 → 50 not taken.
✓ Branch 3 → 4 taken 38 times.
✓ Branch 3 → 5 taken 962 times.
1000 if (isArray())
342 38 return true;
343 // Otherwise the type must be a struct that implements the iterator interface
344
3/4
✓ Branch 5 → 6 taken 962 times.
✗ Branch 5 → 50 not taken.
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 8 taken 960 times.
962 if (!is(TY_STRUCT))
345 2 return false;
346
347
2/4
✓ Branch 10 → 11 taken 960 times.
✗ Branch 10 → 33 not taken.
✓ Branch 11 → 12 taken 960 times.
✗ Branch 11 → 31 not taken.
1920 const QualType genericType(TY_GENERIC, "T");
348 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
349
3/6
✓ Branch 16 → 17 taken 960 times.
✗ Branch 16 → 45 not taken.
✓ Branch 19 → 20 taken 960 times.
✗ Branch 19 → 39 not taken.
✓ Branch 20 → 21 taken 960 times.
✗ Branch 20 → 37 not taken.
3840 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERABLE_INTERFACE, data, {genericType});
350
1/2
✓ Branch 25 → 26 taken 960 times.
✗ Branch 25 → 50 not taken.
960 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
351
1/2
✓ Branch 27 → 28 taken 960 times.
✗ Branch 27 → 50 not taken.
960 return doesImplement(iteratorQualType, node);
352 }
353
354 /**
355 * Check if the current type is a string object
356 *
357 * @return String object or not
358 */
359 2246 bool QualType::isStringObj() const {
360
4/6
✓ Branch 3 → 4 taken 352 times.
✓ Branch 3 → 10 taken 1894 times.
✓ Branch 6 → 7 taken 352 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 352 times.
✗ Branch 8 → 10 not taken.
2246 return is(TY_STRUCT) && getSubType() == STROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
361 }
362
363 /**
364 * Check if the current type is an error object
365 *
366 * @return Error object or not
367 */
368 5181 bool QualType::isErrorObj() const {
369
4/6
✓ Branch 3 → 4 taken 5179 times.
✓ Branch 3 → 10 taken 2 times.
✓ Branch 6 → 7 taken 5179 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 5179 times.
✗ Branch 8 → 10 not taken.
5181 return is(TY_STRUCT) && getSubType() == ERROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
370 }
371
372 /**
373 * Check if the current type is a result object
374 *
375 * @return Result object or not
376 */
377 264 bool QualType::isResultObj() const {
378
4/6
✓ Branch 3 → 4 taken 258 times.
✓ Branch 3 → 10 taken 6 times.
✓ Branch 6 → 7 taken 258 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 258 times.
✗ Branch 8 → 10 not taken.
264 return is(TY_STRUCT) && getSubType() == RESULTOBJ_NAME && getBodyScope()->sourceFile->isStdFile;
379 }
380
381 /**
382 * Check if the current type has any generic parts
383 *
384 * @return Generic parts or not
385 */
386 3382797 bool QualType::hasAnyGenericParts() const { return type->hasAnyGenericParts(); }
387
388 /**
389 * Check if constructing an instance of the current type would require calling a ctor.
390 * If this function return true, the type does not need to be constructed.
391 *
392 * @param node Accessing ASTNode
393 * @return Trivially constructible or not
394 */
395 6092 bool QualType::isTriviallyConstructible(const ASTNode *node) const {
396 // References can't be default initialized
397
3/4
✓ Branch 2 → 3 taken 6092 times.
✗ Branch 2 → 39 not taken.
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 5 taken 6086 times.
6092 if (isRef())
398 6 return false;
399
400 // In case of an array, the item type is determining the construction triviality
401
3/4
✓ Branch 5 → 6 taken 6086 times.
✗ Branch 5 → 39 not taken.
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 11 taken 6084 times.
6086 if (isArray())
402
2/4
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 38 not taken.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 38 not taken.
2 return getBase().isTriviallyConstructible(node);
403
404 // In case of a struct, the member types determine the construction triviality
405
3/4
✓ Branch 11 → 12 taken 6084 times.
✗ Branch 11 → 39 not taken.
✓ Branch 12 → 13 taken 672 times.
✓ Branch 12 → 14 taken 5412 times.
6084 if (!is(TY_STRUCT))
406 672 return true;
407
408 // If the struct has a ctor, it is a non-trivially constructible one
409
1/2
✓ Branch 14 → 15 taken 5412 times.
✗ Branch 14 → 39 not taken.
5412 const Struct *spiceStruct = getStruct(node);
410
1/2
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 5412 times.
5412 assert(spiceStruct != nullptr); // Callers must ensure the struct is manifested (see structFullyManifested)
411
3/4
✓ Branch 17 → 18 taken 5412 times.
✗ Branch 17 → 39 not taken.
✓ Branch 18 → 19 taken 5120 times.
✓ Branch 18 → 20 taken 292 times.
5412 if (FunctionManager::hasAnyNonCopyCtor(spiceStruct->scope))
412 5120 return false;
413
414 // If the struct emits a vtable, it is non-trivially constructible, because the vtable needs to be initialized in the ctor
415
1/2
✓ Branch 20 → 21 taken 292 times.
✗ Branch 20 → 22 not taken.
292 const auto *structDefNode = spice_pointer_cast<StructDefNode *>(spiceStruct->declNode);
416
2/2
✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 31 taken 290 times.
292 if (structDefNode->emitVTable)
417 2 return false;
418
419 // If any field has a default value, the struct is non-trivially constructible
420 428 const auto pred1 = [&](const FieldNode *fieldNode) { return fieldNode->defaultValue != nullptr; };
421
3/4
✓ Branch 31 → 32 taken 290 times.
✗ Branch 31 → 39 not taken.
✓ Branch 32 → 33 taken 12 times.
✓ Branch 32 → 34 taken 278 times.
290 if (std::ranges::any_of(structDefNode->fields, pred1))
422 12 return false;
423
424 // Check if all member types are trivially constructible
425 414 const auto pred2 = [&](const QualType &fieldType) { return fieldType.isTriviallyConstructible(node); };
426
1/2
✓ Branch 34 → 35 taken 278 times.
✗ Branch 34 → 39 not taken.
278 return std::ranges::all_of(spiceStruct->fieldTypes, pred2);
427 }
428
429 /**
430 * Check if copying an instance of the current type would require a call to the copy ctor.
431 * If this function return true, the type can be copied by calling memcpy.
432 *
433 * @param node Accessing ASTNode
434 * @return Trivially copyable or not
435 */
436 140434 bool QualType::isTriviallyCopyable(const ASTNode *node) const { // NOLINT(*-no-recursion)
437 // In case of an array, the item type is determining the copy triviality
438
3/4
✓ Branch 2 → 3 taken 140434 times.
✗ Branch 2 → 20 not taken.
✓ Branch 3 → 4 taken 222 times.
✓ Branch 3 → 8 taken 140212 times.
140434 if (isArray())
439
2/4
✓ Branch 4 → 5 taken 222 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 222 times.
✗ Branch 5 → 19 not taken.
222 return getBase().isTriviallyCopyable(node);
440
441 // In case of a struct, the member types determine the copy triviality
442 // Only structs can own a copy ctor
443
3/4
✓ Branch 8 → 9 taken 140212 times.
✗ Branch 8 → 20 not taken.
✓ Branch 9 → 10 taken 123125 times.
✓ Branch 9 → 11 taken 17087 times.
140212 if (!is(TY_STRUCT))
444 123125 return true;
445
446 // If the struct has a copy ctor, it is a non-trivially copyable one
447
1/2
✓ Branch 11 → 12 taken 17087 times.
✗ Branch 11 → 20 not taken.
17087 const Struct *spiceStruct = getStruct(node);
448
3/4
✓ Branch 12 → 13 taken 17087 times.
✗ Branch 12 → 20 not taken.
✓ Branch 13 → 14 taken 5236 times.
✓ Branch 13 → 15 taken 11851 times.
17087 if (FunctionManager::hasCopyCtor(spiceStruct->scope))
449 5236 return false;
450
451 // Check if all member types are trivially copyable
452 27462 const auto pred = [&](const QualType &fieldType) { return fieldType.isTriviallyCopyable(node); }; // NOLINT(*-no-recursion)
453
1/2
✓ Branch 15 → 16 taken 11851 times.
✗ Branch 15 → 20 not taken.
11851 return std::ranges::all_of(spiceStruct->fieldTypes, pred);
454 }
455
456 /**
457 * Check if destructing an instance of the current type would require calling a dtor.
458 * If this function return true, the type does not need to be destructed.
459 *
460 * @param node Accessing ASTNode
461 * @return Trivially destructible or not
462 */
463 88069 bool QualType::isTriviallyDestructible(const ASTNode *node) const {
464 // In case of an array, the item type is determining the destructing triviality
465
3/4
✓ Branch 2 → 3 taken 88069 times.
✗ Branch 2 → 20 not taken.
✓ Branch 3 → 4 taken 18 times.
✓ Branch 3 → 8 taken 88051 times.
88069 if (isArray())
466
2/4
✓ Branch 4 → 5 taken 18 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 18 times.
✗ Branch 5 → 19 not taken.
18 return getBase().isTriviallyDestructible(node);
467
468 // Only structs can own a dtor
469
3/4
✓ Branch 8 → 9 taken 88051 times.
✗ Branch 8 → 20 not taken.
✓ Branch 9 → 10 taken 44751 times.
✓ Branch 9 → 11 taken 43300 times.
88051 if (!is(TY_STRUCT))
470 44751 return true;
471
472 // If the struct has a dtor, it is a non-trivially destructible one
473
1/2
✓ Branch 11 → 12 taken 43300 times.
✗ Branch 11 → 20 not taken.
43300 const Struct *spiceStruct = getStruct(node);
474
3/4
✓ Branch 12 → 13 taken 43300 times.
✗ Branch 12 → 20 not taken.
✓ Branch 13 → 14 taken 22431 times.
✓ Branch 13 → 15 taken 20869 times.
43300 if (FunctionManager::hasDtor(spiceStruct->scope))
475 22431 return false;
476
477 // Check if all member types are trivially destructible
478 48529 const auto pred = [&](const QualType &fieldType) { return fieldType.isTriviallyDestructible(node); }; // NOLINT(*-no-recursion)
479
1/2
✓ Branch 15 → 16 taken 20869 times.
✗ Branch 15 → 20 not taken.
20869 return std::ranges::all_of(spiceStruct->fieldTypes, pred);
480 }
481
482 /**
483 * Check if the current type implements the given interface type
484 *
485 * @param implementedInterfaceType Interface type
486 * @param node Accessing ASTNode
487 * @return Struct implements interface or not
488 */
489 1956 bool QualType::doesImplement(const QualType &implementedInterfaceType, const ASTNode *node) const {
490
2/4
✓ Branch 3 → 4 taken 1956 times.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 1956 times.
✗ Branch 5 → 7 not taken.
1956 assert(is(TY_STRUCT) && implementedInterfaceType.is(TY_INTERFACE));
491 1956 const Struct *spiceStruct = getStruct(node);
492
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 1956 times.
1956 assert(spiceStruct != nullptr);
493 1956 return std::ranges::any_of(spiceStruct->interfaceTypes, [&](const QualType &interfaceType) {
494
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1956 times.
1956 assert(interfaceType.is(TY_INTERFACE));
495 1956 return implementedInterfaceType.matches(interfaceType, false, false, true);
496 1956 });
497 }
498
499 /**
500 * Check if a certain input type can be bound (assigned) to the current type.
501 *
502 * @param inputType Qualified type, which should be bound to the current type
503 * @param isTemporary Is the input type a temporary type
504 * @return Can be bound or not
505 */
506 119508 bool QualType::canBind(const QualType &inputType, bool isTemporary) const {
507
8/8
✓ Branch 2 → 3 taken 29827 times.
✓ Branch 2 → 9 taken 89681 times.
✓ Branch 4 → 5 taken 28584 times.
✓ Branch 4 → 9 taken 1243 times.
✓ Branch 6 → 7 taken 3152 times.
✓ Branch 6 → 9 taken 25432 times.
✓ Branch 8 → 9 taken 3148 times.
✓ Branch 8 → 10 taken 4 times.
119508 return !isTemporary || inputType.type->isRef() || !type->isRef() || isConstRef();
508 }
509
510 /**
511 * Check for the matching compatibility of two types.
512 * Useful for struct and function matching as well as assignment type validation and function arg matching.
513 *
514 * @param otherType Type to compare against
515 * @param ignoreArraySize Ignore array sizes
516 * @param ignoreQualifiers Ignore qualifiers, except for pointer and reference types
517 * @param allowConstify Match when the types are the same, but the lhs type is more const restrictive than the rhs type
518 * @return Matching or not
519 */
520 1042748 bool QualType::matches(const QualType &otherType, bool ignoreArraySize, bool ignoreQualifiers, bool allowConstify) const {
521 // Special case: string is equivalent to const char*
522
6/8
✓ Branch 3 → 4 taken 123752 times.
✓ Branch 3 → 9 taken 918996 times.
✓ Branch 5 → 6 taken 9472 times.
✓ Branch 5 → 9 taken 114280 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 9472 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1042748 times.
1042748 if (is(TY_STRING) && otherType.isPtrTo(TY_CHAR) && otherType.isConst())
523 return true;
524
4/8
✓ Branch 13 → 14 taken 38288 times.
✓ Branch 13 → 19 taken 1004460 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 19 taken 38288 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 1042748 times.
1042748 if (isPtrTo(TY_CHAR) && isConst() && otherType.is(TY_STRING))
525 return true;
526
527 // Compare type
528
2/2
✓ Branch 23 → 24 taken 425494 times.
✓ Branch 23 → 25 taken 617254 times.
1042748 if (!type->matches(otherType.type, ignoreArraySize))
529 425494 return false;
530
531 // Ignore or compare qualifiers
532
4/4
✓ Branch 25 → 26 taken 162111 times.
✓ Branch 25 → 28 taken 455143 times.
✓ Branch 27 → 28 taken 161074 times.
✓ Branch 27 → 29 taken 1037 times.
617254 return ignoreQualifiers || qualifiers.match(otherType.qualifiers, allowConstify);
533 }
534
535 /**
536 * Check for the matching compatibility of two types in terms of interface implementation.
537 * Useful for function matching as well as assignment type validation and function arg matching.
538 *
539 * @param structType Type to compare against
540 * @return Matching or not
541 */
542 554401 bool QualType::matchesInterfaceImplementedByStruct(const QualType &structType) const {
543
8/10
✓ Branch 2 → 3 taken 554401 times.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 6590 times.
✓ Branch 3 → 6 taken 547811 times.
✓ Branch 4 → 5 taken 6590 times.
✗ Branch 4 → 17 not taken.
✓ Branch 5 → 6 taken 3989 times.
✓ Branch 5 → 7 taken 2601 times.
✓ Branch 8 → 9 taken 551800 times.
✓ Branch 8 → 10 taken 2601 times.
554401 if (!is(TY_INTERFACE) || !structType.is(TY_STRUCT))
544 551800 return false;
545
546 // Check if the rhs is a struct type that implements the lhs interface type
547
1/2
✓ Branch 10 → 11 taken 2601 times.
✗ Branch 10 → 17 not taken.
2601 const Struct *spiceStruct = structType.getStruct(nullptr);
548
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 2601 times.
2601 assert(spiceStruct != nullptr);
549 2522 const auto pred = [&](const QualType &interfaceType) { return matches(interfaceType, false, false, true); };
550
1/2
✓ Branch 13 → 14 taken 2601 times.
✗ Branch 13 → 17 not taken.
2601 return std::ranges::any_of(spiceStruct->interfaceTypes, pred);
551 }
552
553 /**
554 * Check if the current (struct) type is a base of the given struct type, embedded via the 'compose'
555 * qualifier as its first field. The compiler does not perform implicit struct-to-composed-base upcasts;
556 * this matcher only gates the explicit 'cast<Base*>(derived)' conversion (and the matching IR pointer
557 * adjustment). Only first-field compositions are considered, because those are the ones reachable by
558 * advancing the pointer along the first-field chain. The check follows that chain transitively, so a base
559 * that is composed several levels deep is still matched.
560 */
561 14112 bool QualType::matchesComposedBaseOfStruct(const QualType &structType) const {
562
6/6
✓ Branch 3 → 4 taken 7754 times.
✓ Branch 3 → 6 taken 6358 times.
✓ Branch 5 → 6 taken 2816 times.
✓ Branch 5 → 7 taken 4938 times.
✓ Branch 8 → 9 taken 9174 times.
✓ Branch 8 → 10 taken 4938 times.
14112 if (!is(TY_STRUCT) || !structType.is(TY_STRUCT))
563 9174 return false;
564
565 4938 const Struct *spiceStruct = structType.getStruct(nullptr);
566
3/6
✓ Branch 11 → 12 taken 4938 times.
✗ Branch 11 → 14 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 4938 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 4938 times.
4938 if (spiceStruct == nullptr || spiceStruct->fieldTypes.empty())
567 return false;
568
569 // Only the first field can be a composed base that is reachable along the first-field chain
570 4938 const QualType &firstFieldType = spiceStruct->fieldTypes.front();
571
1/2
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 4938 times.
4938 if (!firstFieldType.isComposition())
572 return false;
573 // The composed field matches the requested base directly (qualifiers like 'compose' are ignored)
574
2/2
✓ Branch 23 → 24 taken 2772 times.
✓ Branch 23 → 25 taken 2166 times.
4938 if (matches(firstFieldType, false, true, true))
575 2772 return true;
576 // Otherwise follow the composition chain further down
577 2166 return matchesComposedBaseOfStruct(firstFieldType);
578 }
579
580 /**
581 * Check if the current type is the same container type as another type.
582 * Container types include arrays, pointers, and references.
583 *
584 * @param other Other type
585 * @return Same container type or not
586 */
587 22183 bool QualType::isSameContainerTypeAs(const QualType &other) const { return type->isSameContainerTypeAs(other.type); }
588
589 /**
590 * Check if the current type is a self-referencing struct type
591 *
592 * @param typeToCompareWith Type to compare with (nil on the first iteration)
593 * @return Self-referencing struct type or not
594 */
595 238725 bool QualType::isSelfReferencingStructType(const QualType *typeToCompareWith) const { // NOLINT(*-no-recursion)
596
2/2
✓ Branch 3 → 4 taken 178792 times.
✓ Branch 3 → 5 taken 59933 times.
238725 if (!is(TY_STRUCT))
597 178792 return false;
598
599 // If no type was set by a previous iteration, we set it to the current type
600
2/2
✓ Branch 5 → 6 taken 44770 times.
✓ Branch 5 → 7 taken 15163 times.
59933 if (typeToCompareWith == nullptr)
601 44770 typeToCompareWith = this;
602
603 59933 Scope *baseTypeBodyScope = getBodyScope();
604
2/2
✓ Branch 25 → 9 taken 191841 times.
✓ Branch 25 → 26 taken 58418 times.
250259 for (size_t i = 0; i < baseTypeBodyScope->getFieldCount(); i++) {
605
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 191841 times.
191841 const SymbolTableEntry *field = baseTypeBodyScope->lookupField(i);
606 191841 const QualType &fieldType = field->getQualType();
607 // Check if the base type of the field matches with the current type, which is also a base type
608 // If yes, this is a self-referencing struct type
609
3/4
✓ Branch 16 → 17 taken 191841 times.
✗ Branch 16 → 28 not taken.
✓ Branch 18 → 19 taken 1515 times.
✓ Branch 18 → 20 taken 190326 times.
191841 if (fieldType.getBase() == *typeToCompareWith)
610 1515 return true;
611
612 // If the field is a struct, check if it is a self-referencing struct type
613
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 190326 times.
190326 if (fieldType.isSelfReferencingStructType(typeToCompareWith))
614 return true;
615 }
616 58418 return false;
617 }
618
619 /**
620 * Check if the given generic type list has a substantiation for the current (generic) type
621 *
622 * @param genericTypeList Generic type list
623 * @return Has substantiation or not
624 */
625 180055 bool QualType::isCoveredByGenericTypeList(std::vector<GenericType> &genericTypeList) const { // NOLINT(*-no-recursion)
626
1/2
✓ Branch 2 → 3 taken 180055 times.
✗ Branch 2 → 19 not taken.
180055 const QualType baseType = getBase();
627 // Check if the symbol type itself is generic
628
3/4
✓ Branch 3 → 4 taken 180055 times.
✗ Branch 3 → 19 not taken.
✓ Branch 4 → 5 taken 28047 times.
✓ Branch 4 → 7 taken 152008 times.
180055 if (baseType.is(TY_GENERIC)) {
629
1/2
✓ Branch 5 → 6 taken 28047 times.
✗ Branch 5 → 19 not taken.
28047 return std::ranges::any_of(genericTypeList, [&](GenericType &t) {
630
2/2
✓ Branch 3 → 4 taken 28031 times.
✓ Branch 3 → 5 taken 5308 times.
33339 if (baseType.matches(t, true, true, true)) {
631 28031 t.used = true;
632 28031 return true;
633 }
634 5308 return false;
635 28047 });
636 }
637
638 // If the type is non-generic check template types
639 152008 bool covered = true;
640 // Check template types
641
1/2
✓ Branch 7 → 8 taken 152008 times.
✗ Branch 7 → 19 not taken.
152008 const QualTypeList &baseTemplateTypes = baseType.getTemplateTypes();
642 166412 auto outerPred = [&](const QualType &templateType) { // NOLINT(*-no-recursion)
643 14404 return templateType.isCoveredByGenericTypeList(genericTypeList);
644 152008 };
645
1/2
✓ Branch 8 → 9 taken 152008 times.
✗ Branch 8 → 19 not taken.
152008 covered &= std::ranges::all_of(baseTemplateTypes, outerPred);
646
647 // If function/procedure, check param and return types
648
3/4
✓ Branch 9 → 10 taken 152008 times.
✗ Branch 9 → 17 not taken.
✓ Branch 10 → 11 taken 649 times.
✓ Branch 10 → 14 taken 151359 times.
152008 if (baseType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
649
1/2
✓ Branch 11 → 12 taken 649 times.
✗ Branch 11 → 18 not taken.
649 const QualTypeList &paramAndReturnTypes = baseType.getFunctionParamAndReturnTypes();
650 1933 const auto innerPred = [&](const QualType &paramType) { // NOLINT(*-no-recursion)
651 1284 return paramType.isCoveredByGenericTypeList(genericTypeList);
652 649 };
653
1/2
✓ Branch 12 → 13 taken 649 times.
✗ Branch 12 → 18 not taken.
649 covered &= std::ranges::all_of(paramAndReturnTypes, innerPred);
654 }
655
656 152008 return covered;
657 }
658
659 /**
660 * Check if the current type needs de-allocation
661 *
662 * @return Needs de-allocation or not
663 */
664 33405 bool QualType::needsDeAllocation() const {
665
2/2
✓ Branch 3 → 4 taken 32120 times.
✓ Branch 3 → 5 taken 1285 times.
33405 if (!isHeap())
666 32120 return false;
667 // We only need de-allocation, if we directly point to a heap-allocated type
668 // e.g. for heap TestStruct** we don't need to de-allocate, since it is a non-owning pointer to an owning pointer
669
3/4
✓ Branch 6 → 7 taken 1285 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 1245 times.
✓ Branch 8 → 10 taken 40 times.
1285 return isPtr() && !isPtrTo(TY_PTR);
670 }
671
672 /**
673 * Get the name of the symbol type as a string
674 *
675 * @param name Name stream
676 * @param withSize Include the array size for sized types
677 * @param ignorePublic Ignore any potential public qualifier
678 * @param withAliases Print aliases as is and not decompose them
679 */
680 5414235 void QualType::getName(std::stringstream &name, bool withSize, bool ignorePublic, bool withAliases) const {
681 // Append the qualifiers
682
3/6
✓ Branch 2 → 3 taken 5414235 times.
✗ Branch 2 → 31 not taken.
✓ Branch 3 → 4 taken 5414235 times.
✗ Branch 3 → 31 not taken.
✓ Branch 4 → 5 taken 5414235 times.
✗ Branch 4 → 31 not taken.
5414235 const TypeQualifiers defaultForSuperType = TypeQualifiers::of(getBase().getSuperType());
683
5/6
✓ Branch 5 → 6 taken 3997737 times.
✓ Branch 5 → 9 taken 1416498 times.
✓ Branch 6 → 7 taken 1697798 times.
✓ Branch 6 → 9 taken 2299939 times.
✓ Branch 7 → 8 taken 1697798 times.
✗ Branch 7 → 9 not taken.
5414235 if (!ignorePublic && qualifiers.isPublic && !defaultForSuperType.isPublic)
684
1/2
✓ Branch 8 → 9 taken 1697798 times.
✗ Branch 8 → 32 not taken.
1697798 name << "public ";
685
3/4
✓ Branch 9 → 10 taken 8440 times.
✓ Branch 9 → 12 taken 5405795 times.
✓ Branch 10 → 11 taken 8440 times.
✗ Branch 10 → 12 not taken.
5414235 if (qualifiers.isComposition && !defaultForSuperType.isComposition)
686
1/2
✓ Branch 11 → 12 taken 8440 times.
✗ Branch 11 → 32 not taken.
8440 name << "compose ";
687
8/8
✓ Branch 12 → 13 taken 577510 times.
✓ Branch 12 → 17 taken 4836725 times.
✓ Branch 13 → 14 taken 553273 times.
✓ Branch 13 → 17 taken 24237 times.
✓ Branch 15 → 16 taken 432167 times.
✓ Branch 15 → 17 taken 121106 times.
✓ Branch 18 → 19 taken 432167 times.
✓ Branch 18 → 20 taken 4982068 times.
5414235 if (qualifiers.isConst && !defaultForSuperType.isConst && type->typeChain.size() > 1)
688
1/2
✓ Branch 19 → 20 taken 432167 times.
✗ Branch 19 → 32 not taken.
432167 name << "const ";
689
3/4
✓ Branch 20 → 21 taken 180961 times.
✓ Branch 20 → 23 taken 5233274 times.
✓ Branch 21 → 22 taken 180961 times.
✗ Branch 21 → 23 not taken.
5414235 if (qualifiers.isHeap && !defaultForSuperType.isHeap)
690
1/2
✓ Branch 22 → 23 taken 180961 times.
✗ Branch 22 → 32 not taken.
180961 name << "heap ";
691
4/4
✓ Branch 23 → 24 taken 430591 times.
✓ Branch 23 → 26 taken 4983644 times.
✓ Branch 24 → 25 taken 2 times.
✓ Branch 24 → 26 taken 430589 times.
5414235 if (qualifiers.isSigned && !defaultForSuperType.isSigned)
692
1/2
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 32 not taken.
2 name << "signed ";
693
4/4
✓ Branch 26 → 27 taken 4983644 times.
✓ Branch 26 → 29 taken 430591 times.
✓ Branch 27 → 28 taken 529177 times.
✓ Branch 27 → 29 taken 4454467 times.
5414235 if (!qualifiers.isSigned && defaultForSuperType.isSigned)
694
1/2
✓ Branch 28 → 29 taken 529177 times.
✗ Branch 28 → 32 not taken.
529177 name << "unsigned ";
695
696 // Loop through all chain elements
697
1/2
✓ Branch 29 → 30 taken 5414235 times.
✗ Branch 29 → 32 not taken.
5414235 type->getName(name, withSize, ignorePublic, withAliases);
698 5414235 }
699
700 /**
701 * Get the name of the symbol type as a string
702 *
703 * @param withSize Include the array size for sized types
704 * @param ignorePublic Ignore any potential public qualifier
705 * @param withAliases Print aliases as is and not decompose them
706 * @return Symbol type name
707 */
708 2507897 std::string QualType::getName(bool withSize, bool ignorePublic, bool withAliases) const {
709
1/2
✓ Branch 2 → 3 taken 2507897 times.
✗ Branch 2 → 11 not taken.
2507897 std::stringstream name;
710
1/2
✓ Branch 3 → 4 taken 2507897 times.
✗ Branch 3 → 9 not taken.
2507897 getName(name, withSize, ignorePublic, withAliases);
711
1/2
✓ Branch 4 → 5 taken 2507897 times.
✗ Branch 4 → 9 not taken.
5015794 return name.str();
712 2507897 }
713
714 /**
715 * Convert the type to an LLVM type
716 *
717 * @param sourceFile Source file
718 * @return LLVM type
719 */
720 2786471 llvm::Type *QualType::toLLVMType(SourceFile *sourceFile) const { return sourceFile->getLLVMType(type); }
721
722 /**
723 * Convert the type to the LLVM type to use for a parameter of this type in a function signature
724 *
725 * @param sourceFile Source file
726 * @return LLVM type
727 */
728 141859 llvm::Type *QualType::getParamLLVMType(SourceFile *sourceFile) const {
729 // Take the context from the converted type, so that we always end up in the same context as toLLVMType()
730 141859 llvm::Type *llvmType = toLLVMType(sourceFile);
731
2/2
✓ Branch 4 → 5 taken 30 times.
✓ Branch 4 → 8 taken 141829 times.
141859 return isDecayedArray() ? llvm::PointerType::get(llvmType->getContext(), 0) : llvmType;
732 }
733
734 /**
735 * Retrieve the pointer type to this type
736 *
737 * @param node ASTNode
738 * @return New type
739 */
740 250617 QualType QualType::toPtr(const ASTNode *node) const {
741 250617 QualType newType = *this;
742
2/2
✓ Branch 2 → 3 taken 250613 times.
✓ Branch 2 → 5 taken 4 times.
250617 newType.type = type->toPtr(node);
743 250613 return newType;
744 }
745
746 /**
747 * Retrieve the reference type to this type
748 *
749 * @param node ASTNode
750 * @return New type
751 */
752 116757 QualType QualType::toRef(const ASTNode *node) const {
753 116757 QualType newType = *this;
754
1/2
✓ Branch 2 → 3 taken 116757 times.
✗ Branch 2 → 5 not taken.
116757 newType.type = type->toRef(node);
755 116757 return newType;
756 }
757
758 /**
759 * Retrieve the const reference type of this type
760 *
761 * @param node ASTNode
762 * @return New type
763 */
764 52363 QualType QualType::toConstRef(const ASTNode *node) const {
765
1/2
✓ Branch 2 → 3 taken 52363 times.
✗ Branch 2 → 6 not taken.
52363 QualType newType = toRef(node);
766 52363 newType.makeConst();
767 52363 return newType;
768 }
769
770 /**
771 * Retrieve the array type of this type
772 *
773 * @param node ASTNode
774 * @param size Array size
775 * @param skipDynCheck Skip dynamic check
776 * @return New type
777 */
778 1921 QualType QualType::toArr(const ASTNode *node, size_t size, bool skipDynCheck /*=false*/) const {
779 1921 QualType newType = *this;
780
2/2
✓ Branch 2 → 3 taken 1919 times.
✓ Branch 2 → 5 taken 2 times.
1921 newType.type = type->toArr(node, size, skipDynCheck);
781 1919 return newType;
782 }
783
784 /**
785 * Retrieve the non-const type of this type
786 *
787 * @return New type
788 */
789 25313 QualType QualType::toNonConst() const {
790 25313 QualType newType = *this;
791 25313 newType.qualifiers.isConst = false;
792 25313 return newType;
793 }
794
795 /**
796 * Retrieve the contained type of this type
797 * This works on pointers, arrays, references and strings (which alias with char*)
798 *
799 * @return New type
800 */
801 894306 QualType QualType::getContained() const {
802
2/4
✓ Branch 2 → 3 taken 894306 times.
✗ Branch 2 → 8 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 894306 times.
894306 assert(isOneOf({TY_PTR, TY_REF, TY_ARRAY, TY_STRING}));
803 894306 QualType newType = *this;
804
1/2
✓ Branch 5 → 6 taken 894306 times.
✗ Branch 5 → 9 not taken.
894306 newType.type = type->getContained();
805 894306 return newType;
806 }
807
808 /**
809 * Retrieve the base type of this type
810 *
811 * @return New type
812 */
813 14962074 QualType QualType::getBase() const {
814 14962074 QualType newType = *this;
815
1/2
✓ Branch 2 → 3 taken 14962074 times.
✗ Branch 2 → 5 not taken.
14962074 newType.type = type->getBase();
816 14962074 return newType;
817 }
818
819 /**
820 * Get aliased type for an alias type
821 *
822 * @param aliasEntry Entry of the alias definition
823 * @return Aliased type
824 */
825 12749 QualType QualType::getAliased(const SymbolTableEntry *aliasEntry) const {
826
2/4
✓ Branch 2 → 3 taken 12749 times.
✗ Branch 2 → 17 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 12749 times.
12749 assert(is(TY_ALIAS));
827 // Get type of aliased type container entry
828
1/2
✓ Branch 5 → 6 taken 12749 times.
✗ Branch 5 → 17 not taken.
12749 const std::string aliasedContainerEntryName = aliasEntry->name + ALIAS_CONTAINER_SUFFIX;
829
1/2
✓ Branch 6 → 7 taken 12749 times.
✗ Branch 6 → 15 not taken.
12749 const SymbolTableEntry *aliasedTypeContainerEntry = aliasEntry->scope->lookupStrict(aliasedContainerEntryName);
830
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 12749 times.
12749 assert(aliasedTypeContainerEntry != nullptr);
831
1/2
✓ Branch 11 → 12 taken 12749 times.
✗ Branch 11 → 15 not taken.
25498 return aliasedTypeContainerEntry->getQualType();
832 12749 }
833
834 /**
835 * Remove reference of this type, if it is a reference
836 *
837 * @return New type
838 */
839
2/2
✓ Branch 3 → 4 taken 68639 times.
✓ Branch 3 → 5 taken 1592239 times.
1660878 QualType QualType::removeReferenceWrapper() const { return isRef() ? getContained() : *this; }
840
841 /**
842 * Auto-dereference the given symbol type (peeling off all ptr/ref wrappers).
843 * This process is NOT equivalent with getBase() because getBase() also removes e.g. array wrappers
844 *
845 * @return New type
846 */
847 215712 QualType QualType::autoDeReference() const {
848 215712 QualType newType = *this;
849
3/4
✓ Branch 5 → 6 taken 396801 times.
✗ Branch 5 → 10 not taken.
✓ Branch 6 → 3 taken 181089 times.
✓ Branch 6 → 7 taken 215712 times.
396801 while (newType.isOneOf({TY_PTR, TY_REF}))
850
1/2
✓ Branch 3 → 4 taken 181089 times.
✗ Branch 3 → 9 not taken.
181089 newType = newType.getContained();
851 215712 return newType;
852 }
853
854 /**
855 * Replace the base type with another one
856 *
857 * @param newBaseType New base type
858 * @return New type
859 */
860 158200 QualType QualType::replaceBaseType(const QualType &newBaseType) const {
861 // Create new type
862
1/2
✓ Branch 3 → 4 taken 158200 times.
✗ Branch 3 → 8 not taken.
158200 const Type *newType = type->replaceBase(newBaseType.getType());
863 // Create new qualifiers
864
1/2
✓ Branch 4 → 5 taken 158200 times.
✗ Branch 4 → 8 not taken.
158200 TypeQualifiers newQualifiers = qualifiers.merge(newBaseType.qualifiers);
865 // Return the new qualified type
866 158200 return {newType, newQualifiers};
867 }
868
869 /**
870 * Retrieve the same type, but with lambda captures enabled
871 *
872 * @return Same type with lambda captures
873 */
874 279 QualType QualType::getWithLambdaCaptures(bool enabled /*=true*/) const {
875 // Create new type
876 279 const Type *newType = type->getWithLambdaCaptures(enabled);
877 // Return the new qualified type
878 279 return {newType, qualifiers};
879 }
880
881 /**
882 * Retrieve the same type, but with a new body scope
883 *
884 * @return Same type with body scope
885 */
886 256473 QualType QualType::getWithBodyScope(Scope *bodyScope) const {
887 // Create new type
888 256473 const Type *newType = type->getWithBodyScope(bodyScope);
889 // Return the new qualified type
890 256473 return {newType, qualifiers};
891 }
892
893 /**
894 * Retrieve the same type, but with new template types
895 *
896 * @param templateTypes New template types
897 * @return Same type with new template types
898 */
899 33516 QualType QualType::getWithTemplateTypes(const QualTypeList &templateTypes) const {
900 // Create new type
901 33516 const Type *newType = type->getWithTemplateTypes(templateTypes);
902 // Return the new qualified type
903 33516 return {newType, qualifiers};
904 }
905
906 /**
907 * Retrieve the same type, but with new base template types
908 *
909 * @param templateTypes New base template types
910 * @return Same type with new base template types
911 */
912 48399 QualType QualType::getWithBaseTemplateTypes(const QualTypeList &templateTypes) const {
913 // Create new type
914 48399 const Type *newType = type->getWithBaseTemplateTypes(templateTypes);
915 // Return the new qualified type
916 48399 return {newType, qualifiers};
917 }
918
919 /**
920 * Retrieve the same type, but with new function parameter and return types
921 *
922 * @param paramAndReturnTypes New parameter types
923 * @return Same type with new parameter types
924 */
925 97057 QualType QualType::getWithFunctionParamAndReturnTypes(const QualTypeList &paramAndReturnTypes) const {
926 // Create new type
927 97057 const Type *newType = type->getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
928 // Return the new qualified type
929 97057 return {newType, qualifiers};
930 }
931
932 /**
933 * Retrieve the same type, but with new function parameter and return types
934 *
935 * @param returnType New return type
936 * @param paramTypes New parameter types
937 * @return Same type with new parameter types
938 */
939 96959 QualType QualType::getWithFunctionParamAndReturnTypes(const QualType &returnType, const QualTypeList &paramTypes) const {
940
1/2
✓ Branch 2 → 3 taken 96959 times.
✗ Branch 2 → 17 not taken.
96959 QualTypeList paramAndReturnTypes = paramTypes;
941
1/2
✓ Branch 7 → 8 taken 96959 times.
✗ Branch 7 → 13 not taken.
193918 paramAndReturnTypes.insert(paramAndReturnTypes.begin(), returnType);
942
1/2
✓ Branch 8 → 9 taken 96959 times.
✗ Branch 8 → 15 not taken.
193918 return getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
943 96959 }
944
945 /**
946 * Check if the current type is const
947 *
948 * Examples for const types:
949 * - const int
950 * - const TestStruct
951 * - const string
952 *
953 * Examples for non-const types:
954 * - double (reason: not marked const)
955 * - const int* (reason: pointer to const int is not const itself)
956 * - const TestStruct& (reason: reference to const TestStruct is not const itself)
957 *
958 * @return Is const or not
959 */
960
4/4
✓ Branch 3 → 4 taken 211294 times.
✓ Branch 3 → 6 taken 78775 times.
✓ Branch 4 → 5 taken 31272 times.
✓ Branch 4 → 6 taken 180022 times.
290069 bool QualType::isConst() const { return isExtendedPrimitive() && qualifiers.isConst; }
961
962 /**
963 * Check if the current type is marked signed
964 *
965 * @return Is signed or not
966 */
967 181445 bool QualType::isSigned() const {
968
2/4
✓ Branch 2 → 3 taken 181445 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 181445 times.
181445 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
969 181445 return qualifiers.isSigned;
970 }
971
972 /**
973 * Check if the current type is marked unsigned
974 *
975 * @return Is unsigned or not
976 */
977 4 bool QualType::isUnsigned() const {
978
2/4
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
979 4 return qualifiers.isUnsigned;
980 }
981
982 /**
983 * Check if the current type is marked inline
984 *
985 * @return Is inline or not
986 */
987 85424 bool QualType::isInline() const {
988
2/4
✓ Branch 2 → 3 taken 85424 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 85424 times.
85424 assert(isOneOf({TY_FUNCTION, TY_PROCEDURE}));
989 85424 return qualifiers.isInline;
990 }
991
992 /**
993 * Check if the current type is marked public
994 *
995 * @return Is public or not
996 */
997 252431 bool QualType::isPublic() const {
998
5/8
✓ Branch 2 → 3 taken 252431 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 243003 times.
✓ Branch 3 → 7 taken 9428 times.
✓ Branch 4 → 5 taken 243003 times.
✗ Branch 4 → 9 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 243003 times.
252431 assert(type->isPrimitive() /* Global variables */ ||
999 isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE, TY_UNION}));
1000 252431 return qualifiers.isPublic;
1001 }
1002
1003 /**
1004 * Check if the current type is marked heap
1005 *
1006 * @return Is heap or not
1007 */
1008 146830 bool QualType::isHeap() const { return qualifiers.isHeap; }
1009
1010 /**
1011 * Check if the current type is marked as composition
1012 *
1013 * @return Is composition or not
1014 */
1015 7388 bool QualType::isComposition() const { return qualifiers.isComposition; }
1016
1017 /**
1018 * Make the current type const
1019 *
1020 * @param isConst Is const or not
1021 */
1022 56221 void QualType::makeConst(bool isConst) { qualifiers.isConst = isConst; }
1023
1024 /**
1025 * Make the current type unsigned
1026 *
1027 * @param isUnsigned Is unsigned or not
1028 */
1029 541 void QualType::makeUnsigned(bool isUnsigned) {
1030
2/4
✓ Branch 2 → 3 taken 541 times.
✗ Branch 2 → 6 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 541 times.
541 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
1031 541 qualifiers.isSigned = !isUnsigned;
1032 541 qualifiers.isUnsigned = isUnsigned;
1033 541 }
1034
1035 /**
1036 * Make the current type public
1037 *
1038 * @param isPublic Is public or not
1039 */
1040 8176 void QualType::makePublic(bool isPublic) {
1041
4/8
✓ Branch 2 → 3 taken 8176 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 8176 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 8176 times.
✗ Branch 4 → 8 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 8176 times.
8176 assert(type->isPrimitive() /* Global variables */ ||
1042 isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE, TY_UNION}));
1043 8176 qualifiers.isPublic = isPublic;
1044 8176 }
1045
1046 /**
1047 * Make the current type heap
1048 *
1049 * @param isHeap Is heap or not
1050 */
1051 2878 void QualType::makeHeap(bool isHeap) { qualifiers.isHeap = isHeap; }
1052
1053 /**
1054 * Check if two types are equal
1055 *
1056 * @param lhs Left-hand side type
1057 * @param rhs Right-hand side type
1058 * @return Equal or not
1059 */
1060 8574714 bool operator==(const QualType &lhs, const QualType &rhs) { return lhs.type == rhs.type; }
1061
1062 /**
1063 * Check if two types are not equal
1064 *
1065 * @param lhs Left-hand side type
1066 * @param rhs Right-hand side type
1067 * @return Not equal or not
1068 */
1069 1388439 bool operator!=(const QualType &lhs, const QualType &rhs) { return !(lhs == rhs); }
1070
1071 /**
1072 * Remove pointers / arrays / references if both types have them as far as possible.
1073 *
1074 * @param typeA Candidate type
1075 * @param typeB Requested type
1076 */
1077 16346 void QualType::unwrapBoth(QualType &typeA, QualType &typeB) { Type::unwrapBoth(typeA.type, typeB.type); }
1078
1079 /**
1080 * Remove pointers / arrays / references if both types have them as far as possible.
1081 * Furthermore, remove reference wrappers if possible.
1082 *
1083 * @param typeA Candidate type
1084 * @param typeB Requested type
1085 */
1086 799157 void QualType::unwrapBothWithRefWrappers(QualType &typeA, QualType &typeB) {
1087 799157 Type::unwrapBothWithRefWrappers(typeA.type, typeB.type);
1088 799157 }
1089
1090 } // namespace spice::compiler
1091