GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.1% 304 / 0 / 313
Functions: 97.8% 91 / 0 / 93
Branches: 63.6% 271 / 0 / 426

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 3814287 QualType::QualType(SuperType superType) : type(TypeRegistry::getOrInsert(superType)), qualifiers(TypeQualifiers::of(superType)) {}
22 5600 QualType::QualType(SuperType superType, const std::string &subType)
23 5600 : type(TypeRegistry::getOrInsert(superType, subType)), qualifiers(TypeQualifiers::of(superType)) {}
24 263072 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 3554349 SuperType QualType::getSuperType() const { return type->getSuperType(); }
32
33 /**
34 * Get the subtype of the underlying type
35 *
36 * @return Subtype
37 */
38 940834 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 1651 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 3063084 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 51 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 354 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 156 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 303 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 390901 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 89141 Struct *QualType::getStruct(const ASTNode *node, const QualTypeList &templateTypes) const {
97
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 89141 times.
89141 assert(is(TY_STRUCT));
98 89141 Scope *structDefScope = getBodyScope()->parent;
99 89141 const std::string &structName = getSubType();
100 89141 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 58979 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 1314 Struct *QualType::getStructAndAdjustType(const ASTNode *node, const QualTypeList &templateTypes) {
120 1314 Struct *spiceStruct = getStruct(node, templateTypes);
121
2/4
✓ Branch 4 → 5 taken 1314 times.
✗ Branch 4 → 11 not taken.
✓ Branch 5 → 6 taken 1314 times.
✗ Branch 5 → 9 not taken.
1314 type = type->getWithBodyScope(spiceStruct->scope)->getWithTemplateTypes(spiceStruct->getTemplateTypes());
122 1314 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 7524 Interface *QualType::getInterface(const ASTNode *node, const QualTypeList &templateTypes) const {
142
2/4
✓ Branch 2 → 3 taken 7524 times.
✗ Branch 2 → 15 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 7524 times.
7524 assert(is(TY_INTERFACE));
143
1/2
✓ Branch 5 → 6 taken 7524 times.
✗ Branch 5 → 15 not taken.
7524 Scope *interfaceDefScope = getBodyScope()->parent;
144
2/4
✓ Branch 6 → 7 taken 7524 times.
✗ Branch 6 → 15 not taken.
✓ Branch 7 → 8 taken 7524 times.
✗ Branch 7 → 15 not taken.
7524 const std::string structName = getSubType();
145
1/2
✓ Branch 8 → 9 taken 7524 times.
✗ Branch 8 → 13 not taken.
15048 return InterfaceManager::match(interfaceDefScope, structName, templateTypes, node);
146 7524 }
147
148 /**
149 * Get the interface instance for an interface type
150 *
151 * @param node Accessing AST node
152 * @return Interface instance
153 */
154 4690 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 12318674 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 2327903 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 14769188 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 2392 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 261709 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 1085743 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 536388 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 53611 times.
✓ Branch 3 → 8 taken 482777 times.
✓ Branch 4 → 5 taken 53611 times.
✗ Branch 4 → 11 not taken.
✓ Branch 5 → 6 taken 53611 times.
✗ Branch 5 → 11 not taken.
✓ Branch 6 → 7 taken 17179 times.
✓ Branch 6 → 8 taken 36432 times.
536388 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 1555890 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 367855 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 an array that decays to a pointer to itself when passed to a function.
246 *
247 * Fixed-size arrays are the only aggregates that Spice used to hand to LLVM as first-class aggregate arguments. That
248 * left the ABI lowering of the individual elements to the backend, which is neither a stable contract nor efficient,
249 * because the whole array had to be loaded at the call site and stored again in the callee prologue. Instead, we now
250 * decay them to a pointer to the array, just like C/C++ frontends do. Arrays of unknown size are plain pointers
251 * already, so there is nothing to decay for them.
252 *
253 * @return Decays to a pointer or not
254 */
255
4/4
✓ Branch 3 → 4 taken 635 times.
✓ Branch 3 → 7 taken 239515 times.
✓ Branch 5 → 6 taken 79 times.
✓ Branch 5 → 7 taken 556 times.
240150 bool QualType::isDecayedArray() const { return isArray() && getArraySize() != ARRAY_SIZE_UNKNOWN; }
256
257 /**
258 * Check if the underlying type is a const reference
259 *
260 * @return Const reference or not
261 */
262
4/4
✓ Branch 2 → 3 taken 27996 times.
✓ Branch 2 → 6 taken 5321 times.
✓ Branch 4 → 5 taken 27687 times.
✓ Branch 4 → 6 taken 309 times.
33317 bool QualType::isConstRef() const { return qualifiers.isConst && isRef(); }
263
264 /**
265 * Check if the current type is an iterator
266 *
267 * @param node ASTNode
268 * @return Iterator or not
269 */
270 592 bool QualType::isIterator(const ASTNode *node) const {
271 // The type must be a struct that implements the iterator interface
272
3/4
✓ Branch 2 → 3 taken 592 times.
✗ Branch 2 → 47 not taken.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 591 times.
592 if (!is(TY_STRUCT))
273 1 return false;
274
275
2/4
✓ Branch 7 → 8 taken 591 times.
✗ Branch 7 → 30 not taken.
✓ Branch 8 → 9 taken 591 times.
✗ Branch 8 → 28 not taken.
1182 const QualType genericType(TY_GENERIC, "T");
276 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
277
3/6
✓ Branch 13 → 14 taken 591 times.
✗ Branch 13 → 42 not taken.
✓ Branch 16 → 17 taken 591 times.
✗ Branch 16 → 36 not taken.
✓ Branch 17 → 18 taken 591 times.
✗ Branch 17 → 34 not taken.
2364 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERATOR_INTERFACE, data, {genericType});
278
1/2
✓ Branch 22 → 23 taken 591 times.
✗ Branch 22 → 47 not taken.
591 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
279
1/2
✓ Branch 24 → 25 taken 591 times.
✗ Branch 24 → 47 not taken.
591 return doesImplement(iteratorQualType, node);
280 }
281
282 /**
283 * Check if the current type is an iterable
284 * - Arrays are always considered iterable
285 * - Otherwise the type must be a struct that implements the iterator interface
286 *
287 * @param node ASTNode
288 * @return Iterable or not
289 */
290 594 bool QualType::isIterable(const ASTNode *node) const {
291 // Arrays are always considered iterable
292
3/4
✓ Branch 2 → 3 taken 594 times.
✗ Branch 2 → 50 not taken.
✓ Branch 3 → 4 taken 19 times.
✓ Branch 3 → 5 taken 575 times.
594 if (isArray())
293 19 return true;
294 // Otherwise the type must be a struct that implements the iterator interface
295
3/4
✓ Branch 5 → 6 taken 575 times.
✗ Branch 5 → 50 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 574 times.
575 if (!is(TY_STRUCT))
296 1 return false;
297
298
2/4
✓ Branch 10 → 11 taken 574 times.
✗ Branch 10 → 33 not taken.
✓ Branch 11 → 12 taken 574 times.
✗ Branch 11 → 31 not taken.
1148 const QualType genericType(TY_GENERIC, "T");
299 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
300
3/6
✓ Branch 16 → 17 taken 574 times.
✗ Branch 16 → 45 not taken.
✓ Branch 19 → 20 taken 574 times.
✗ Branch 19 → 39 not taken.
✓ Branch 20 → 21 taken 574 times.
✗ Branch 20 → 37 not taken.
2296 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERABLE_INTERFACE, data, {genericType});
301
1/2
✓ Branch 25 → 26 taken 574 times.
✗ Branch 25 → 50 not taken.
574 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
302
1/2
✓ Branch 27 → 28 taken 574 times.
✗ Branch 27 → 50 not taken.
574 return doesImplement(iteratorQualType, node);
303 }
304
305 /**
306 * Check if the current type is a string object
307 *
308 * @return String object or not
309 */
310 1157 bool QualType::isStringObj() const {
311
4/6
✓ Branch 3 → 4 taken 162 times.
✓ Branch 3 → 10 taken 995 times.
✓ Branch 6 → 7 taken 162 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 162 times.
✗ Branch 8 → 10 not taken.
1157 return is(TY_STRUCT) && getSubType() == STROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
312 }
313
314 /**
315 * Check if the current type is an error object
316 *
317 * @return Error object or not
318 */
319 2269 bool QualType::isErrorObj() const {
320
4/6
✓ Branch 3 → 4 taken 2268 times.
✓ Branch 3 → 10 taken 1 time.
✓ Branch 6 → 7 taken 2268 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 2268 times.
✗ Branch 8 → 10 not taken.
2269 return is(TY_STRUCT) && getSubType() == ERROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
321 }
322
323 /**
324 * Check if the current type has any generic parts
325 *
326 * @return Generic parts or not
327 */
328 1396669 bool QualType::hasAnyGenericParts() const { return type->hasAnyGenericParts(); }
329
330 /**
331 * Check if constructing an instance of the current type would require calling a ctor.
332 * If this function return true, the type does not need to be constructed.
333 *
334 * @param node Accessing ASTNode
335 * @return Trivially constructible or not
336 */
337 2502 bool QualType::isTriviallyConstructible(const ASTNode *node) const {
338 // Heap-allocated values require manual allocation, which is done in the default/explicit ctor
339
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 2501 times.
2502 if (qualifiers.isHeap)
340 1 return false;
341
342 // References can't be default initialized
343
2/2
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 2498 times.
2501 if (isRef())
344 3 return false;
345
346 // In case of an array, the item type is determining the construction triviality
347
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 13 taken 2498 times.
2498 if (isArray())
348 return getBase().isTriviallyConstructible(node);
349
350 // In case of a struct, the member types determine the construction triviality
351
2/2
✓ Branch 14 → 15 taken 2377 times.
✓ Branch 14 → 36 taken 121 times.
2498 if (is(TY_STRUCT)) {
352 // If the struct has a ctor, it is a non-trivially constructible one
353
1/2
✓ Branch 15 → 16 taken 2377 times.
✗ Branch 15 → 39 not taken.
2377 const Struct *spiceStruct = getStruct(node);
354
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 2377 times.
2377 assert(spiceStruct != nullptr); // Callers must ensure the struct is manifested (see structFullyManifested)
355
3/4
✓ Branch 18 → 19 taken 2377 times.
✗ Branch 18 → 39 not taken.
✓ Branch 19 → 20 taken 2269 times.
✓ Branch 19 → 21 taken 108 times.
2377 if (FunctionManager::hasAnyNonCopyCtor(spiceStruct->scope))
356 2269 return false;
357
358 // If the struct emits a vtable, it is non-trivially constructible, because the vtable needs to be initialized in the ctor
359
1/2
✓ Branch 21 → 22 taken 108 times.
✗ Branch 21 → 23 not taken.
108 const auto *structDefNode = spice_pointer_cast<StructDefNode *>(spiceStruct->declNode);
360
2/2
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 30 taken 107 times.
108 if (structDefNode->emitVTable)
361 1 return false;
362
363 // If any field has a default value, the struct is non-trivially constructible
364 141 const auto pred1 = [&](const FieldNode *fieldNode) { return fieldNode->defaultValue != nullptr; };
365
3/4
✓ Branch 30 → 31 taken 107 times.
✗ Branch 30 → 39 not taken.
✓ Branch 31 → 32 taken 5 times.
✓ Branch 31 → 33 taken 102 times.
107 if (std::ranges::any_of(structDefNode->fields, pred1))
366 5 return false;
367
368 // Check if all member types are trivially constructible
369 136 const auto pred2 = [&](const QualType &fieldType) { return fieldType.isTriviallyConstructible(node); };
370
1/2
✓ Branch 33 → 34 taken 102 times.
✗ Branch 33 → 39 not taken.
102 return std::ranges::all_of(spiceStruct->fieldTypes, pred2);
371 }
372
373 121 return true;
374 }
375
376 /**
377 * Check if copying an instance of the current type would require a call to the copy ctor.
378 * If this function return true, the type can be copied by calling memcpy.
379 *
380 * @param node Accessing ASTNode
381 * @return Trivially copyable or not
382 */
383 11832 bool QualType::isTriviallyCopyable(const ASTNode *node) const { // NOLINT(*-no-recursion)
384 // Heap-allocated values may not be copied via memcpy
385
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 11832 times.
11832 if (qualifiers.isHeap)
386 return false;
387
388 // In case of an array, the item type is determining the copy triviality
389
2/2
✓ Branch 5 → 6 taken 20 times.
✓ Branch 5 → 10 taken 11812 times.
11832 if (isArray())
390
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);
391
392 // In case of a struct, the member types determine the copy triviality
393
2/2
✓ Branch 11 → 12 taken 4205 times.
✓ Branch 11 → 19 taken 7607 times.
11812 if (is(TY_STRUCT)) {
394 // If the struct has a copy ctor, it is a non-trivially copyable one
395
1/2
✓ Branch 12 → 13 taken 4205 times.
✗ Branch 12 → 22 not taken.
4205 const Struct *spiceStruct = getStruct(node);
396
3/4
✓ Branch 13 → 14 taken 4205 times.
✗ Branch 13 → 22 not taken.
✓ Branch 14 → 15 taken 2305 times.
✓ Branch 14 → 16 taken 1900 times.
4205 if (FunctionManager::hasCopyCtor(spiceStruct->scope))
397 2305 return false;
398
399 // Check if all member types are trivially copyable
400 6196 const auto pred = [&](const QualType &fieldType) { return fieldType.isTriviallyCopyable(node); }; // NOLINT(*-no-recursion)
401
1/2
✓ Branch 16 → 17 taken 1900 times.
✗ Branch 16 → 22 not taken.
1900 return std::ranges::all_of(spiceStruct->fieldTypes, pred);
402 }
403
404 7607 return true;
405 }
406
407 /**
408 * Check if destructing an instance of the current type would require calling a dtor.
409 * If this function return true, the type does not need to be destructed.
410 *
411 * @param node Accessing ASTNode
412 * @return Trivially destructible or not
413 */
414 36387 bool QualType::isTriviallyDestructible(const ASTNode *node) const {
415 // Heap-allocated values require manual de-allocation, which is done in the default/explicit dtor
416
2/2
✓ Branch 2 → 3 taken 1818 times.
✓ Branch 2 → 4 taken 34569 times.
36387 if (qualifiers.isHeap)
417 1818 return false;
418
419 // In case of an array, the item type is determining the destructing triviality
420
2/2
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 10 taken 34564 times.
34569 if (isArray())
421
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);
422
423 // In case of a struct, the member types determine the destructing triviality
424
2/2
✓ Branch 11 → 12 taken 18118 times.
✓ Branch 11 → 19 taken 16446 times.
34564 if (is(TY_STRUCT)) {
425 // If the struct has a dtor, it is a non-trivially destructible one
426
1/2
✓ Branch 12 → 13 taken 18118 times.
✗ Branch 12 → 22 not taken.
18118 const Struct *spiceStruct = getStruct(node);
427
3/4
✓ Branch 13 → 14 taken 18118 times.
✗ Branch 13 → 22 not taken.
✓ Branch 14 → 15 taken 8550 times.
✓ Branch 14 → 16 taken 9568 times.
18118 if (FunctionManager::hasDtor(spiceStruct->scope))
428 8550 return false;
429
430 // Check if all member types are trivially destructible
431 29131 const auto pred = [&](const QualType &fieldType) {
432 19563 return fieldType.isTriviallyDestructible(node);
433 9568 }; // NOLINT(*-no-recursion)
434
1/2
✓ Branch 16 → 17 taken 9568 times.
✗ Branch 16 → 22 not taken.
9568 return std::ranges::all_of(spiceStruct->fieldTypes, pred);
435 }
436
437 16446 return true;
438 }
439
440 /**
441 * Check if the current type implements the given interface type
442 *
443 * @param implementedInterfaceType Interface type
444 * @param node Accessing ASTNode
445 * @return Struct implements interface or not
446 */
447 1166 bool QualType::doesImplement(const QualType &implementedInterfaceType, const ASTNode *node) const {
448
2/4
✓ Branch 3 → 4 taken 1166 times.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 1166 times.
✗ Branch 5 → 7 not taken.
1166 assert(is(TY_STRUCT) && implementedInterfaceType.is(TY_INTERFACE));
449 1166 const Struct *spiceStruct = getStruct(node);
450
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 1166 times.
1166 assert(spiceStruct != nullptr);
451 1166 return std::ranges::any_of(spiceStruct->interfaceTypes, [&](const QualType &interfaceType) {
452
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1166 times.
1166 assert(interfaceType.is(TY_INTERFACE));
453 1166 return implementedInterfaceType.matches(interfaceType, false, false, true);
454 1166 });
455 }
456
457 /**
458 * Check if a certain input type can be bound (assigned) to the current type.
459 *
460 * @param inputType Qualified type, which should be bound to the current type
461 * @param isTemporary Is the input type a temporary type
462 * @return Can be bound or not
463 */
464 44090 bool QualType::canBind(const QualType &inputType, bool isTemporary) const {
465
8/8
✓ Branch 2 → 3 taken 10189 times.
✓ Branch 2 → 9 taken 33901 times.
✓ Branch 4 → 5 taken 9677 times.
✓ Branch 4 → 9 taken 512 times.
✓ Branch 6 → 7 taken 1204 times.
✓ Branch 6 → 9 taken 8473 times.
✓ Branch 8 → 9 taken 1202 times.
✓ Branch 8 → 10 taken 2 times.
44090 return !isTemporary || inputType.type->isRef() || !type->isRef() || isConstRef();
466 }
467
468 /**
469 * Check for the matching compatibility of two types.
470 * Useful for struct and function matching as well as assignment type validation and function arg matching.
471 *
472 * @param otherType Type to compare against
473 * @param ignoreArraySize Ignore array sizes
474 * @param ignoreQualifiers Ignore qualifiers, except for pointer and reference types
475 * @param allowConstify Match when the types are the same, but the lhs type is more const restrictive than the rhs type
476 * @return Matching or not
477 */
478 408549 bool QualType::matches(const QualType &otherType, bool ignoreArraySize, bool ignoreQualifiers, bool allowConstify) const {
479 // Special case: string is equivalent to const char*
480
6/8
✓ Branch 3 → 4 taken 44640 times.
✓ Branch 3 → 9 taken 363909 times.
✓ Branch 5 → 6 taken 2947 times.
✓ Branch 5 → 9 taken 41693 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 2947 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 408549 times.
408549 if (is(TY_STRING) && otherType.isPtrTo(TY_CHAR) && otherType.isConst())
481 return true;
482
4/8
✓ Branch 13 → 14 taken 11168 times.
✓ Branch 13 → 19 taken 397381 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 19 taken 11168 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 408549 times.
408549 if (isPtrTo(TY_CHAR) && isConst() && otherType.is(TY_STRING))
483 return true;
484
485 // Compare type
486
2/2
✓ Branch 23 → 24 taken 161627 times.
✓ Branch 23 → 25 taken 246922 times.
408549 if (!type->matches(otherType.type, ignoreArraySize))
487 161627 return false;
488
489 // Ignore or compare qualifiers
490
4/4
✓ Branch 25 → 26 taken 65952 times.
✓ Branch 25 → 28 taken 180970 times.
✓ Branch 27 → 28 taken 65442 times.
✓ Branch 27 → 29 taken 510 times.
246922 return ignoreQualifiers || qualifiers.match(otherType.qualifiers, allowConstify);
491 }
492
493 /**
494 * Check for the matching compatibility of two types in terms of interface implementation.
495 * Useful for function matching as well as assignment type validation and function arg matching.
496 *
497 * @param structType Type to compare against
498 * @return Matching or not
499 */
500 213762 bool QualType::matchesInterfaceImplementedByStruct(const QualType &structType) const {
501
8/10
✓ Branch 2 → 3 taken 213762 times.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 3296 times.
✓ Branch 3 → 6 taken 210466 times.
✓ Branch 4 → 5 taken 3296 times.
✗ Branch 4 → 17 not taken.
✓ Branch 5 → 6 taken 1983 times.
✓ Branch 5 → 7 taken 1313 times.
✓ Branch 8 → 9 taken 212449 times.
✓ Branch 8 → 10 taken 1313 times.
213762 if (!is(TY_INTERFACE) || !structType.is(TY_STRUCT))
502 212449 return false;
503
504 // Check if the rhs is a struct type that implements the lhs interface type
505
1/2
✓ Branch 10 → 11 taken 1313 times.
✗ Branch 10 → 17 not taken.
1313 const Struct *spiceStruct = structType.getStruct(nullptr);
506
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1313 times.
1313 assert(spiceStruct != nullptr);
507 1275 const auto pred = [&](const QualType &interfaceType) { return matches(interfaceType, false, false, true); };
508
1/2
✓ Branch 13 → 14 taken 1313 times.
✗ Branch 13 → 17 not taken.
1313 return std::ranges::any_of(spiceStruct->interfaceTypes, pred);
509 }
510
511 /**
512 * Check if the current (struct) type is a base of the given struct type, embedded via the 'compose'
513 * qualifier as its first field. The compiler does not perform implicit struct-to-composed-base upcasts;
514 * this matcher only gates the explicit 'cast<Base*>(derived)' conversion (and the matching IR pointer
515 * adjustment). Only first-field compositions are considered, because those are the ones reachable by
516 * advancing the pointer along the first-field chain. The check follows that chain transitively, so a base
517 * that is composed several levels deep is still matched.
518 */
519 6490 bool QualType::matchesComposedBaseOfStruct(const QualType &structType) const {
520
6/6
✓ Branch 3 → 4 taken 3685 times.
✓ Branch 3 → 6 taken 2805 times.
✓ Branch 5 → 6 taken 1216 times.
✓ Branch 5 → 7 taken 2469 times.
✓ Branch 8 → 9 taken 4021 times.
✓ Branch 8 → 10 taken 2469 times.
6490 if (!is(TY_STRUCT) || !structType.is(TY_STRUCT))
521 4021 return false;
522
523 2469 const Struct *spiceStruct = structType.getStruct(nullptr);
524
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())
525 return false;
526
527 // Only the first field can be a composed base that is reachable along the first-field chain
528 2469 const QualType &firstFieldType = spiceStruct->fieldTypes.front();
529
1/2
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 2469 times.
2469 if (!firstFieldType.isComposition())
530 return false;
531 // The composed field matches the requested base directly (qualifiers like 'compose' are ignored)
532
2/2
✓ Branch 23 → 24 taken 1386 times.
✓ Branch 23 → 25 taken 1083 times.
2469 if (matches(firstFieldType, false, true, true))
533 1386 return true;
534 // Otherwise follow the composition chain further down
535 1083 return matchesComposedBaseOfStruct(firstFieldType);
536 }
537
538 /**
539 * Check if the current type is the same container type as another type.
540 * Container types include arrays, pointers, and references.
541 *
542 * @param other Other type
543 * @return Same container type or not
544 */
545 8330 bool QualType::isSameContainerTypeAs(const QualType &other) const { return type->isSameContainerTypeAs(other.type); }
546
547 /**
548 * Check if the current type is a self-referencing struct type
549 *
550 * @param typeToCompareWith Type to compare with (nil on the first iteration)
551 * @return Self-referencing struct type or not
552 */
553 109914 bool QualType::isSelfReferencingStructType(const QualType *typeToCompareWith) const { // NOLINT(*-no-recursion)
554
2/2
✓ Branch 3 → 4 taken 82456 times.
✓ Branch 3 → 5 taken 27458 times.
109914 if (!is(TY_STRUCT))
555 82456 return false;
556
557 // If no type was set by a previous iteration, we set it to the current type
558
2/2
✓ Branch 5 → 6 taken 20521 times.
✓ Branch 5 → 7 taken 6937 times.
27458 if (typeToCompareWith == nullptr)
559 20521 typeToCompareWith = this;
560
561 27458 Scope *baseTypeBodyScope = getBodyScope();
562
2/2
✓ Branch 24 → 9 taken 88360 times.
✓ Branch 24 → 25 taken 26640 times.
115000 for (size_t i = 0; i < baseTypeBodyScope->getFieldCount(); i++) {
563
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 88360 times.
88360 const SymbolTableEntry *field = baseTypeBodyScope->lookupField(i);
564 88360 const QualType &fieldType = field->getQualType();
565 // Check if the base type of the field matches with the current type, which is also a base type
566 // If yes, this is a self-referencing struct type
567
3/4
✓ Branch 15 → 16 taken 88360 times.
✗ Branch 15 → 27 not taken.
✓ Branch 17 → 18 taken 818 times.
✓ Branch 17 → 19 taken 87542 times.
88360 if (fieldType.getBase() == *typeToCompareWith)
568 818 return true;
569
570 // If the field is a struct, check if it is a self-referencing struct type
571
1/2
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 87542 times.
87542 if (fieldType.isSelfReferencingStructType(typeToCompareWith))
572 return true;
573 }
574 26640 return false;
575 }
576
577 /**
578 * Check if the given generic type list has a substantiation for the current (generic) type
579 *
580 * @param genericTypeList Generic type list
581 * @return Has substantiation or not
582 */
583 69592 bool QualType::isCoveredByGenericTypeList(std::vector<GenericType> &genericTypeList) const { // NOLINT(*-no-recursion)
584
1/2
✓ Branch 2 → 3 taken 69592 times.
✗ Branch 2 → 19 not taken.
69592 const QualType baseType = getBase();
585 // Check if the symbol type itself is generic
586
3/4
✓ Branch 3 → 4 taken 69592 times.
✗ Branch 3 → 19 not taken.
✓ Branch 4 → 5 taken 11015 times.
✓ Branch 4 → 7 taken 58577 times.
69592 if (baseType.is(TY_GENERIC)) {
587
1/2
✓ Branch 5 → 6 taken 11015 times.
✗ Branch 5 → 19 not taken.
11015 return std::ranges::any_of(genericTypeList, [&](GenericType &t) {
588
2/2
✓ Branch 3 → 4 taken 11007 times.
✓ Branch 3 → 5 taken 2060 times.
13067 if (baseType.matches(t, true, true, true)) {
589 11007 t.used = true;
590 11007 return true;
591 }
592 2060 return false;
593 11015 });
594 }
595
596 // If the type is non-generic check template types
597 58577 bool covered = true;
598 // Check template types
599
1/2
✓ Branch 7 → 8 taken 58577 times.
✗ Branch 7 → 19 not taken.
58577 const QualTypeList &baseTemplateTypes = baseType.getTemplateTypes();
600 64291 auto outerPred = [&](const QualType &templateType) { // NOLINT(*-no-recursion)
601 5714 return templateType.isCoveredByGenericTypeList(genericTypeList);
602 58577 };
603
1/2
✓ Branch 8 → 9 taken 58577 times.
✗ Branch 8 → 19 not taken.
58577 covered &= std::ranges::all_of(baseTemplateTypes, outerPred);
604
605 // If function/procedure, check param and return types
606
3/4
✓ Branch 9 → 10 taken 58577 times.
✗ Branch 9 → 17 not taken.
✓ Branch 10 → 11 taken 98 times.
✓ Branch 10 → 14 taken 58479 times.
58577 if (baseType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
607
1/2
✓ Branch 11 → 12 taken 98 times.
✗ Branch 11 → 18 not taken.
98 const QualTypeList &paramAndReturnTypes = baseType.getFunctionParamAndReturnTypes();
608 288 const auto innerPred = [&](const QualType &paramType) { // NOLINT(*-no-recursion)
609 190 return paramType.isCoveredByGenericTypeList(genericTypeList);
610 98 };
611
1/2
✓ Branch 12 → 13 taken 98 times.
✗ Branch 12 → 18 not taken.
98 covered &= std::ranges::all_of(paramAndReturnTypes, innerPred);
612 }
613
614 58577 return covered;
615 }
616
617 /**
618 * Check if the current type needs de-allocation
619 *
620 * @return Needs de-allocation or not
621 */
622 5037 bool QualType::needsDeAllocation() const {
623
2/2
✓ Branch 3 → 4 taken 4861 times.
✓ Branch 3 → 5 taken 176 times.
5037 if (!isHeap())
624 4861 return false;
625 // We only need de-allocation, if we directly point to a heap-allocated type
626 // e.g. for heap TestStruct** we don't need to de-allocate, since it is a non-owning pointer to an owning pointer
627
2/4
✓ Branch 6 → 7 taken 176 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 176 times.
✗ Branch 8 → 10 not taken.
176 return isPtr() && !isPtrTo(TY_PTR);
628 }
629
630 /**
631 * Get the name of the symbol type as a string
632 *
633 * @param name Name stream
634 * @param withSize Include the array size for sized types
635 * @param ignorePublic Ignore any potential public qualifier
636 * @param withAliases Print aliases as is and not decompose them
637 */
638 2219113 void QualType::getName(std::stringstream &name, bool withSize, bool ignorePublic, bool withAliases) const {
639 // Append the qualifiers
640
3/6
✓ Branch 2 → 3 taken 2219113 times.
✗ Branch 2 → 31 not taken.
✓ Branch 3 → 4 taken 2219113 times.
✗ Branch 3 → 31 not taken.
✓ Branch 4 → 5 taken 2219113 times.
✗ Branch 4 → 31 not taken.
2219113 const TypeQualifiers defaultForSuperType = TypeQualifiers::of(getBase().getSuperType());
641
5/6
✓ Branch 5 → 6 taken 1617421 times.
✓ Branch 5 → 9 taken 601692 times.
✓ Branch 6 → 7 taken 711452 times.
✓ Branch 6 → 9 taken 905969 times.
✓ Branch 7 → 8 taken 711452 times.
✗ Branch 7 → 9 not taken.
2219113 if (!ignorePublic && qualifiers.isPublic && !defaultForSuperType.isPublic)
642
1/2
✓ Branch 8 → 9 taken 711452 times.
✗ Branch 8 → 32 not taken.
711452 name << "public ";
643
3/4
✓ Branch 9 → 10 taken 4053 times.
✓ Branch 9 → 12 taken 2215060 times.
✓ Branch 10 → 11 taken 4053 times.
✗ Branch 10 → 12 not taken.
2219113 if (qualifiers.isComposition && !defaultForSuperType.isComposition)
644
1/2
✓ Branch 11 → 12 taken 4053 times.
✗ Branch 11 → 32 not taken.
4053 name << "compose ";
645
8/8
✓ Branch 12 → 13 taken 223248 times.
✓ Branch 12 → 17 taken 1995865 times.
✓ Branch 13 → 14 taken 214682 times.
✓ Branch 13 → 17 taken 8566 times.
✓ Branch 15 → 16 taken 165415 times.
✓ Branch 15 → 17 taken 49267 times.
✓ Branch 18 → 19 taken 165415 times.
✓ Branch 18 → 20 taken 2053698 times.
2219113 if (qualifiers.isConst && !defaultForSuperType.isConst && type->typeChain.size() > 1)
646
1/2
✓ Branch 19 → 20 taken 165415 times.
✗ Branch 19 → 32 not taken.
165415 name << "const ";
647
3/4
✓ Branch 20 → 21 taken 56994 times.
✓ Branch 20 → 23 taken 2162119 times.
✓ Branch 21 → 22 taken 56994 times.
✗ Branch 21 → 23 not taken.
2219113 if (qualifiers.isHeap && !defaultForSuperType.isHeap)
648
1/2
✓ Branch 22 → 23 taken 56994 times.
✗ Branch 22 → 32 not taken.
56994 name << "heap ";
649
4/4
✓ Branch 23 → 24 taken 176082 times.
✓ Branch 23 → 26 taken 2043031 times.
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 26 taken 176081 times.
2219113 if (qualifiers.isSigned && !defaultForSuperType.isSigned)
650
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 32 not taken.
1 name << "signed ";
651
4/4
✓ Branch 26 → 27 taken 2043031 times.
✓ Branch 26 → 29 taken 176082 times.
✓ Branch 27 → 28 taken 206698 times.
✓ Branch 27 → 29 taken 1836333 times.
2219113 if (!qualifiers.isSigned && defaultForSuperType.isSigned)
652
1/2
✓ Branch 28 → 29 taken 206698 times.
✗ Branch 28 → 32 not taken.
206698 name << "unsigned ";
653
654 // Loop through all chain elements
655
1/2
✓ Branch 29 → 30 taken 2219113 times.
✗ Branch 29 → 32 not taken.
2219113 type->getName(name, withSize, ignorePublic, withAliases);
656 2219113 }
657
658 /**
659 * Get the name of the symbol type as a string
660 *
661 * @param withSize Include the array size for sized types
662 * @param ignorePublic Ignore any potential public qualifier
663 * @param withAliases Print aliases as is and not decompose them
664 * @return Symbol type name
665 */
666 988817 std::string QualType::getName(bool withSize, bool ignorePublic, bool withAliases) const {
667
1/2
✓ Branch 2 → 3 taken 988817 times.
✗ Branch 2 → 11 not taken.
988817 std::stringstream name;
668
1/2
✓ Branch 3 → 4 taken 988817 times.
✗ Branch 3 → 9 not taken.
988817 getName(name, withSize, ignorePublic, withAliases);
669
1/2
✓ Branch 4 → 5 taken 988817 times.
✗ Branch 4 → 9 not taken.
1977634 return name.str();
670 988817 }
671
672 /**
673 * Convert the type to an LLVM type
674 *
675 * @param sourceFile Source file
676 * @return LLVM type
677 */
678 1075177 llvm::Type *QualType::toLLVMType(SourceFile *sourceFile) const { return sourceFile->getLLVMType(type); }
679
680 /**
681 * Convert the type to the LLVM type to use for a parameter of this type in a function signature
682 *
683 * @param sourceFile Source file
684 * @return LLVM type
685 */
686 53297 llvm::Type *QualType::getParamLLVMType(SourceFile *sourceFile) const {
687 // Take the context from the converted type, so that we always end up in the same context as toLLVMType()
688 53297 llvm::Type *llvmType = toLLVMType(sourceFile);
689
2/2
✓ Branch 4 → 5 taken 15 times.
✓ Branch 4 → 8 taken 53282 times.
53297 return isDecayedArray() ? llvm::PointerType::get(llvmType->getContext(), 0) : llvmType;
690 }
691
692 /**
693 * Retrieve the pointer type to this type
694 *
695 * @param node ASTNode
696 * @return New type
697 */
698 99912 QualType QualType::toPtr(const ASTNode *node) const {
699 99912 QualType newType = *this;
700
2/2
✓ Branch 2 → 3 taken 99910 times.
✓ Branch 2 → 5 taken 2 times.
99912 newType.type = type->toPtr(node);
701 99910 return newType;
702 }
703
704 /**
705 * Retrieve the reference type to this type
706 *
707 * @param node ASTNode
708 * @return New type
709 */
710 44647 QualType QualType::toRef(const ASTNode *node) const {
711 44647 QualType newType = *this;
712
1/2
✓ Branch 2 → 3 taken 44647 times.
✗ Branch 2 → 5 not taken.
44647 newType.type = type->toRef(node);
713 44647 return newType;
714 }
715
716 /**
717 * Retrieve the const reference type of this type
718 *
719 * @param node ASTNode
720 * @return New type
721 */
722 21026 QualType QualType::toConstRef(const ASTNode *node) const {
723
1/2
✓ Branch 2 → 3 taken 21026 times.
✗ Branch 2 → 6 not taken.
21026 QualType newType = toRef(node);
724 21026 newType.makeConst();
725 21026 return newType;
726 }
727
728 /**
729 * Retrieve the array type of this type
730 *
731 * @param node ASTNode
732 * @param size Array size
733 * @param skipDynCheck Skip dynamic check
734 * @return New type
735 */
736 601 QualType QualType::toArr(const ASTNode *node, size_t size, bool skipDynCheck /*=false*/) const {
737 601 QualType newType = *this;
738
2/2
✓ Branch 2 → 3 taken 600 times.
✓ Branch 2 → 5 taken 1 time.
601 newType.type = type->toArr(node, size, skipDynCheck);
739 600 return newType;
740 }
741
742 /**
743 * Retrieve the non-const type of this type
744 *
745 * @return New type
746 */
747 10483 QualType QualType::toNonConst() const {
748 10483 QualType newType = *this;
749 10483 newType.qualifiers.isConst = false;
750 10483 return newType;
751 }
752
753 /**
754 * Retrieve the contained type of this type
755 * This works on pointers, arrays, references and strings (which alias with char*)
756 *
757 * @return New type
758 */
759 336765 QualType QualType::getContained() const {
760
2/4
✓ Branch 2 → 3 taken 336765 times.
✗ Branch 2 → 8 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 336765 times.
336765 assert(isOneOf({TY_PTR, TY_REF, TY_ARRAY, TY_STRING}));
761 336765 QualType newType = *this;
762
1/2
✓ Branch 5 → 6 taken 336765 times.
✗ Branch 5 → 9 not taken.
336765 newType.type = type->getContained();
763 336765 return newType;
764 }
765
766 /**
767 * Retrieve the base type of this type
768 *
769 * @return New type
770 */
771 5485722 QualType QualType::getBase() const {
772 5485722 QualType newType = *this;
773
1/2
✓ Branch 2 → 3 taken 5485722 times.
✗ Branch 2 → 5 not taken.
5485722 newType.type = type->getBase();
774 5485722 return newType;
775 }
776
777 /**
778 * Get aliased type for an alias type
779 *
780 * @param aliasEntry Entry of the alias definition
781 * @return Aliased type
782 */
783 5892 QualType QualType::getAliased(const SymbolTableEntry *aliasEntry) const {
784
2/4
✓ Branch 2 → 3 taken 5892 times.
✗ Branch 2 → 17 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5892 times.
5892 assert(is(TY_ALIAS));
785 // Get type of aliased type container entry
786
1/2
✓ Branch 5 → 6 taken 5892 times.
✗ Branch 5 → 17 not taken.
5892 const std::string aliasedContainerEntryName = aliasEntry->name + ALIAS_CONTAINER_SUFFIX;
787
1/2
✓ Branch 6 → 7 taken 5892 times.
✗ Branch 6 → 15 not taken.
5892 const SymbolTableEntry *aliasedTypeContainerEntry = aliasEntry->scope->lookupStrict(aliasedContainerEntryName);
788
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 5892 times.
5892 assert(aliasedTypeContainerEntry != nullptr);
789
1/2
✓ Branch 11 → 12 taken 5892 times.
✗ Branch 11 → 15 not taken.
11784 return aliasedTypeContainerEntry->getQualType();
790 5892 }
791
792 /**
793 * Remove reference of this type, if it is a reference
794 *
795 * @return New type
796 */
797
2/2
✓ Branch 3 → 4 taken 26932 times.
✓ Branch 3 → 5 taken 589636 times.
616568 QualType QualType::removeReferenceWrapper() const { return isRef() ? getContained() : *this; }
798
799 /**
800 * Auto-dereference the given symbol type (peeling off all ptr/ref wrappers).
801 * This process is NOT equivalent with getBase() because getBase() also removes e.g. array wrappers
802 *
803 * @return New type
804 */
805 81896 QualType QualType::autoDeReference() const {
806 81896 QualType newType = *this;
807
3/4
✓ Branch 5 → 6 taken 147397 times.
✗ Branch 5 → 10 not taken.
✓ Branch 6 → 3 taken 65501 times.
✓ Branch 6 → 7 taken 81896 times.
147397 while (newType.isOneOf({TY_PTR, TY_REF}))
808
1/2
✓ Branch 3 → 4 taken 65501 times.
✗ Branch 3 → 9 not taken.
65501 newType = newType.getContained();
809 81896 return newType;
810 }
811
812 /**
813 * Replace the base type with another one
814 *
815 * @param newBaseType New base type
816 * @return New type
817 */
818 72749 QualType QualType::replaceBaseType(const QualType &newBaseType) const {
819 // Create new type
820
1/2
✓ Branch 3 → 4 taken 72749 times.
✗ Branch 3 → 8 not taken.
72749 const Type *newType = type->replaceBase(newBaseType.getType());
821 // Create new qualifiers
822
1/2
✓ Branch 4 → 5 taken 72749 times.
✗ Branch 4 → 8 not taken.
72749 TypeQualifiers newQualifiers = qualifiers.merge(newBaseType.qualifiers);
823 // Return the new qualified type
824 72749 return {newType, newQualifiers};
825 }
826
827 /**
828 * Retrieve the same type, but with lambda captures enabled
829 *
830 * @return Same type with lambda captures
831 */
832 97 QualType QualType::getWithLambdaCaptures(bool enabled /*=true*/) const {
833 // Create new type
834 97 const Type *newType = type->getWithLambdaCaptures(enabled);
835 // Return the new qualified type
836 97 return {newType, qualifiers};
837 }
838
839 /**
840 * Retrieve the same type, but with a new body scope
841 *
842 * @return Same type with body scope
843 */
844 110297 QualType QualType::getWithBodyScope(Scope *bodyScope) const {
845 // Create new type
846 110297 const Type *newType = type->getWithBodyScope(bodyScope);
847 // Return the new qualified type
848 110297 return {newType, qualifiers};
849 }
850
851 /**
852 * Retrieve the same type, but with new template types
853 *
854 * @param templateTypes New template types
855 * @return Same type with new template types
856 */
857 14016 QualType QualType::getWithTemplateTypes(const QualTypeList &templateTypes) const {
858 // Create new type
859 14016 const Type *newType = type->getWithTemplateTypes(templateTypes);
860 // Return the new qualified type
861 14016 return {newType, qualifiers};
862 }
863
864 /**
865 * Retrieve the same type, but with new base template types
866 *
867 * @param templateTypes New base template types
868 * @return Same type with new base template types
869 */
870 22372 QualType QualType::getWithBaseTemplateTypes(const QualTypeList &templateTypes) const {
871 // Create new type
872 22372 const Type *newType = type->getWithBaseTemplateTypes(templateTypes);
873 // Return the new qualified type
874 22372 return {newType, qualifiers};
875 }
876
877 /**
878 * Retrieve the same type, but with new function parameter and return types
879 *
880 * @param paramAndReturnTypes New parameter types
881 * @return Same type with new parameter types
882 */
883 37285 QualType QualType::getWithFunctionParamAndReturnTypes(const QualTypeList &paramAndReturnTypes) const {
884 // Create new type
885 37285 const Type *newType = type->getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
886 // Return the new qualified type
887 37285 return {newType, qualifiers};
888 }
889
890 /**
891 * Retrieve the same type, but with new function parameter and return types
892 *
893 * @param returnType New return type
894 * @param paramTypes New parameter types
895 * @return Same type with new parameter types
896 */
897 37245 QualType QualType::getWithFunctionParamAndReturnTypes(const QualType &returnType, const QualTypeList &paramTypes) const {
898
1/2
✓ Branch 2 → 3 taken 37245 times.
✗ Branch 2 → 17 not taken.
37245 QualTypeList paramAndReturnTypes = paramTypes;
899
1/2
✓ Branch 7 → 8 taken 37245 times.
✗ Branch 7 → 13 not taken.
74490 paramAndReturnTypes.insert(paramAndReturnTypes.begin(), returnType);
900
1/2
✓ Branch 8 → 9 taken 37245 times.
✗ Branch 8 → 15 not taken.
74490 return getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
901 37245 }
902
903 /**
904 * Check if the current type is const
905 *
906 * Examples for const types:
907 * - const int
908 * - const TestStruct
909 * - const string
910 *
911 * Examples for non-const types:
912 * - double (reason: not marked const)
913 * - const int* (reason: pointer to const int is not const itself)
914 * - const TestStruct& (reason: reference to const TestStruct is not const itself)
915 *
916 * @return Is const or not
917 */
918
4/4
✓ Branch 3 → 4 taken 77918 times.
✓ Branch 3 → 6 taken 26331 times.
✓ Branch 4 → 5 taken 13071 times.
✓ Branch 4 → 6 taken 64847 times.
104249 bool QualType::isConst() const { return isExtendedPrimitive() && qualifiers.isConst; }
919
920 /**
921 * Check if the current type is marked signed
922 *
923 * @return Is signed or not
924 */
925 69647 bool QualType::isSigned() const {
926
2/4
✓ Branch 2 → 3 taken 69647 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 69647 times.
69647 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
927 69647 return qualifiers.isSigned;
928 }
929
930 /**
931 * Check if the current type is marked unsigned
932 *
933 * @return Is unsigned or not
934 */
935 2 bool QualType::isUnsigned() const {
936
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}));
937 2 return qualifiers.isUnsigned;
938 }
939
940 /**
941 * Check if the current type is marked inline
942 *
943 * @return Is inline or not
944 */
945 33229 bool QualType::isInline() const {
946
2/4
✓ Branch 2 → 3 taken 33229 times.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 33229 times.
33229 assert(isOneOf({TY_FUNCTION, TY_PROCEDURE}));
947 33229 return qualifiers.isInline;
948 }
949
950 /**
951 * Check if the current type is marked public
952 *
953 * @return Is public or not
954 */
955 84670 bool QualType::isPublic() const {
956
5/8
✓ Branch 2 → 3 taken 84670 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 80901 times.
✓ Branch 3 → 7 taken 3769 times.
✓ Branch 4 → 5 taken 80901 times.
✗ Branch 4 → 9 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 80901 times.
84670 assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE}));
957 84670 return qualifiers.isPublic;
958 }
959
960 /**
961 * Check if the current type is marked heap
962 *
963 * @return Is heap or not
964 */
965 46401 bool QualType::isHeap() const { return qualifiers.isHeap; }
966
967 /**
968 * Check if the current type is marked as composition
969 *
970 * @return Is composition or not
971 */
972 3694 bool QualType::isComposition() const { return qualifiers.isComposition; }
973
974 /**
975 * Make the current type const
976 *
977 * @param isConst Is const or not
978 */
979 23059 void QualType::makeConst(bool isConst) { qualifiers.isConst = isConst; }
980
981 /**
982 * Make the current type unsigned
983 *
984 * @param isUnsigned Is unsigned or not
985 */
986 110 void QualType::makeUnsigned(bool isUnsigned) {
987
2/4
✓ Branch 2 → 3 taken 110 times.
✗ Branch 2 → 6 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 110 times.
110 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
988 110 qualifiers.isSigned = !isUnsigned;
989 110 qualifiers.isUnsigned = isUnsigned;
990 110 }
991
992 /**
993 * Make the current type public
994 *
995 * @param isPublic Is public or not
996 */
997 3684 void QualType::makePublic(bool isPublic) {
998
4/8
✓ Branch 2 → 3 taken 3684 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 3684 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 3684 times.
✗ Branch 4 → 8 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 3684 times.
3684 assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE}));
999 3684 qualifiers.isPublic = isPublic;
1000 3684 }
1001
1002 /**
1003 * Make the current type heap
1004 *
1005 * @param isHeap Is heap or not
1006 */
1007 287 void QualType::makeHeap(bool isHeap) { qualifiers.isHeap = isHeap; }
1008
1009 /**
1010 * Check if two types are equal
1011 *
1012 * @param lhs Left-hand side type
1013 * @param rhs Right-hand side type
1014 * @return Equal or not
1015 */
1016 2852186 bool operator==(const QualType &lhs, const QualType &rhs) { return lhs.type == rhs.type; }
1017
1018 /**
1019 * Check if two types are not equal
1020 *
1021 * @param lhs Left-hand side type
1022 * @param rhs Right-hand side type
1023 * @return Not equal or not
1024 */
1025 507696 bool operator!=(const QualType &lhs, const QualType &rhs) { return !(lhs == rhs); }
1026
1027 /**
1028 * Remove pointers / arrays / references if both types have them as far as possible.
1029 *
1030 * @param typeA Candidate type
1031 * @param typeB Requested type
1032 */
1033 5950 void QualType::unwrapBoth(QualType &typeA, QualType &typeB) { Type::unwrapBoth(typeA.type, typeB.type); }
1034
1035 /**
1036 * Remove pointers / arrays / references if both types have them as far as possible.
1037 * Furthermore, remove reference wrappers if possible.
1038 *
1039 * @param typeA Candidate type
1040 * @param typeB Requested type
1041 */
1042 308109 void QualType::unwrapBothWithRefWrappers(QualType &typeA, QualType &typeB) {
1043 308109 Type::unwrapBothWithRefWrappers(typeA.type, typeB.type);
1044 308109 }
1045
1046 } // namespace spice::compiler
1047