GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.1% 299 / 0 / 308
Functions: 97.8% 89 / 0 / 91
Branches: 63.4% 265 / 0 / 418

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 <symboltablebuilder/Scope.h>
13 #include <symboltablebuilder/SymbolTableBuilder.h>
14 #include <symboltablebuilder/Type.h>
15 #include <typechecker/FunctionManager.h>
16 #include <typechecker/InterfaceManager.h>
17 #include <typechecker/StructManager.h>
18
19 namespace spice::compiler {
20
21 3604862 QualType::QualType(SuperType superType) : type(TypeRegistry::getOrInsert(superType)), qualifiers(TypeQualifiers::of(superType)) {}
22 5776 QualType::QualType(SuperType superType, const std::string &subType)
23 5776 : type(TypeRegistry::getOrInsert(superType, subType)), qualifiers(TypeQualifiers::of(superType)) {}
24 257944 QualType::QualType(const Type *type, TypeQualifiers qualifiers) : type(type), qualifiers(qualifiers) {}
25
26 /**
27 * Get the super type of the underlying type
28 *
29 * @return Super type
30 */
31 3420639 SuperType QualType::getSuperType() const { return type->getSuperType(); }
32
33 /**
34 * Get the subtype of the underlying type
35 *
36 * @return Subtype
37 */
38 923554 const std::string &QualType::getSubType() const { return type->getSubType(); }
39
40 /**
41 * Get the array size of the underlying type
42 *
43 * @return Array size
44 */
45 977 unsigned int QualType::getArraySize() const { return type->getArraySize(); }
46
47 /**
48 * Get the body scope of the underlying type
49 *
50 * @return Body scope
51 */
52 2660181 Scope *QualType::getBodyScope() const { return type->getBodyScope(); }
53
54 /**
55 * Get the function parameter types of the underlying type
56 *
57 * @return Function parameter types
58 */
59 49 const QualType &QualType::getFunctionReturnType() const { return type->getFunctionReturnType(); }
60
61 /**
62 * Get the function parameter types of the underlying type
63 *
64 * @return Function parameter types
65 */
66 350 QualTypeList QualType::getFunctionParamTypes() const { return type->getFunctionParamTypes(); }
67
68 /**
69 * Get the function parameter and return types of the underlying type
70 *
71 * @return Function parameter and return types
72 */
73 153 const QualTypeList &QualType::getFunctionParamAndReturnTypes() const { return type->getFunctionParamAndReturnTypes(); }
74
75 /**
76 * Check if the underlying type has lambda captures
77 *
78 * @return Has lambda captures or not
79 */
80 287 bool QualType::hasLambdaCaptures() const { return type->hasLambdaCaptures(); }
81
82 /**
83 * Get the template types of the underlying type
84 *
85 * @return Template types
86 */
87 385111 const QualTypeList &QualType::getTemplateTypes() const { return type->getTemplateTypes(); }
88
89 /**
90 * Get the struct instance for a struct type
91 *
92 * @param node Accessing AST node
93 * @param templateTypes Custom set of template types
94 * @return Struct instance
95 */
96 77903 Struct *QualType::getStruct(const ASTNode *node, const QualTypeList &templateTypes) const {
97
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 77903 times.
77903 assert(is(TY_STRUCT));
98 77903 Scope *structDefScope = getBodyScope()->parent;
99 77903 const std::string &structName = getSubType();
100 77903 return StructManager::match(structDefScope, structName, templateTypes, node);
101 }
102
103 /**
104 * Get the struct instance for a struct type
105 *
106 * @param node Accessing AST node
107 * @return Struct instance
108 */
109 46742 Struct *QualType::getStruct(const ASTNode *node) const { return getStruct(node, type->getTemplateTypes()); }
110
111 /**
112 * Get the struct instance for a struct type
113 * Adopt information from the struct to this type.
114 *
115 * @param node Accessing AST node
116 * @param templateTypes Custom set of template types
117 * @return Struct instance
118 */
119 1310 Struct *QualType::getStructAndAdjustType(const ASTNode *node, const QualTypeList &templateTypes) {
120 1310 Struct *spiceStruct = getStruct(node, templateTypes);
121
2/4
✓ Branch 4 → 5 taken 1310 times.
✗ Branch 4 → 11 not taken.
✓ Branch 5 → 6 taken 1310 times.
✗ Branch 5 → 9 not taken.
1310 type = type->getWithBodyScope(spiceStruct->scope)->getWithTemplateTypes(spiceStruct->getTemplateTypes());
122 1310 return spiceStruct;
123 }
124
125 /**
126 * Get the struct instance for a struct type
127 * Adopt information from the struct to this type.
128 *
129 * @param node Accessing AST node
130 * @return Struct instance
131 */
132 Struct *QualType::getStructAndAdjustType(const ASTNode *node) { return getStructAndAdjustType(node, type->getTemplateTypes()); }
133
134 /**
135 * Get the interface instance for an interface type
136 *
137 * @param node Accessing AST node
138 * @param templateTypes Custom set of template types
139 * @return Interface instance
140 */
141 7486 Interface *QualType::getInterface(const ASTNode *node, const QualTypeList &templateTypes) const {
142
2/4
✓ Branch 2 → 3 taken 7486 times.
✗ Branch 2 → 15 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 7486 times.
7486 assert(is(TY_INTERFACE));
143
1/2
✓ Branch 5 → 6 taken 7486 times.
✗ Branch 5 → 15 not taken.
7486 Scope *interfaceDefScope = getBodyScope()->parent;
144
2/4
✓ Branch 6 → 7 taken 7486 times.
✗ Branch 6 → 15 not taken.
✓ Branch 7 → 8 taken 7486 times.
✗ Branch 7 → 15 not taken.
7486 const std::string structName = getSubType();
145
1/2
✓ Branch 8 → 9 taken 7486 times.
✗ Branch 8 → 13 not taken.
14972 return InterfaceManager::match(interfaceDefScope, structName, templateTypes, node);
146 7486 }
147
148 /**
149 * Get the interface instance for an interface type
150 *
151 * @param node Accessing AST node
152 * @return Interface instance
153 */
154 4662 Interface *QualType::getInterface(const ASTNode *node) const { return getInterface(node, type->getTemplateTypes()); }
155
156 /**
157 * Check if the underlying type is of a certain super type
158 *
159 * @param superType Super type
160 * @return Is of super type or not
161 */
162 11842801 bool QualType::is(SuperType superType) const { return type->is(superType); }
163
164 /**
165 * Check if the underlying type is one of a list of super types
166 *
167 * @param superTypes List of super types
168 * @return Is one of the super types or not
169 */
170 2244038 bool QualType::isOneOf(const std::initializer_list<SuperType> &superTypes) const { return type->isOneOf(superTypes); }
171
172 /**
173 * Check if the base type of the underlying type is a certain super type
174 *
175 * @param superType Super type
176 * @return Is base type or not
177 */
178 15346102 bool QualType::isBase(SuperType superType) const { return type->isBase(superType); }
179
180 /**
181 * Check if the underlying type is a primitive type
182 * Note: enum types are mapped to int, so they are also count as primitive types.
183 *
184 * @return Primitive or not
185 */
186 2372 bool QualType::isPrimitive() const { return type->isPrimitive(); }
187
188 /**
189 * Check if the underlying type is an extended primitive type
190 * The definition of extended primitive types contains all primitive types plus the following:
191 * - structs
192 * - interfaces
193 * - functions/procedures
194 *
195 * @return Extended primitive or not
196 */
197 248918 bool QualType::isExtendedPrimitive() const { return type->isExtendedPrimitive(); }
198
199 /**
200 * Check if the underlying type is a pointer
201 *
202 * @return Pointer or not
203 */
204 1021330 bool QualType::isPtr() const { return type->isPtr(); }
205
206 /**
207 * Check if the underlying type is a pointer to a certain super type
208 *
209 * @param superType Super type
210 * @return Pointer to super type or not
211 */
212
7/10
✓ Branch 2 → 3 taken 495746 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 49452 times.
✓ Branch 3 → 8 taken 446294 times.
✓ Branch 4 → 5 taken 49452 times.
✗ Branch 4 → 11 not taken.
✓ Branch 5 → 6 taken 49452 times.
✗ Branch 5 → 11 not taken.
✓ Branch 6 → 7 taken 14640 times.
✓ Branch 6 → 8 taken 34812 times.
495746 bool QualType::isPtrTo(SuperType superType) const { return isPtr() && getContained().is(superType); }
213
214 /**
215 * Check if the underlying type is a reference
216 *
217 * @return Reference or not
218 */
219 1467485 bool QualType::isRef() const { return type->isRef(); }
220
221 /**
222 * Check if the underlying type is a reference to a certain super type
223 *
224 * @param superType Super type
225 * @return Reference to super type or not
226 */
227 bool QualType::isRefTo(SuperType superType) const { return isRef() && getContained().is(superType); }
228
229 /**
230 * Check if the underlying type is an array
231 *
232 * @return Array or not
233 */
234 120769 bool QualType::isArray() const { return type->isArray(); }
235
236 /**
237 * Check if the underlying type is an array of a certain super type
238 *
239 * @param superType Super type
240 * @return Array of super type or not
241 */
242
2/10
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 11 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 8 taken 1 time.
✗ 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.
1 bool QualType::isArrayOf(SuperType superType) const { return isArray() && getContained().is(superType); }
243
244 /**
245 * Check if the underlying type is a const reference
246 *
247 * @return Const reference or not
248 */
249
4/4
✓ Branch 2 → 3 taken 25787 times.
✓ Branch 2 → 6 taken 5129 times.
✓ Branch 4 → 5 taken 25484 times.
✓ Branch 4 → 6 taken 303 times.
30916 bool QualType::isConstRef() const { return qualifiers.isConst && isRef(); }
250
251 /**
252 * Check if the current type is an iterator
253 *
254 * @param node ASTNode
255 * @return Iterator or not
256 */
257 667 bool QualType::isIterator(const ASTNode *node) const {
258 // The type must be a struct that implements the iterator interface
259
3/4
✓ Branch 2 → 3 taken 667 times.
✗ Branch 2 → 47 not taken.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 666 times.
667 if (!is(TY_STRUCT))
260 1 return false;
261
262
2/4
✓ Branch 7 → 8 taken 666 times.
✗ Branch 7 → 30 not taken.
✓ Branch 8 → 9 taken 666 times.
✗ Branch 8 → 28 not taken.
1332 const QualType genericType(TY_GENERIC, "T");
263 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
264
3/6
✓ Branch 13 → 14 taken 666 times.
✗ Branch 13 → 42 not taken.
✓ Branch 16 → 17 taken 666 times.
✗ Branch 16 → 36 not taken.
✓ Branch 17 → 18 taken 666 times.
✗ Branch 17 → 34 not taken.
2664 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERATOR_INTERFACE, data, {genericType});
265
1/2
✓ Branch 22 → 23 taken 666 times.
✗ Branch 22 → 47 not taken.
666 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
266
1/2
✓ Branch 24 → 25 taken 666 times.
✗ Branch 24 → 47 not taken.
666 return doesImplement(iteratorQualType, node);
267 }
268
269 /**
270 * Check if the current type is an iterable
271 * - Arrays are always considered iterable
272 * - Otherwise the type must be a struct that implements the iterator interface
273 *
274 * @param node ASTNode
275 * @return Iterable or not
276 */
277 669 bool QualType::isIterable(const ASTNode *node) const {
278 // Arrays are always considered iterable
279
3/4
✓ Branch 2 → 3 taken 669 times.
✗ Branch 2 → 50 not taken.
✓ Branch 3 → 4 taken 19 times.
✓ Branch 3 → 5 taken 650 times.
669 if (isArray())
280 19 return true;
281 // Otherwise the type must be a struct that implements the iterator interface
282
3/4
✓ Branch 5 → 6 taken 650 times.
✗ Branch 5 → 50 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 649 times.
650 if (!is(TY_STRUCT))
283 1 return false;
284
285
2/4
✓ Branch 10 → 11 taken 649 times.
✗ Branch 10 → 33 not taken.
✓ Branch 11 → 12 taken 649 times.
✗ Branch 11 → 31 not taken.
1298 const QualType genericType(TY_GENERIC, "T");
286 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
287
3/6
✓ Branch 16 → 17 taken 649 times.
✗ Branch 16 → 45 not taken.
✓ Branch 19 → 20 taken 649 times.
✗ Branch 19 → 39 not taken.
✓ Branch 20 → 21 taken 649 times.
✗ Branch 20 → 37 not taken.
2596 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERABLE_INTERFACE, data, {genericType});
288
1/2
✓ Branch 25 → 26 taken 649 times.
✗ Branch 25 → 50 not taken.
649 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
289
1/2
✓ Branch 27 → 28 taken 649 times.
✗ Branch 27 → 50 not taken.
649 return doesImplement(iteratorQualType, node);
290 }
291
292 /**
293 * Check if the current type is a string object
294 *
295 * @return String object or not
296 */
297 1036 bool QualType::isStringObj() const {
298
5/6
✓ Branch 3 → 4 taken 163 times.
✓ Branch 3 → 10 taken 873 times.
✓ Branch 6 → 7 taken 162 times.
✓ Branch 6 → 10 taken 1 time.
✓ Branch 8 → 9 taken 162 times.
✗ Branch 8 → 10 not taken.
1036 return is(TY_STRUCT) && getSubType() == STROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
299 }
300
301 /**
302 * Check if the current type is an error object
303 *
304 * @return Error object or not
305 */
306 2233 bool QualType::isErrorObj() const {
307
4/6
✓ Branch 3 → 4 taken 2232 times.
✓ Branch 3 → 10 taken 1 time.
✓ Branch 6 → 7 taken 2232 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 2232 times.
✗ Branch 8 → 10 not taken.
2233 return is(TY_STRUCT) && getSubType() == ERROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
308 }
309
310 /**
311 * Check if the current type has any generic parts
312 *
313 * @return Generic parts or not
314 */
315 1350538 bool QualType::hasAnyGenericParts() const { return type->hasAnyGenericParts(); }
316
317 /**
318 * Check if constructing an instance of the current type would require calling a ctor.
319 * If this function return true, the type does not need to be constructed.
320 *
321 * @param node Accessing ASTNode
322 * @return Trivially constructible or not
323 */
324 2549 bool QualType::isTriviallyConstructible(const ASTNode *node) const {
325 // Heap-allocated values require manual allocation, which is done in the default/explicit ctor
326
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 2548 times.
2549 if (qualifiers.isHeap)
327 1 return false;
328
329 // References can't be default initialized
330
2/2
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 2545 times.
2548 if (isRef())
331 3 return false;
332
333 // In case of an array, the item type is determining the construction triviality
334
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 13 taken 2545 times.
2545 if (isArray())
335 return getBase().isTriviallyConstructible(node);
336
337 // In case of a struct, the member types determine the construction triviality
338
2/2
✓ Branch 14 → 15 taken 2430 times.
✓ Branch 14 → 34 taken 115 times.
2545 if (is(TY_STRUCT)) {
339 // If the struct has a ctor, it is a non-trivially constructible one
340
1/2
✓ Branch 15 → 16 taken 2430 times.
✗ Branch 15 → 37 not taken.
2430 const Struct *spiceStruct = getStruct(node);
341
3/4
✓ Branch 16 → 17 taken 2430 times.
✗ Branch 16 → 37 not taken.
✓ Branch 17 → 18 taken 2328 times.
✓ Branch 17 → 19 taken 102 times.
2430 if (FunctionManager::hasAnyNonCopyCtor(spiceStruct->scope))
342 2328 return false;
343
344 // If the struct emits a vtable, it is non-trivially constructible, because the vtable needs to be initialized in the ctor
345
1/2
✓ Branch 19 → 20 taken 102 times.
✗ Branch 19 → 21 not taken.
102 const auto *structDefNode = spice_pointer_cast<StructDefNode *>(spiceStruct->declNode);
346
2/2
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 28 taken 101 times.
102 if (structDefNode->emitVTable)
347 1 return false;
348
349 // If any field has a default value, the struct is non-trivially constructible
350 135 const auto pred1 = [&](const FieldNode *fieldNode) { return fieldNode->defaultValue != nullptr; };
351
3/4
✓ Branch 28 → 29 taken 101 times.
✗ Branch 28 → 37 not taken.
✓ Branch 29 → 30 taken 5 times.
✓ Branch 29 → 31 taken 96 times.
101 if (std::ranges::any_of(structDefNode->fields, pred1))
352 5 return false;
353
354 // Check if all member types are trivially constructible
355 130 const auto pred2 = [&](const QualType &fieldType) { return fieldType.isTriviallyConstructible(node); };
356
1/2
✓ Branch 31 → 32 taken 96 times.
✗ Branch 31 → 37 not taken.
96 return std::ranges::all_of(spiceStruct->fieldTypes, pred2);
357 }
358
359 115 return true;
360 }
361
362 /**
363 * Check if copying an instance of the current type would require a call to the copy ctor.
364 * If this function return true, the type can be copied by calling memcpy.
365 *
366 * @param node Accessing ASTNode
367 * @return Trivially copyable or not
368 */
369 10173 bool QualType::isTriviallyCopyable(const ASTNode *node) const { // NOLINT(*-no-recursion)
370 // Heap-allocated values may not be copied via memcpy
371
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 10173 times.
10173 if (qualifiers.isHeap)
372 return false;
373
374 // In case of an array, the item type is determining the copy triviality
375
2/2
✓ Branch 5 → 6 taken 20 times.
✓ Branch 5 → 10 taken 10153 times.
10173 if (isArray())
376
2/4
✓ Branch 6 → 7 taken 20 times.
✗ Branch 6 → 21 not taken.
✓ Branch 7 → 8 taken 20 times.
✗ Branch 7 → 21 not taken.
20 return getBase().isTriviallyCopyable(node);
377
378 // In case of a struct, the member types determine the copy triviality
379
2/2
✓ Branch 11 → 12 taken 3861 times.
✓ Branch 11 → 19 taken 6292 times.
10153 if (is(TY_STRUCT)) {
380 // If the struct has a copy ctor, it is a non-trivially copyable one
381
1/2
✓ Branch 12 → 13 taken 3861 times.
✗ Branch 12 → 22 not taken.
3861 const Struct *spiceStruct = getStruct(node);
382
3/4
✓ Branch 13 → 14 taken 3861 times.
✗ Branch 13 → 22 not taken.
✓ Branch 14 → 15 taken 2122 times.
✓ Branch 14 → 16 taken 1739 times.
3861 if (FunctionManager::hasCopyCtor(spiceStruct->scope))
383 2122 return false;
384
385 // Check if all member types are trivially copyable
386 5703 const auto pred = [&](const QualType &fieldType) { return fieldType.isTriviallyCopyable(node); }; // NOLINT(*-no-recursion)
387
1/2
✓ Branch 16 → 17 taken 1739 times.
✗ Branch 16 → 22 not taken.
1739 return std::ranges::all_of(spiceStruct->fieldTypes, pred);
388 }
389
390 6292 return true;
391 }
392
393 /**
394 * Check if destructing an instance of the current type would require calling a dtor.
395 * If this function return true, the type does not need to be destructed.
396 *
397 * @param node Accessing ASTNode
398 * @return Trivially destructible or not
399 */
400 36111 bool QualType::isTriviallyDestructible(const ASTNode *node) const {
401 // Heap-allocated values require manual de-allocation, which is done in the default/explicit dtor
402
2/2
✓ Branch 2 → 3 taken 1853 times.
✓ Branch 2 → 4 taken 34258 times.
36111 if (qualifiers.isHeap)
403 1853 return false;
404
405 // In case of an array, the item type is determining the destructing triviality
406
2/2
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 10 taken 34253 times.
34258 if (isArray())
407
2/4
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 21 not taken.
✓ Branch 7 → 8 taken 5 times.
✗ Branch 7 → 21 not taken.
5 return getBase().isTriviallyDestructible(node);
408
409 // In case of a struct, the member types determine the destructing triviality
410
2/2
✓ Branch 11 → 12 taken 17773 times.
✓ Branch 11 → 19 taken 16480 times.
34253 if (is(TY_STRUCT)) {
411 // If the struct has a dtor, it is a non-trivially destructible one
412
1/2
✓ Branch 12 → 13 taken 17773 times.
✗ Branch 12 → 22 not taken.
17773 const Struct *spiceStruct = getStruct(node);
413
3/4
✓ Branch 13 → 14 taken 17773 times.
✗ Branch 13 → 22 not taken.
✓ Branch 14 → 15 taken 8159 times.
✓ Branch 14 → 16 taken 9614 times.
17773 if (FunctionManager::hasDtor(spiceStruct->scope))
414 8159 return false;
415
416 // Check if all member types are trivially destructible
417 29243 const auto pred = [&](const QualType &fieldType) {
418 19629 return fieldType.isTriviallyDestructible(node);
419 9614 }; // NOLINT(*-no-recursion)
420
1/2
✓ Branch 16 → 17 taken 9614 times.
✗ Branch 16 → 22 not taken.
9614 return std::ranges::all_of(spiceStruct->fieldTypes, pred);
421 }
422
423 16480 return true;
424 }
425
426 /**
427 * Check if the current type implements the given interface type
428 *
429 * @param implementedInterfaceType Interface type
430 * @param node Accessing ASTNode
431 * @return Struct implements interface or not
432 */
433 1316 bool QualType::doesImplement(const QualType &implementedInterfaceType, const ASTNode *node) const {
434
2/4
✓ Branch 3 → 4 taken 1316 times.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 1316 times.
✗ Branch 5 → 7 not taken.
1316 assert(is(TY_STRUCT) && implementedInterfaceType.is(TY_INTERFACE));
435 1316 const Struct *spiceStruct = getStruct(node);
436
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 1316 times.
1316 assert(spiceStruct != nullptr);
437 1316 return std::ranges::any_of(spiceStruct->interfaceTypes, [&](const QualType &interfaceType) {
438
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1316 times.
1316 assert(interfaceType.is(TY_INTERFACE));
439 1316 return implementedInterfaceType.matches(interfaceType, false, false, true);
440 1316 });
441 }
442
443 /**
444 * Check if a certain input type can be bound (assigned) to the current type.
445 *
446 * @param inputType Qualified type, which should be bound to the current type
447 * @param isTemporary Is the input type a temporary type
448 * @return Can be bound or not
449 */
450 41929 bool QualType::canBind(const QualType &inputType, bool isTemporary) const {
451
8/8
✓ Branch 2 → 3 taken 10360 times.
✓ Branch 2 → 9 taken 31569 times.
✓ Branch 4 → 5 taken 9844 times.
✓ Branch 4 → 9 taken 516 times.
✓ Branch 6 → 7 taken 1216 times.
✓ Branch 6 → 9 taken 8628 times.
✓ Branch 8 → 9 taken 1214 times.
✓ Branch 8 → 10 taken 2 times.
41929 return !isTemporary || inputType.type->isRef() || !type->isRef() || isConstRef();
452 }
453
454 /**
455 * Check for the matching compatibility of two types.
456 * Useful for struct and function matching as well as assignment type validation and function arg matching.
457 *
458 * @param otherType Type to compare against
459 * @param ignoreArraySize Ignore array sizes
460 * @param ignoreQualifiers Ignore qualifiers, except for pointer and reference types
461 * @param allowConstify Match when the types are the same, but the lhs type is more const restrictive than the rhs type
462 * @return Matching or not
463 */
464 379446 bool QualType::matches(const QualType &otherType, bool ignoreArraySize, bool ignoreQualifiers, bool allowConstify) const {
465 // Special case: string is equivalent to const char*
466
6/8
✓ Branch 3 → 4 taken 41162 times.
✓ Branch 3 → 9 taken 338284 times.
✓ Branch 5 → 6 taken 2286 times.
✓ Branch 5 → 9 taken 38876 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 2286 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 379446 times.
379446 if (is(TY_STRING) && otherType.isPtrTo(TY_CHAR) && otherType.isConst())
467 return true;
468
4/8
✓ Branch 13 → 14 taken 10526 times.
✓ Branch 13 → 19 taken 368920 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 19 taken 10526 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 379446 times.
379446 if (isPtrTo(TY_CHAR) && isConst() && otherType.is(TY_STRING))
469 return true;
470
471 // Compare type
472
2/2
✓ Branch 23 → 24 taken 143703 times.
✓ Branch 23 → 25 taken 235743 times.
379446 if (!type->matches(otherType.type, ignoreArraySize))
473 143703 return false;
474
475 // Ignore or compare qualifiers
476
4/4
✓ Branch 25 → 26 taken 62264 times.
✓ Branch 25 → 28 taken 173479 times.
✓ Branch 27 → 28 taken 61754 times.
✓ Branch 27 → 29 taken 510 times.
235743 return ignoreQualifiers || qualifiers.match(otherType.qualifiers, allowConstify);
477 }
478
479 /**
480 * Check for the matching compatibility of two types in terms of interface implementation.
481 * Useful for function matching as well as assignment type validation and function arg matching.
482 *
483 * @param structType Type to compare against
484 * @return Matching or not
485 */
486 190190 bool QualType::matchesInterfaceImplementedByStruct(const QualType &structType) const {
487
8/10
✓ Branch 2 → 3 taken 190190 times.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 2122 times.
✓ Branch 3 → 6 taken 188068 times.
✓ Branch 4 → 5 taken 2122 times.
✗ Branch 4 → 17 not taken.
✓ Branch 5 → 6 taken 822 times.
✓ Branch 5 → 7 taken 1300 times.
✓ Branch 8 → 9 taken 188890 times.
✓ Branch 8 → 10 taken 1300 times.
190190 if (!is(TY_INTERFACE) || !structType.is(TY_STRUCT))
488 188890 return false;
489
490 // Check if the rhs is a struct type that implements the lhs interface type
491
1/2
✓ Branch 10 → 11 taken 1300 times.
✗ Branch 10 → 17 not taken.
1300 const Struct *spiceStruct = structType.getStruct(nullptr);
492
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1300 times.
1300 assert(spiceStruct != nullptr);
493 1262 const auto pred = [&](const QualType &interfaceType) { return matches(interfaceType, false, false, true); };
494
1/2
✓ Branch 13 → 14 taken 1300 times.
✗ Branch 13 → 17 not taken.
1300 return std::ranges::any_of(spiceStruct->interfaceTypes, pred);
495 }
496
497 /**
498 * Check if the current (struct) type is a base of the given struct type, embedded via the 'compose'
499 * qualifier as its first field. The compiler does not perform implicit struct-to-composed-base upcasts;
500 * this matcher only gates the explicit 'cast<Base*>(derived)' conversion (and the matching IR pointer
501 * adjustment). Only first-field compositions are considered, because those are the ones reachable by
502 * advancing the pointer along the first-field chain. The check follows that chain transitively, so a base
503 * that is composed several levels deep is still matched.
504 */
505 6198 bool QualType::matchesComposedBaseOfStruct(const QualType &structType) const {
506
6/6
✓ Branch 3 → 4 taken 3725 times.
✓ Branch 3 → 6 taken 2473 times.
✓ Branch 5 → 6 taken 1256 times.
✓ Branch 5 → 7 taken 2469 times.
✓ Branch 8 → 9 taken 3729 times.
✓ Branch 8 → 10 taken 2469 times.
6198 if (!is(TY_STRUCT) || !structType.is(TY_STRUCT))
507 3729 return false;
508
509 2469 const Struct *spiceStruct = structType.getStruct(nullptr);
510
3/6
✓ Branch 11 → 12 taken 2469 times.
✗ Branch 11 → 14 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 2469 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 2469 times.
2469 if (spiceStruct == nullptr || spiceStruct->fieldTypes.empty())
511 return false;
512
513 // Only the first field can be a composed base that is reachable along the first-field chain
514 2469 const QualType &firstFieldType = spiceStruct->fieldTypes.front();
515
1/2
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 2469 times.
2469 if (!firstFieldType.isComposition())
516 return false;
517 // The composed field matches the requested base directly (qualifiers like 'compose' are ignored)
518
2/2
✓ Branch 23 → 24 taken 1386 times.
✓ Branch 23 → 25 taken 1083 times.
2469 if (matches(firstFieldType, false, true, true))
519 1386 return true;
520 // Otherwise follow the composition chain further down
521 1083 return matchesComposedBaseOfStruct(firstFieldType);
522 }
523
524 /**
525 * Check if the current type is the same container type as another type.
526 * Container types include arrays, pointers, and references.
527 *
528 * @param other Other type
529 * @return Same container type or not
530 */
531 7950 bool QualType::isSameContainerTypeAs(const QualType &other) const { return type->isSameContainerTypeAs(other.type); }
532
533 /**
534 * Check if the current type is a self-referencing struct type
535 *
536 * @param typeToCompareWith Type to compare with (nil on the first iteration)
537 * @return Self-referencing struct type or not
538 */
539 110859 bool QualType::isSelfReferencingStructType(const QualType *typeToCompareWith) const { // NOLINT(*-no-recursion)
540
2/2
✓ Branch 3 → 4 taken 83248 times.
✓ Branch 3 → 5 taken 27611 times.
110859 if (!is(TY_STRUCT))
541 83248 return false;
542
543 // If no type was set by a previous iteration, we set it to the current type
544
2/2
✓ Branch 5 → 6 taken 20732 times.
✓ Branch 5 → 7 taken 6879 times.
27611 if (typeToCompareWith == nullptr)
545 20732 typeToCompareWith = this;
546
547 27611 Scope *baseTypeBodyScope = getBodyScope();
548
2/2
✓ Branch 24 → 9 taken 89090 times.
✓ Branch 24 → 25 taken 26803 times.
115893 for (size_t i = 0; i < baseTypeBodyScope->getFieldCount(); i++) {
549
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 89090 times.
89090 const SymbolTableEntry *field = baseTypeBodyScope->lookupField(i);
550 89090 const QualType &fieldType = field->getQualType();
551 // Check if the base type of the field matches with the current type, which is also a base type
552 // If yes, this is a self-referencing struct type
553
3/4
✓ Branch 15 → 16 taken 89090 times.
✗ Branch 15 → 27 not taken.
✓ Branch 17 → 18 taken 808 times.
✓ Branch 17 → 19 taken 88282 times.
89090 if (fieldType.getBase() == *typeToCompareWith)
554 808 return true;
555
556 // If the field is a struct, check if it is a self-referencing struct type
557
1/2
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 88282 times.
88282 if (fieldType.isSelfReferencingStructType(typeToCompareWith))
558 return true;
559 }
560 26803 return false;
561 }
562
563 /**
564 * Check if the given generic type list has a substantiation for the current (generic) type
565 *
566 * @param genericTypeList Generic type list
567 * @return Has substantiation or not
568 */
569 66477 bool QualType::isCoveredByGenericTypeList(std::vector<GenericType> &genericTypeList) const { // NOLINT(*-no-recursion)
570
1/2
✓ Branch 2 → 3 taken 66477 times.
✗ Branch 2 → 19 not taken.
66477 const QualType baseType = getBase();
571 // Check if the symbol type itself is generic
572
3/4
✓ Branch 3 → 4 taken 66477 times.
✗ Branch 3 → 19 not taken.
✓ Branch 4 → 5 taken 10990 times.
✓ Branch 4 → 7 taken 55487 times.
66477 if (baseType.is(TY_GENERIC)) {
573
1/2
✓ Branch 5 → 6 taken 10990 times.
✗ Branch 5 → 19 not taken.
10990 return std::ranges::any_of(genericTypeList, [&](GenericType &t) {
574
2/2
✓ Branch 3 → 4 taken 10982 times.
✓ Branch 3 → 5 taken 2057 times.
13039 if (baseType.matches(t, true, true, true)) {
575 10982 t.used = true;
576 10982 return true;
577 }
578 2057 return false;
579 10990 });
580 }
581
582 // If the type is non-generic check template types
583 55487 bool covered = true;
584 // Check template types
585
1/2
✓ Branch 7 → 8 taken 55487 times.
✗ Branch 7 → 19 not taken.
55487 const QualTypeList &baseTemplateTypes = baseType.getTemplateTypes();
586 61222 auto outerPred = [&](const QualType &templateType) { // NOLINT(*-no-recursion)
587 5735 return templateType.isCoveredByGenericTypeList(genericTypeList);
588 55487 };
589
1/2
✓ Branch 8 → 9 taken 55487 times.
✗ Branch 8 → 19 not taken.
55487 covered &= std::ranges::all_of(baseTemplateTypes, outerPred);
590
591 // If function/procedure, check param and return types
592
3/4
✓ Branch 9 → 10 taken 55487 times.
✗ Branch 9 → 17 not taken.
✓ Branch 10 → 11 taken 98 times.
✓ Branch 10 → 14 taken 55389 times.
55487 if (baseType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
593
1/2
✓ Branch 11 → 12 taken 98 times.
✗ Branch 11 → 18 not taken.
98 const QualTypeList &paramAndReturnTypes = baseType.getFunctionParamAndReturnTypes();
594 288 const auto innerPred = [&](const QualType &paramType) { // NOLINT(*-no-recursion)
595 190 return paramType.isCoveredByGenericTypeList(genericTypeList);
596 98 };
597
1/2
✓ Branch 12 → 13 taken 98 times.
✗ Branch 12 → 18 not taken.
98 covered &= std::ranges::all_of(paramAndReturnTypes, innerPred);
598 }
599
600 55487 return covered;
601 }
602
603 /**
604 * Check if the current type needs de-allocation
605 *
606 * @return Needs de-allocation or not
607 */
608 4866 bool QualType::needsDeAllocation() const {
609
2/2
✓ Branch 3 → 4 taken 4688 times.
✓ Branch 3 → 5 taken 178 times.
4866 if (!isHeap())
610 4688 return false;
611 // We only need de-allocation, if we directly point to a heap-allocated type
612 // e.g. for heap TestStruct** we don't need to de-allocate, since it is a non-owning pointer to an owning pointer
613
2/4
✓ Branch 6 → 7 taken 178 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 178 times.
✗ Branch 8 → 10 not taken.
178 return isPtr() && !isPtrTo(TY_PTR);
614 }
615
616 /**
617 * Get the name of the symbol type as a string
618 *
619 * @param name Name stream
620 * @param withSize Include the array size for sized types
621 * @param ignorePublic Ignore any potential public qualifier
622 * @param withAliases Print aliases as is and not decompose them
623 */
624 2193492 void QualType::getName(std::stringstream &name, bool withSize, bool ignorePublic, bool withAliases) const {
625 // Append the qualifiers
626
3/6
✓ Branch 2 → 3 taken 2193492 times.
✗ Branch 2 → 31 not taken.
✓ Branch 3 → 4 taken 2193492 times.
✗ Branch 3 → 31 not taken.
✓ Branch 4 → 5 taken 2193492 times.
✗ Branch 4 → 31 not taken.
2193492 const TypeQualifiers defaultForSuperType = TypeQualifiers::of(getBase().getSuperType());
627
5/6
✓ Branch 5 → 6 taken 1597379 times.
✓ Branch 5 → 9 taken 596113 times.
✓ Branch 6 → 7 taken 693261 times.
✓ Branch 6 → 9 taken 904118 times.
✓ Branch 7 → 8 taken 693261 times.
✗ Branch 7 → 9 not taken.
2193492 if (!ignorePublic && qualifiers.isPublic && !defaultForSuperType.isPublic)
628
1/2
✓ Branch 8 → 9 taken 693261 times.
✗ Branch 8 → 32 not taken.
693261 name << "public ";
629
3/4
✓ Branch 9 → 10 taken 2740 times.
✓ Branch 9 → 12 taken 2190752 times.
✓ Branch 10 → 11 taken 2740 times.
✗ Branch 10 → 12 not taken.
2193492 if (qualifiers.isComposition && !defaultForSuperType.isComposition)
630
1/2
✓ Branch 11 → 12 taken 2740 times.
✗ Branch 11 → 32 not taken.
2740 name << "compose ";
631
8/8
✓ Branch 12 → 13 taken 221129 times.
✓ Branch 12 → 17 taken 1972363 times.
✓ Branch 13 → 14 taken 212204 times.
✓ Branch 13 → 17 taken 8925 times.
✓ Branch 15 → 16 taken 165530 times.
✓ Branch 15 → 17 taken 46674 times.
✓ Branch 18 → 19 taken 165530 times.
✓ Branch 18 → 20 taken 2027962 times.
2193492 if (qualifiers.isConst && !defaultForSuperType.isConst && type->typeChain.size() > 1)
632
1/2
✓ Branch 19 → 20 taken 165530 times.
✗ Branch 19 → 32 not taken.
165530 name << "const ";
633
3/4
✓ Branch 20 → 21 taken 55103 times.
✓ Branch 20 → 23 taken 2138389 times.
✓ Branch 21 → 22 taken 55103 times.
✗ Branch 21 → 23 not taken.
2193492 if (qualifiers.isHeap && !defaultForSuperType.isHeap)
634
1/2
✓ Branch 22 → 23 taken 55103 times.
✗ Branch 22 → 32 not taken.
55103 name << "heap ";
635
4/4
✓ Branch 23 → 24 taken 176653 times.
✓ Branch 23 → 26 taken 2016839 times.
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 26 taken 176652 times.
2193492 if (qualifiers.isSigned && !defaultForSuperType.isSigned)
636
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 32 not taken.
1 name << "signed ";
637
4/4
✓ Branch 26 → 27 taken 2016839 times.
✓ Branch 26 → 29 taken 176653 times.
✓ Branch 27 → 28 taken 203157 times.
✓ Branch 27 → 29 taken 1813682 times.
2193492 if (!qualifiers.isSigned && defaultForSuperType.isSigned)
638
1/2
✓ Branch 28 → 29 taken 203157 times.
✗ Branch 28 → 32 not taken.
203157 name << "unsigned ";
639
640 // Loop through all chain elements
641
1/2
✓ Branch 29 → 30 taken 2193492 times.
✗ Branch 29 → 32 not taken.
2193492 type->getName(name, withSize, ignorePublic, withAliases);
642 2193492 }
643
644 /**
645 * Get the name of the symbol type as a string
646 *
647 * @param withSize Include the array size for sized types
648 * @param ignorePublic Ignore any potential public qualifier
649 * @param withAliases Print aliases as is and not decompose them
650 * @return Symbol type name
651 */
652 969940 std::string QualType::getName(bool withSize, bool ignorePublic, bool withAliases) const {
653
1/2
✓ Branch 2 → 3 taken 969940 times.
✗ Branch 2 → 11 not taken.
969940 std::stringstream name;
654
1/2
✓ Branch 3 → 4 taken 969940 times.
✗ Branch 3 → 9 not taken.
969940 getName(name, withSize, ignorePublic, withAliases);
655
1/2
✓ Branch 4 → 5 taken 969940 times.
✗ Branch 4 → 9 not taken.
1939880 return name.str();
656 969940 }
657
658 /**
659 * Convert the type to an LLVM type
660 *
661 * @param sourceFile Source file
662 * @return LLVM type
663 */
664 1027372 llvm::Type *QualType::toLLVMType(SourceFile *sourceFile) const { return sourceFile->getLLVMType(type); }
665
666 /**
667 * Retrieve the pointer type to this type
668 *
669 * @param node ASTNode
670 * @return New type
671 */
672 94577 QualType QualType::toPtr(const ASTNode *node) const {
673 94577 QualType newType = *this;
674
2/2
✓ Branch 2 → 3 taken 94575 times.
✓ Branch 2 → 5 taken 2 times.
94577 newType.type = type->toPtr(node);
675 94575 return newType;
676 }
677
678 /**
679 * Retrieve the reference type to this type
680 *
681 * @param node ASTNode
682 * @return New type
683 */
684 43015 QualType QualType::toRef(const ASTNode *node) const {
685 43015 QualType newType = *this;
686
1/2
✓ Branch 2 → 3 taken 43015 times.
✗ Branch 2 → 5 not taken.
43015 newType.type = type->toRef(node);
687 43015 return newType;
688 }
689
690 /**
691 * Retrieve the const reference type of this type
692 *
693 * @param node ASTNode
694 * @return New type
695 */
696 19715 QualType QualType::toConstRef(const ASTNode *node) const {
697
1/2
✓ Branch 2 → 3 taken 19715 times.
✗ Branch 2 → 6 not taken.
19715 QualType newType = toRef(node);
698 19715 newType.makeConst();
699 19715 return newType;
700 }
701
702 /**
703 * Retrieve the array type of this type
704 *
705 * @param node ASTNode
706 * @param size Array size
707 * @param skipDynCheck Skip dynamic check
708 * @return New type
709 */
710 589 QualType QualType::toArr(const ASTNode *node, size_t size, bool skipDynCheck /*=false*/) const {
711 589 QualType newType = *this;
712
2/2
✓ Branch 2 → 3 taken 588 times.
✓ Branch 2 → 5 taken 1 time.
589 newType.type = type->toArr(node, size, skipDynCheck);
713 588 return newType;
714 }
715
716 /**
717 * Retrieve the non-const type of this type
718 *
719 * @return New type
720 */
721 10550 QualType QualType::toNonConst() const {
722 10550 QualType newType = *this;
723 10550 newType.qualifiers.isConst = false;
724 10550 return newType;
725 }
726
727 /**
728 * Retrieve the contained type of this type
729 * This works on pointers, arrays, references and strings (which alias with char*)
730 *
731 * @return New type
732 */
733 316745 QualType QualType::getContained() const {
734
2/4
✓ Branch 2 → 3 taken 316745 times.
✗ Branch 2 → 8 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 316745 times.
316745 assert(isOneOf({TY_PTR, TY_REF, TY_ARRAY, TY_STRING}));
735 316745 QualType newType = *this;
736
1/2
✓ Branch 5 → 6 taken 316745 times.
✗ Branch 5 → 9 not taken.
316745 newType.type = type->getContained();
737 316745 return newType;
738 }
739
740 /**
741 * Retrieve the base type of this type
742 *
743 * @return New type
744 */
745 5105451 QualType QualType::getBase() const {
746 5105451 QualType newType = *this;
747
1/2
✓ Branch 2 → 3 taken 5105451 times.
✗ Branch 2 → 5 not taken.
5105451 newType.type = type->getBase();
748 5105451 return newType;
749 }
750
751 /**
752 * Get aliased type for an alias type
753 *
754 * @param aliasEntry Entry of the alias definition
755 * @return Aliased type
756 */
757 5747 QualType QualType::getAliased(const SymbolTableEntry *aliasEntry) const {
758
2/4
✓ Branch 2 → 3 taken 5747 times.
✗ Branch 2 → 17 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5747 times.
5747 assert(is(TY_ALIAS));
759 // Get type of aliased type container entry
760
1/2
✓ Branch 5 → 6 taken 5747 times.
✗ Branch 5 → 17 not taken.
5747 const std::string aliasedContainerEntryName = aliasEntry->name + ALIAS_CONTAINER_SUFFIX;
761
1/2
✓ Branch 6 → 7 taken 5747 times.
✗ Branch 6 → 15 not taken.
5747 const SymbolTableEntry *aliasedTypeContainerEntry = aliasEntry->scope->lookupStrict(aliasedContainerEntryName);
762
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 5747 times.
5747 assert(aliasedTypeContainerEntry != nullptr);
763
1/2
✓ Branch 11 → 12 taken 5747 times.
✗ Branch 11 → 15 not taken.
11494 return aliasedTypeContainerEntry->getQualType();
764 5747 }
765
766 /**
767 * Remove reference of this type, if it is a reference
768 *
769 * @return New type
770 */
771
2/2
✓ Branch 3 → 4 taken 23472 times.
✓ Branch 3 → 5 taken 554878 times.
578350 QualType QualType::removeReferenceWrapper() const { return isRef() ? getContained() : *this; }
772
773 /**
774 * Auto-dereference the given symbol type (peeling off all ptr/ref wrappers).
775 * This process is NOT equivalent with getBase() because getBase() also removes e.g. array wrappers
776 *
777 * @return New type
778 */
779 76871 QualType QualType::autoDeReference() const {
780 76871 QualType newType = *this;
781
3/4
✓ Branch 5 → 6 taken 137682 times.
✗ Branch 5 → 10 not taken.
✓ Branch 6 → 3 taken 60811 times.
✓ Branch 6 → 7 taken 76871 times.
137682 while (newType.isOneOf({TY_PTR, TY_REF}))
782
1/2
✓ Branch 3 → 4 taken 60811 times.
✗ Branch 3 → 9 not taken.
60811 newType = newType.getContained();
783 76871 return newType;
784 }
785
786 /**
787 * Replace the base type with another one
788 *
789 * @param newBaseType New base type
790 * @return New type
791 */
792 72784 QualType QualType::replaceBaseType(const QualType &newBaseType) const {
793 // Create new type
794
1/2
✓ Branch 3 → 4 taken 72784 times.
✗ Branch 3 → 8 not taken.
72784 const Type *newType = type->replaceBase(newBaseType.getType());
795 // Create new qualifiers
796
1/2
✓ Branch 4 → 5 taken 72784 times.
✗ Branch 4 → 8 not taken.
72784 TypeQualifiers newQualifiers = qualifiers.merge(newBaseType.qualifiers);
797 // Return the new qualified type
798 72784 return {newType, newQualifiers};
799 }
800
801 /**
802 * Retrieve the same type, but with lambda captures enabled
803 *
804 * @return Same type with lambda captures
805 */
806 82 QualType QualType::getWithLambdaCaptures(bool enabled /*=true*/) const {
807 // Create new type
808 82 const Type *newType = type->getWithLambdaCaptures(enabled);
809 // Return the new qualified type
810 82 return {newType, qualifiers};
811 }
812
813 /**
814 * Retrieve the same type, but with a new body scope
815 *
816 * @return Same type with body scope
817 */
818 107331 QualType QualType::getWithBodyScope(Scope *bodyScope) const {
819 // Create new type
820 107331 const Type *newType = type->getWithBodyScope(bodyScope);
821 // Return the new qualified type
822 107331 return {newType, qualifiers};
823 }
824
825 /**
826 * Retrieve the same type, but with new template types
827 *
828 * @param templateTypes New template types
829 * @return Same type with new template types
830 */
831 14261 QualType QualType::getWithTemplateTypes(const QualTypeList &templateTypes) const {
832 // Create new type
833 14261 const Type *newType = type->getWithTemplateTypes(templateTypes);
834 // Return the new qualified type
835 14261 return {newType, qualifiers};
836 }
837
838 /**
839 * Retrieve the same type, but with new base template types
840 *
841 * @param templateTypes New base template types
842 * @return Same type with new base template types
843 */
844 22577 QualType QualType::getWithBaseTemplateTypes(const QualTypeList &templateTypes) const {
845 // Create new type
846 22577 const Type *newType = type->getWithBaseTemplateTypes(templateTypes);
847 // Return the new qualified type
848 22577 return {newType, qualifiers};
849 }
850
851 /**
852 * Retrieve the same type, but with new function parameter and return types
853 *
854 * @param paramAndReturnTypes New parameter types
855 * @return Same type with new parameter types
856 */
857 35713 QualType QualType::getWithFunctionParamAndReturnTypes(const QualTypeList &paramAndReturnTypes) const {
858 // Create new type
859 35713 const Type *newType = type->getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
860 // Return the new qualified type
861 35713 return {newType, qualifiers};
862 }
863
864 /**
865 * Retrieve the same type, but with new function parameter and return types
866 *
867 * @param returnType New return type
868 * @param paramTypes New parameter types
869 * @return Same type with new parameter types
870 */
871 35674 QualType QualType::getWithFunctionParamAndReturnTypes(const QualType &returnType, const QualTypeList &paramTypes) const {
872
1/2
✓ Branch 2 → 3 taken 35674 times.
✗ Branch 2 → 17 not taken.
35674 QualTypeList paramAndReturnTypes = paramTypes;
873
1/2
✓ Branch 7 → 8 taken 35674 times.
✗ Branch 7 → 13 not taken.
71348 paramAndReturnTypes.insert(paramAndReturnTypes.begin(), returnType);
874
1/2
✓ Branch 8 → 9 taken 35674 times.
✗ Branch 8 → 15 not taken.
71348 return getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
875 35674 }
876
877 /**
878 * Check if the current type is const
879 *
880 * Examples for const types:
881 * - const int
882 * - const TestStruct
883 * - const string
884 *
885 * Examples for non-const types:
886 * - double (reason: not marked const)
887 * - const int* (reason: pointer to const int is not const itself)
888 * - const TestStruct& (reason: reference to const TestStruct is not const itself)
889 *
890 * @return Is const or not
891 */
892
4/4
✓ Branch 3 → 4 taken 75022 times.
✓ Branch 3 → 6 taken 24450 times.
✓ Branch 4 → 5 taken 11353 times.
✓ Branch 4 → 6 taken 63669 times.
99472 bool QualType::isConst() const { return isExtendedPrimitive() && qualifiers.isConst; }
893
894 /**
895 * Check if the current type is marked signed
896 *
897 * @return Is signed or not
898 */
899 69110 bool QualType::isSigned() const {
900
2/4
✓ Branch 2 → 3 taken 69110 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 69110 times.
69110 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
901 69110 return qualifiers.isSigned;
902 }
903
904 /**
905 * Check if the current type is marked unsigned
906 *
907 * @return Is unsigned or not
908 */
909 2 bool QualType::isUnsigned() const {
910
2/4
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
2 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
911 2 return qualifiers.isUnsigned;
912 }
913
914 /**
915 * Check if the current type is marked inline
916 *
917 * @return Is inline or not
918 */
919 32811 bool QualType::isInline() const {
920
2/4
✓ Branch 2 → 3 taken 32811 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 32811 times.
32811 assert(isOneOf({TY_FUNCTION, TY_PROCEDURE}));
921 32811 return qualifiers.isInline;
922 }
923
924 /**
925 * Check if the current type is marked public
926 *
927 * @return Is public or not
928 */
929 83533 bool QualType::isPublic() const {
930
5/8
✓ Branch 2 → 3 taken 83533 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 79815 times.
✓ Branch 3 → 7 taken 3718 times.
✓ Branch 4 → 5 taken 79815 times.
✗ Branch 4 → 9 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 79815 times.
83533 assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE}));
931 83533 return qualifiers.isPublic;
932 }
933
934 /**
935 * Check if the current type is marked heap
936 *
937 * @return Is heap or not
938 */
939 44733 bool QualType::isHeap() const { return qualifiers.isHeap; }
940
941 /**
942 * Check if the current type is marked as composition
943 *
944 * @return Is composition or not
945 */
946 3413 bool QualType::isComposition() const { return qualifiers.isComposition; }
947
948 /**
949 * Make the current type const
950 *
951 * @param isConst Is const or not
952 */
953 20924 void QualType::makeConst(bool isConst) { qualifiers.isConst = isConst; }
954
955 /**
956 * Make the current type unsigned
957 *
958 * @param isUnsigned Is unsigned or not
959 */
960 107 void QualType::makeUnsigned(bool isUnsigned) {
961
2/4
✓ Branch 2 → 3 taken 107 times.
✗ Branch 2 → 6 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 107 times.
107 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
962 107 qualifiers.isSigned = !isUnsigned;
963 107 qualifiers.isUnsigned = isUnsigned;
964 107 }
965
966 /**
967 * Make the current type public
968 *
969 * @param isPublic Is public or not
970 */
971 3343 void QualType::makePublic(bool isPublic) {
972
4/8
✓ Branch 2 → 3 taken 3343 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 3343 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 3343 times.
✗ Branch 4 → 8 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 3343 times.
3343 assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE}));
973 3343 qualifiers.isPublic = isPublic;
974 3343 }
975
976 /**
977 * Make the current type heap
978 *
979 * @param isHeap Is heap or not
980 */
981 286 void QualType::makeHeap(bool isHeap) { qualifiers.isHeap = isHeap; }
982
983 /**
984 * Check if two types are equal
985 *
986 * @param lhs Left-hand side type
987 * @param rhs Right-hand side type
988 * @return Equal or not
989 */
990 2775506 bool operator==(const QualType &lhs, const QualType &rhs) { return lhs.type == rhs.type; }
991
992 /**
993 * Check if two types are not equal
994 *
995 * @param lhs Left-hand side type
996 * @param rhs Right-hand side type
997 * @return Not equal or not
998 */
999 501308 bool operator!=(const QualType &lhs, const QualType &rhs) { return !(lhs == rhs); }
1000
1001 /**
1002 * Remove pointers / arrays / references if both types have them as far as possible.
1003 *
1004 * @param typeA Candidate type
1005 * @param typeB Requested type
1006 */
1007 5861 void QualType::unwrapBoth(QualType &typeA, QualType &typeB) { Type::unwrapBoth(typeA.type, typeB.type); }
1008
1009 /**
1010 * Remove pointers / arrays / references if both types have them as far as possible.
1011 * Furthermore, remove reference wrappers if possible.
1012 *
1013 * @param typeA Candidate type
1014 * @param typeB Requested type
1015 */
1016 282436 void QualType::unwrapBothWithRefWrappers(QualType &typeA, QualType &typeB) {
1017 282436 Type::unwrapBothWithRefWrappers(typeA.type, typeB.type);
1018 282436 }
1019
1020 } // namespace spice::compiler
1021