GCC Code Coverage Report


Directory: ../
File: src/symboltablebuilder/QualType.cpp
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 234 243 96.3%
Functions: 76 78 97.4%
Branches: 197 328 60.1%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "QualType.h"
4
5 #include <sstream>
6
7 #include <SourceFile.h>
8 #include <global/TypeRegistry.h>
9 #include <model/Struct.h>
10 #include <symboltablebuilder/Scope.h>
11 #include <symboltablebuilder/SymbolTableBuilder.h>
12 #include <symboltablebuilder/Type.h>
13 #include <typechecker/InterfaceManager.h>
14 #include <typechecker/StructManager.h>
15
16 namespace spice::compiler {
17
18 3751701 QualType::QualType(SuperType superType) : type(TypeRegistry::getOrInsert(superType)), qualifiers(TypeQualifiers::of(superType)) {}
19 1397 QualType::QualType(SuperType superType, const std::string &subType)
20 1397 : type(TypeRegistry::getOrInsert(superType, subType)), qualifiers(TypeQualifiers::of(superType)) {}
21 51933 QualType::QualType(const Type *type, TypeQualifiers qualifiers) : type(type), qualifiers(qualifiers) {}
22
23 /**
24 * Get the super type of the underlying type
25 *
26 * @return Super type
27 */
28 696128 SuperType QualType::getSuperType() const { return type->getSuperType(); }
29
30 /**
31 * Get the subtype of the underlying type
32 *
33 * @return Subtype
34 */
35 167654 const std::string &QualType::getSubType() const { return type->getSubType(); }
36
37 /**
38 * Get the array size of the underlying type
39 *
40 * @return Array size
41 */
42 396 unsigned int QualType::getArraySize() const { return type->getArraySize(); }
43
44 /**
45 * Get the body scope of the underlying type
46 *
47 * @return Body scope
48 */
49 122868 Scope *QualType::getBodyScope() const { return type->getBodyScope(); }
50
51 /**
52 * Get the function parameter types of the underlying type
53 *
54 * @return Function parameter types
55 */
56 39 const QualType &QualType::getFunctionReturnType() const { return type->getFunctionReturnType(); }
57
58 /**
59 * Get the function parameter types of the underlying type
60 *
61 * @return Function parameter types
62 */
63 140 QualTypeList QualType::getFunctionParamTypes() const { return type->getFunctionParamTypes(); }
64
65 /**
66 * Get the function parameter and return types of the underlying type
67 *
68 * @return Function parameter and return types
69 */
70 143 const QualTypeList &QualType::getFunctionParamAndReturnTypes() const { return type->getFunctionParamAndReturnTypes(); }
71
72 /**
73 * Check if the underlying type has lambda captures
74 *
75 * @return Has lambda captures or not
76 */
77 176 bool QualType::hasLambdaCaptures() const { return type->hasLambdaCaptures(); }
78
79 /**
80 * Get the template types of the underlying type
81 *
82 * @return Template types
83 */
84 85671 const QualTypeList &QualType::getTemplateTypes() const { return type->getTemplateTypes(); }
85
86 /**
87 * Get the struct instance for a struct type
88 *
89 * @param node Accessing AST node
90 * @return Struct instance
91 */
92 3577 Struct *QualType::getStruct(const ASTNode *node) const {
93
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 3577 times.
3577 assert(is(TY_STRUCT));
94 3577 Scope *structDefScope = getBodyScope()->parent;
95 3577 const std::string &structName = getSubType();
96 3577 const QualTypeList &templateTypes = getTemplateTypes();
97 3577 return StructManager::match(structDefScope, structName, templateTypes, node);
98 }
99
100 /**
101 * Get the interface instance for an interface type
102 *
103 * @param node Accessing AST node
104 * @return Interface instance
105 */
106 271 Interface *QualType::getInterface(const ASTNode *node) const {
107
2/4
✓ Branch 0 (2→3) taken 271 times.
✗ Branch 1 (2→16) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 271 times.
271 assert(is(TY_INTERFACE));
108
1/2
✓ Branch 0 (5→6) taken 271 times.
✗ Branch 1 (5→16) not taken.
271 Scope *interfaceDefScope = getBodyScope()->parent;
109
2/4
✓ Branch 0 (6→7) taken 271 times.
✗ Branch 1 (6→16) not taken.
✓ Branch 2 (7→8) taken 271 times.
✗ Branch 3 (7→16) not taken.
271 const std::string structName = getSubType();
110
1/2
✓ Branch 0 (8→9) taken 271 times.
✗ Branch 1 (8→14) not taken.
271 const QualTypeList &templateTypes = getTemplateTypes();
111
1/2
✓ Branch 0 (9→10) taken 271 times.
✗ Branch 1 (9→14) not taken.
542 return InterfaceManager::match(interfaceDefScope, structName, templateTypes, node);
112 271 }
113
114 /**
115 * Check if the underlying type is of a certain super type
116 *
117 * @param superType Super type
118 * @return Is of super type or not
119 */
120 2368256 bool QualType::is(SuperType superType) const { return type->is(superType); }
121
122 /**
123 * Check if the underlying type is one of a list of super types
124 *
125 * @param superTypes List of super types
126 * @return Is one of the super types or not
127 */
128 448106 bool QualType::isOneOf(const std::initializer_list<SuperType> &superTypes) const { return type->isOneOf(superTypes); }
129
130 /**
131 * Check if the base type of the underlying type is a certain super type
132 *
133 * @param superType Super type
134 * @return Is base type or not
135 */
136 550958 bool QualType::isBase(SuperType superType) const { return type->isBase(superType); }
137
138 /**
139 * Check if the underlying type is a primitive type
140 * Note: enum types are mapped to int, so they are also count as primitive types.
141 *
142 * @return Primitive or not
143 */
144 757 bool QualType::isPrimitive() const { return type->isPrimitive(); }
145
146 /**
147 * Check if the underlying type is an extended primitive type
148 * The definition of extended primitive types contains all primitive types plus the following:
149 * - structs
150 * - interfaces
151 * - functions/procedures
152 *
153 * @return Extended primitive or not
154 */
155 70027 bool QualType::isExtendedPrimitive() const { return type->isExtendedPrimitive(); }
156
157 /**
158 * Check if the underlying type is a pointer
159 *
160 * @return Pointer or not
161 */
162 178941 bool QualType::isPtr() const { return type->isPtr(); }
163
164 /**
165 * Check if the underlying type is a pointer to a certain super type
166 *
167 * @param superType Super type
168 * @return Pointer to super type or not
169 */
170
7/10
✓ Branch 0 (2→3) taken 22684 times.
✗ Branch 1 (2→12) not taken.
✓ Branch 2 (3→4) taken 147 times.
✓ Branch 3 (3→8) taken 22537 times.
✓ Branch 4 (4→5) taken 147 times.
✗ Branch 5 (4→12) not taken.
✓ Branch 6 (5→6) taken 147 times.
✗ Branch 7 (5→12) not taken.
✓ Branch 8 (6→7) taken 2 times.
✓ Branch 9 (6→8) taken 145 times.
22684 bool QualType::isPtrTo(SuperType superType) const { return isPtr() && getContained().is(superType); }
171
172 /**
173 * Check if the underlying type is a reference
174 *
175 * @return Reference or not
176 */
177 400565 bool QualType::isRef() const { return type->isRef(); }
178
179 /**
180 * Check if the underlying type is a reference to a certain super type
181 *
182 * @param superType Super type
183 * @return Reference to super type or not
184 */
185 bool QualType::isRefTo(SuperType superType) const { return isRef() && getContained().is(superType); }
186
187 /**
188 * Check if the underlying type is an array
189 *
190 * @return Array or not
191 */
192 21958 bool QualType::isArray() const { return type->isArray(); }
193
194 /**
195 * Check if the underlying type is an array of a certain super type
196 *
197 * @param superType Super type
198 * @return Array of super type or not
199 */
200
2/10
✓ Branch 0 (2→3) taken 1 times.
✗ Branch 1 (2→12) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→8) taken 1 times.
✗ Branch 4 (4→5) not taken.
✗ Branch 5 (4→12) not taken.
✗ Branch 6 (5→6) not taken.
✗ Branch 7 (5→12) not taken.
✗ Branch 8 (6→7) not taken.
✗ Branch 9 (6→8) not taken.
1 bool QualType::isArrayOf(SuperType superType) const { return isArray() && getContained().is(superType); }
201
202 /**
203 * Check if the underlying type is a const reference
204 *
205 * @return Const reference or not
206 */
207
4/4
✓ Branch 0 (2→3) taken 343 times.
✓ Branch 1 (2→6) taken 265 times.
✓ Branch 2 (4→5) taken 339 times.
✓ Branch 3 (4→6) taken 4 times.
608 bool QualType::isConstRef() const { return qualifiers.isConst && isRef(); }
208
209 /**
210 * Check if the current type is an iterator
211 *
212 * @param node ASTNode
213 * @return Iterator or not
214 */
215 90 bool QualType::isIterator(const ASTNode *node) const {
216 // The type must be a struct that implements the iterator interface
217
3/4
✓ Branch 0 (2→3) taken 90 times.
✗ Branch 1 (2→47) not taken.
✓ Branch 2 (3→4) taken 1 times.
✓ Branch 3 (3→5) taken 89 times.
90 if (!is(TY_STRUCT))
218 1 return false;
219
220
2/4
✓ Branch 0 (7→8) taken 89 times.
✗ Branch 1 (7→30) not taken.
✓ Branch 2 (8→9) taken 89 times.
✗ Branch 3 (8→28) not taken.
89 const QualType genericType(TY_GENERIC, "T");
221 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
222
3/6
✓ Branch 0 (13→14) taken 89 times.
✗ Branch 1 (13→42) not taken.
✓ Branch 2 (16→17) taken 89 times.
✗ Branch 3 (16→36) not taken.
✓ Branch 4 (17→18) taken 89 times.
✗ Branch 5 (17→34) not taken.
356 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERATOR_INTERFACE, data, {genericType});
223
1/2
✓ Branch 0 (22→23) taken 89 times.
✗ Branch 1 (22→47) not taken.
89 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
224
1/2
✓ Branch 0 (24→25) taken 89 times.
✗ Branch 1 (24→47) not taken.
89 return doesImplement(iteratorQualType, node);
225 }
226
227 /**
228 * Check if the current type is an iterable
229 * - Arrays are always considered iterable
230 * - Otherwise the type must be a struct that implements the iterator interface
231 *
232 * @param node ASTNode
233 * @return Iterable or not
234 */
235 92 bool QualType::isIterable(const ASTNode *node) const {
236 // Arrays are always considered iterable
237
3/4
✓ Branch 0 (2→3) taken 92 times.
✗ Branch 1 (2→50) not taken.
✓ Branch 2 (3→4) taken 8 times.
✓ Branch 3 (3→5) taken 84 times.
92 if (isArray())
238 8 return true;
239 // Otherwise the type must be a struct that implements the iterator interface
240
3/4
✓ Branch 0 (5→6) taken 84 times.
✗ Branch 1 (5→50) not taken.
✓ Branch 2 (6→7) taken 1 times.
✓ Branch 3 (6→8) taken 83 times.
84 if (!is(TY_STRUCT))
241 1 return false;
242
243
2/4
✓ Branch 0 (10→11) taken 83 times.
✗ Branch 1 (10→33) not taken.
✓ Branch 2 (11→12) taken 83 times.
✗ Branch 3 (11→31) not taken.
83 const QualType genericType(TY_GENERIC, "T");
244 static constexpr TypeChainElementData data = {.bodyScope = nullptr};
245
3/6
✓ Branch 0 (16→17) taken 83 times.
✗ Branch 1 (16→45) not taken.
✓ Branch 2 (19→20) taken 83 times.
✗ Branch 3 (19→39) not taken.
✓ Branch 4 (20→21) taken 83 times.
✗ Branch 5 (20→37) not taken.
332 const Type *itType = TypeRegistry::getOrInsert(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERABLE_INTERFACE, data, {genericType});
246
1/2
✓ Branch 0 (25→26) taken 83 times.
✗ Branch 1 (25→50) not taken.
83 const QualType iteratorQualType(itType, TypeQualifiers::of(TY_INTERFACE));
247
1/2
✓ Branch 0 (27→28) taken 83 times.
✗ Branch 1 (27→50) not taken.
83 return doesImplement(iteratorQualType, node);
248 }
249
250 /**
251 * Check if the current type is a string object
252 *
253 * @return String object or not
254 */
255 7759 bool QualType::isStringObj() const {
256
5/6
✓ Branch 0 (3→4) taken 603 times.
✓ Branch 1 (3→10) taken 7156 times.
✓ Branch 2 (6→7) taken 269 times.
✓ Branch 3 (6→10) taken 334 times.
✓ Branch 4 (8→9) taken 269 times.
✗ Branch 5 (8→10) not taken.
7759 return is(TY_STRUCT) && getSubType() == STROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
257 }
258
259 /**
260 * Check if the current type is an error object
261 *
262 * @return Error object or not
263 */
264 589 bool QualType::isErrorObj() const {
265
3/6
✓ Branch 0 (3→4) taken 589 times.
✗ Branch 1 (3→10) not taken.
✓ Branch 2 (6→7) taken 589 times.
✗ Branch 3 (6→10) not taken.
✓ Branch 4 (8→9) taken 589 times.
✗ Branch 5 (8→10) not taken.
589 return is(TY_STRUCT) && getSubType() == ERROBJ_NAME && getBodyScope()->sourceFile->isStdFile;
266 }
267
268 /**
269 * Check if the current type has any generic parts
270 *
271 * @return Generic parts or not
272 */
273 246419 bool QualType::hasAnyGenericParts() const { return type->hasAnyGenericParts(); }
274
275 /**
276 * Check if copying an instance of the current type would require calling other copy ctors.
277 * If this function return true, the type can be copied by calling memcpy.
278 *
279 * @param node Accessing ASTNode
280 * @return Trivially copyable or not
281 */
282 640 bool QualType::isTriviallyCopyable(const ASTNode *node) const { // NOLINT(*-no-recursion)
283 // Heap-allocated values may not be copied via memcpy
284
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 640 times.
640 if (qualifiers.isHeap)
285 return false;
286
287 // References can't be copied at all
288
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 640 times.
640 if (isRef())
289 return false;
290
291 // In case of an array, the item type is determining the copy triviality
292
1/2
✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→13) taken 640 times.
640 if (isArray())
293 return getBase().isTriviallyCopyable(node);
294
295 // In case of a struct, the member types determine the copy triviality
296
2/2
✓ Branch 0 (14→15) taken 229 times.
✓ Branch 1 (14→34) taken 411 times.
640 if (is(TY_STRUCT)) {
297 // If the struct has a copy ctor, it is a non-trivially copyable one
298
1/2
✓ Branch 0 (15→16) taken 229 times.
✗ Branch 1 (15→51) not taken.
229 const Struct *spiceStruct = getStruct(node);
299
300 // If the struct itself has a copy ctor, it is not trivially copyable
301
2/4
✓ Branch 0 (16→17) taken 229 times.
✗ Branch 1 (16→40) not taken.
✓ Branch 2 (20→21) taken 229 times.
✗ Branch 3 (20→37) not taken.
687 const std::vector args = {Arg(toConstRef(node), false)};
302
2/4
✓ Branch 0 (24→25) taken 229 times.
✗ Branch 1 (24→45) not taken.
✓ Branch 2 (25→26) taken 229 times.
✗ Branch 3 (25→43) not taken.
229 const Function *copyCtor = FunctionManager::lookup(spiceStruct->scope, CTOR_FUNCTION_NAME, *this, args, true);
303
2/2
✓ Branch 0 (28→29) taken 123 times.
✓ Branch 1 (28→30) taken 106 times.
229 if (copyCtor != nullptr)
304 123 return false;
305
306 // Check if all member types are trivially copyable
307 210 const auto pred = [&](const QualType &fieldType) { return fieldType.isTriviallyCopyable(node); }; // NOLINT(*-no-recursion)
308
1/2
✓ Branch 0 (30→31) taken 106 times.
✗ Branch 1 (30→49) not taken.
106 return std::ranges::all_of(spiceStruct->fieldTypes, pred);
309 229 }
310
311 411 return true;
312 }
313
314 /**
315 * Check if the current type implements the given interface type
316 *
317 * @param implementedInterfaceType Interface type
318 * @param node Accessing ASTNode
319 * @return Struct implements interface or not
320 */
321 172 bool QualType::doesImplement(const QualType &implementedInterfaceType, const ASTNode *node) const {
322
2/4
✓ Branch 0 (3→4) taken 172 times.
✗ Branch 1 (3→7) not taken.
✓ Branch 2 (5→6) taken 172 times.
✗ Branch 3 (5→7) not taken.
172 assert(is(TY_STRUCT) && implementedInterfaceType.is(TY_INTERFACE));
323 172 const Struct *spiceStruct = getStruct(node);
324
1/2
✗ Branch 0 (9→10) not taken.
✓ Branch 1 (9→11) taken 172 times.
172 assert(spiceStruct != nullptr);
325 172 return std::ranges::any_of(spiceStruct->interfaceTypes, [&](const QualType &interfaceType) {
326
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 172 times.
172 assert(interfaceType.is(TY_INTERFACE));
327 172 return implementedInterfaceType.matches(interfaceType, false, false, true);
328 172 });
329 }
330
331 /**
332 * Check if a certain input type can be bound (assigned) to the current type->
333 *
334 * @param inputType Qualified type, which should be bound to the current type
335 * @param isTemporary Is the input type a temporary type
336 * @return Can be bound or not
337 */
338 10819 bool QualType::canBind(const QualType &inputType, bool isTemporary) const {
339
8/8
✓ Branch 0 (2→3) taken 2978 times.
✓ Branch 1 (2→9) taken 7841 times.
✓ Branch 2 (4→5) taken 2801 times.
✓ Branch 3 (4→9) taken 177 times.
✓ Branch 4 (6→7) taken 327 times.
✓ Branch 5 (6→9) taken 2474 times.
✓ Branch 6 (8→9) taken 325 times.
✓ Branch 7 (8→10) taken 2 times.
10819 return !isTemporary || inputType.type->isRef() || !type->isRef() || isConstRef();
340 }
341
342 /**
343 * Check for the matching compatibility of two types.
344 * Useful for struct and function matching as well as assignment type validation and function arg matching.
345 *
346 * @param otherType Type to compare against
347 * @param ignoreArraySize Ignore array sizes
348 * @param ignoreQualifiers Ignore qualifiers, except for pointer and reference types
349 * @param allowConstify Match when the types are the same, but the lhs type is more const restrictive than the rhs type
350 * @return Matching or not
351 */
352 92343 bool QualType::matches(const QualType &otherType, bool ignoreArraySize, bool ignoreQualifiers, bool allowConstify) const {
353 // Compare type
354
2/2
✓ Branch 0 (3→4) taken 39403 times.
✓ Branch 1 (3→5) taken 52940 times.
92343 if (!type->matches(otherType.type, ignoreArraySize))
355 39403 return false;
356
357 // Ignore or compare qualifiers
358
4/4
✓ Branch 0 (5→6) taken 10433 times.
✓ Branch 1 (5→8) taken 42507 times.
✓ Branch 2 (7→8) taken 10330 times.
✓ Branch 3 (7→9) taken 103 times.
52940 return ignoreQualifiers || qualifiers.match(otherType.qualifiers, allowConstify);
359 }
360
361 /**
362 * Check for the matching compatibility of two types in terms of interface implementation.
363 * Useful for function matching as well as assignment type validation and function arg matching.
364 *
365 * @param structType Type to compare against
366 * @return Matching or not
367 */
368 48878 bool QualType::matchesInterfaceImplementedByStruct(const QualType &structType) const {
369
8/10
✓ Branch 0 (2→3) taken 48878 times.
✗ Branch 1 (2→17) not taken.
✓ Branch 2 (3→4) taken 127 times.
✓ Branch 3 (3→6) taken 48751 times.
✓ Branch 4 (4→5) taken 127 times.
✗ Branch 5 (4→17) not taken.
✓ Branch 6 (5→6) taken 10 times.
✓ Branch 7 (5→7) taken 117 times.
✓ Branch 8 (8→9) taken 48761 times.
✓ Branch 9 (8→10) taken 117 times.
48878 if (!is(TY_INTERFACE) || !structType.is(TY_STRUCT))
370 48761 return false;
371
372 // Check if the rhs is a struct type that implements the lhs interface type
373
1/2
✓ Branch 0 (10→11) taken 117 times.
✗ Branch 1 (10→17) not taken.
117 const Struct *spiceStruct = structType.getStruct(nullptr);
374
1/2
✗ Branch 0 (11→12) not taken.
✓ Branch 1 (11→13) taken 117 times.
117 assert(spiceStruct != nullptr);
375 115 const auto pred = [&](const QualType &interfaceType) { return matches(interfaceType, false, false, true); };
376
1/2
✓ Branch 0 (13→14) taken 117 times.
✗ Branch 1 (13→17) not taken.
117 return std::ranges::any_of(spiceStruct->interfaceTypes, pred);
377 }
378
379 /**
380 * Check if the current type is the same container type as another type.
381 * Container types include arrays, pointers, and references.
382 *
383 * @param other Other type
384 * @return Same container type or not
385 */
386 2721 bool QualType::isSameContainerTypeAs(const QualType &other) const { return type->isSameContainerTypeAs(other.type); }
387
388 /**
389 * Check if the current type is a self-referencing struct type
390 *
391 * @return Self-referencing struct type or not
392 */
393 18706 bool QualType::isSelfReferencingStructType(const QualType *typeToCompareWith) const { // NOLINT(*-no-recursion)
394
2/2
✓ Branch 0 (3→4) taken 13865 times.
✓ Branch 1 (3→5) taken 4841 times.
18706 if (!is(TY_STRUCT))
395 13865 return false;
396
397 // If no type was set by a previous iteration, we set it to the current type
398
2/2
✓ Branch 0 (5→6) taken 3378 times.
✓ Branch 1 (5→7) taken 1463 times.
4841 if (typeToCompareWith == nullptr)
399 3378 typeToCompareWith = this;
400
401 4841 Scope *baseTypeBodyScope = getBodyScope();
402
2/2
✓ Branch 0 (24→9) taken 15253 times.
✓ Branch 1 (24→25) taken 4652 times.
19905 for (size_t i = 0; i < baseTypeBodyScope->getFieldCount(); i++) {
403
1/2
✗ Branch 0 (9→10) not taken.
✓ Branch 1 (9→11) taken 15253 times.
15253 const SymbolTableEntry *field = baseTypeBodyScope->lookupField(i);
404 15253 const QualType &fieldType = field->getQualType();
405 // Check if the base type of the field matches with the current type, which is also a base type
406 // If yes, this is a self-referencing struct type
407
3/4
✓ Branch 0 (15→16) taken 15253 times.
✗ Branch 1 (15→27) not taken.
✓ Branch 2 (17→18) taken 189 times.
✓ Branch 3 (17→19) taken 15064 times.
15253 if (fieldType.getBase() == *typeToCompareWith)
408 189 return true;
409
410 // If the field is a struct, check if it is a self-referencing struct type
411
1/2
✗ Branch 0 (20→21) not taken.
✓ Branch 1 (20→22) taken 15064 times.
15064 if (fieldType.isSelfReferencingStructType(typeToCompareWith))
412 return true;
413 }
414 4652 return false;
415 }
416
417 /**
418 * Check if the given generic type list has a substantiation for the current (generic) type
419 *
420 * @param genericTypeList Generic type list
421 * @return Has substantiation or not
422 */
423 19279 bool QualType::isCoveredByGenericTypeList(std::vector<GenericType> &genericTypeList) const { // NOLINT(*-no-recursion)
424
1/2
✓ Branch 0 (2→3) taken 19279 times.
✗ Branch 1 (2→19) not taken.
19279 const QualType baseType = getBase();
425 // Check if the symbol type itself is generic
426
3/4
✓ Branch 0 (3→4) taken 19279 times.
✗ Branch 1 (3→19) not taken.
✓ Branch 2 (4→5) taken 3231 times.
✓ Branch 3 (4→7) taken 16048 times.
19279 if (baseType.is(TY_GENERIC)) {
427
1/2
✓ Branch 0 (5→6) taken 3231 times.
✗ Branch 1 (5→19) not taken.
3231 return std::ranges::any_of(genericTypeList, [&](GenericType &t) {
428
2/2
✓ Branch 0 (3→4) taken 3223 times.
✓ Branch 1 (3→5) taken 605 times.
3828 if (baseType.matches(t, true, true, true)) {
429 3223 t.used = true;
430 3223 return true;
431 }
432 605 return false;
433 3231 });
434 }
435
436 // If the type is non-generic check template types
437 16048 bool covered = true;
438 // Check template types
439
1/2
✓ Branch 0 (7→8) taken 16048 times.
✗ Branch 1 (7→19) not taken.
16048 const QualTypeList &baseTemplateTypes = baseType.getTemplateTypes();
440 1474 auto outerPred = [&](const QualType &templateType) { // NOLINT(*-no-recursion)
441 1474 return templateType.isCoveredByGenericTypeList(genericTypeList);
442 16048 };
443
1/2
✓ Branch 0 (8→9) taken 16048 times.
✗ Branch 1 (8→19) not taken.
16048 covered &= std::ranges::all_of(baseTemplateTypes, outerPred);
444
445 // If function/procedure, check param and return types
446
3/4
✓ Branch 0 (9→10) taken 16048 times.
✗ Branch 1 (9→17) not taken.
✓ Branch 2 (10→11) taken 51 times.
✓ Branch 3 (10→14) taken 15997 times.
16048 if (baseType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
447
1/2
✓ Branch 0 (11→12) taken 51 times.
✗ Branch 1 (11→18) not taken.
51 const QualTypeList &paramAndReturnTypes = baseType.getFunctionParamAndReturnTypes();
448 90 const auto innerPred = [&](const QualType &paramType) { // NOLINT(*-no-recursion)
449 90 return paramType.isCoveredByGenericTypeList(genericTypeList);
450 51 };
451
1/2
✓ Branch 0 (12→13) taken 51 times.
✗ Branch 1 (12→18) not taken.
51 covered &= std::ranges::all_of(paramAndReturnTypes, innerPred);
452 }
453
454 16048 return covered;
455 }
456
457 /**
458 * Check if the current type needs de-allocation
459 *
460 * @return Needs de-allocation or not
461 */
462 1076 bool QualType::needsDeAllocation() const {
463
2/2
✓ Branch 0 (3→4) taken 1030 times.
✓ Branch 1 (3→5) taken 46 times.
1076 if (!isHeap())
464 1030 return false;
465 // We only need de-allocation, if we directly point to a heap-allocated type
466 // e.g. for heap TestStruct** we don't need to de-allocate, since it is a non-owning pointer to an owning pointer
467
2/4
✓ Branch 0 (6→7) taken 46 times.
✗ Branch 1 (6→10) not taken.
✓ Branch 2 (8→9) taken 46 times.
✗ Branch 3 (8→10) not taken.
46 return isPtr() && !isPtrTo(TY_PTR);
468 }
469
470 /**
471 * Get the name of the symbol type as a string
472 *
473 * @param name Name stream
474 * @param withSize Include the array size for sized types
475 * @param ignorePublic Ignore any potential public qualifier
476 */
477 313146 void QualType::getName(std::stringstream &name, bool withSize, bool ignorePublic) const {
478 // Append the qualifiers
479
3/6
✓ Branch 0 (2→3) taken 313146 times.
✗ Branch 1 (2→31) not taken.
✓ Branch 2 (3→4) taken 313146 times.
✗ Branch 3 (3→31) not taken.
✓ Branch 4 (4→5) taken 313146 times.
✗ Branch 5 (4→31) not taken.
313146 const TypeQualifiers defaultForSuperType = TypeQualifiers::of(getBase().getSuperType());
480
5/6
✓ Branch 0 (5→6) taken 228183 times.
✓ Branch 1 (5→9) taken 84963 times.
✓ Branch 2 (6→7) taken 79444 times.
✓ Branch 3 (6→9) taken 148739 times.
✓ Branch 4 (7→8) taken 79444 times.
✗ Branch 5 (7→9) not taken.
313146 if (!ignorePublic && qualifiers.isPublic && !defaultForSuperType.isPublic)
481
1/2
✓ Branch 0 (8→9) taken 79444 times.
✗ Branch 1 (8→32) not taken.
79444 name << "public ";
482
3/4
✓ Branch 0 (9→10) taken 4 times.
✓ Branch 1 (9→12) taken 313142 times.
✓ Branch 2 (10→11) taken 4 times.
✗ Branch 3 (10→12) not taken.
313146 if (qualifiers.isComposition && !defaultForSuperType.isComposition)
483
1/2
✓ Branch 0 (11→12) taken 4 times.
✗ Branch 1 (11→32) not taken.
4 name << "compose ";
484
8/8
✓ Branch 0 (12→13) taken 36280 times.
✓ Branch 1 (12→17) taken 276866 times.
✓ Branch 2 (13→14) taken 35399 times.
✓ Branch 3 (13→17) taken 881 times.
✓ Branch 4 (15→16) taken 27331 times.
✓ Branch 5 (15→17) taken 8068 times.
✓ Branch 6 (18→19) taken 27331 times.
✓ Branch 7 (18→20) taken 285815 times.
313146 if (qualifiers.isConst && !defaultForSuperType.isConst && type->typeChain.size() > 1)
485
1/2
✓ Branch 0 (19→20) taken 27331 times.
✗ Branch 1 (19→32) not taken.
27331 name << "const ";
486
3/4
✓ Branch 0 (20→21) taken 12230 times.
✓ Branch 1 (20→23) taken 300916 times.
✓ Branch 2 (21→22) taken 12230 times.
✗ Branch 3 (21→23) not taken.
313146 if (qualifiers.isHeap && !defaultForSuperType.isHeap)
487
1/2
✓ Branch 0 (22→23) taken 12230 times.
✗ Branch 1 (22→32) not taken.
12230 name << "heap ";
488
3/4
✓ Branch 0 (23→24) taken 29133 times.
✓ Branch 1 (23→26) taken 284013 times.
✗ Branch 2 (24→25) not taken.
✓ Branch 3 (24→26) taken 29133 times.
313146 if (qualifiers.isSigned && !defaultForSuperType.isSigned)
489 name << "signed ";
490
4/4
✓ Branch 0 (26→27) taken 284013 times.
✓ Branch 1 (26→29) taken 29133 times.
✓ Branch 2 (27→28) taken 29427 times.
✓ Branch 3 (27→29) taken 254586 times.
313146 if (!qualifiers.isSigned && defaultForSuperType.isSigned)
491
1/2
✓ Branch 0 (28→29) taken 29427 times.
✗ Branch 1 (28→32) not taken.
29427 name << "unsigned ";
492
493 // Loop through all chain elements
494
1/2
✓ Branch 0 (29→30) taken 313146 times.
✗ Branch 1 (29→32) not taken.
313146 type->getName(name, withSize);
495 313146 }
496
497 /**
498 * Get the name of the symbol type as a string
499 *
500 * @param withSize Include the array size for sized types
501 * @param ignorePublic Ignore any potential public qualifier
502 * @return Symbol type name
503 */
504 219974 std::string QualType::getName(bool withSize, bool ignorePublic) const {
505
1/2
✓ Branch 0 (2→3) taken 219974 times.
✗ Branch 1 (2→11) not taken.
219974 std::stringstream name;
506
1/2
✓ Branch 0 (3→4) taken 219974 times.
✗ Branch 1 (3→9) not taken.
219974 getName(name, withSize, ignorePublic);
507
1/2
✓ Branch 0 (4→5) taken 219974 times.
✗ Branch 1 (4→9) not taken.
439948 return name.str();
508 219974 }
509
510 /**
511 * Convert the type to an LLVM type
512 *
513 * @param sourceFile Source file
514 * @return LLVM type
515 */
516 195119 llvm::Type *QualType::toLLVMType(SourceFile *sourceFile) const { return sourceFile->getLLVMType(type); }
517
518 /**
519 * Retrieve the pointer type to this type
520 *
521 * @param node ASTNode
522 * @return New type
523 */
524 12270 QualType QualType::toPtr(const ASTNode *node) const {
525 12270 QualType newType = *this;
526
2/2
✓ Branch 0 (2→3) taken 12268 times.
✓ Branch 1 (2→5) taken 2 times.
12270 newType.type = type->toPtr(node);
527 12268 return newType;
528 }
529
530 /**
531 * Retrieve the reference type to this type
532 *
533 * @param node ASTNode
534 * @return New type
535 */
536 10310 QualType QualType::toRef(const ASTNode *node) const {
537 10310 QualType newType = *this;
538
1/2
✓ Branch 0 (2→3) taken 10310 times.
✗ Branch 1 (2→5) not taken.
10310 newType.type = type->toRef(node);
539 10310 return newType;
540 }
541
542 /**
543 * Retrieve the const reference type of this type
544 *
545 * @param node ASTNode
546 * @return New type
547 */
548 3506 QualType QualType::toConstRef(const ASTNode *node) const {
549
1/2
✓ Branch 0 (2→3) taken 3506 times.
✗ Branch 1 (2→6) not taken.
3506 QualType newType = toRef(node);
550 3506 newType.makeConst();
551 3506 return newType;
552 }
553
554 /**
555 * Retrieve the array type of this type
556 *
557 * @param node ASTNode
558 * @param size Array size
559 * @param skipDynCheck Skip dynamic check
560 * @return New type
561 */
562 199 QualType QualType::toArr(const ASTNode *node, size_t size, bool skipDynCheck /*=false*/) const {
563 199 QualType newType = *this;
564
2/2
✓ Branch 0 (2→3) taken 198 times.
✓ Branch 1 (2→5) taken 1 times.
199 newType.type = type->toArr(node, size, skipDynCheck);
565 198 return newType;
566 }
567
568 /**
569 * Retrieve the non-const type of this type
570 *
571 * @return New type
572 */
573 2423 QualType QualType::toNonConst() const {
574 2423 QualType newType = *this;
575 2423 newType.qualifiers.isConst = false;
576 2423 return newType;
577 }
578
579 /**
580 * Retrieve the contained type of this type
581 * This works on pointers, arrays, references and strings (which alias with char*)
582 *
583 * @return New type
584 */
585 51070 QualType QualType::getContained() const {
586
2/4
✓ Branch 0 (2→3) taken 51070 times.
✗ Branch 1 (2→8) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 51070 times.
51070 assert(isOneOf({TY_PTR, TY_REF, TY_ARRAY, TY_STRING}));
587 51070 QualType newType = *this;
588
1/2
✓ Branch 0 (5→6) taken 51070 times.
✗ Branch 1 (5→9) not taken.
51070 newType.type = type->getContained();
589 51070 return newType;
590 }
591
592 /**
593 * Retrieve the base type of this type
594 *
595 * @return New type
596 */
597 595182 QualType QualType::getBase() const {
598 595182 QualType newType = *this;
599
1/2
✓ Branch 0 (2→3) taken 595182 times.
✗ Branch 1 (2→5) not taken.
595182 newType.type = type->getBase();
600 595182 return newType;
601 }
602
603 /**
604 * Remove reference of this type, if it is a reference
605 *
606 * @return New type
607 */
608
2/2
✓ Branch 0 (3→4) taken 4333 times.
✓ Branch 1 (3→5) taken 166737 times.
171070 QualType QualType::removeReferenceWrapper() const { return isRef() ? getContained() : *this; }
609
610 /**
611 * Replace the base type with another one
612 *
613 * @param newBaseType New base type
614 * @return The new type
615 */
616 11312 QualType QualType::replaceBaseType(const QualType &newBaseType) const {
617 // Create new type
618
1/2
✓ Branch 0 (3→4) taken 11312 times.
✗ Branch 1 (3→9) not taken.
11312 const Type *newType = type->replaceBase(newBaseType.getType());
619 // Create new qualifiers
620
1/2
✓ Branch 0 (4→5) taken 11312 times.
✗ Branch 1 (4→9) not taken.
11312 TypeQualifiers newQualifiers = qualifiers.merge(newBaseType.qualifiers);
621 // Return the new qualified type
622 11312 return {newType, newQualifiers};
623 }
624
625 /**
626 * Retrieve the same type, but with lambda captures enabled
627 *
628 * @return Same type with lambda captures
629 */
630 45 QualType QualType::getWithLambdaCaptures(bool enabled /*=true*/) const {
631 // Create new type
632 45 const Type *newType = type->getWithLambdaCaptures(enabled);
633 // Return the new qualified type
634 45 return {newType, qualifiers};
635 }
636
637 /**
638 * Retrieve the same type, but with a new body scope
639 *
640 * @return Same type with body scope
641 */
642 22436 QualType QualType::getWithBodyScope(Scope *bodyScope) const {
643 // Create new type
644 22436 const Type *newType = type->getWithBodyScope(bodyScope);
645 // Return the new qualified type
646 22436 return {newType, qualifiers};
647 }
648
649 /**
650 * Retrieve the same type, but with new template types
651 *
652 * @param templateTypes New template types
653 * @return Same type with new template types
654 */
655 2974 QualType QualType::getWithTemplateTypes(const QualTypeList &templateTypes) const {
656 // Create new type
657 2974 const Type *newType = type->getWithTemplateTypes(templateTypes);
658 // Return the new qualified type
659 2974 return {newType, qualifiers};
660 }
661
662 /**
663 * Retrieve the same type, but with new base template types
664 *
665 * @param templateTypes New base template types
666 * @return Same type with new base template types
667 */
668 3642 QualType QualType::getWithBaseTemplateTypes(const QualTypeList &templateTypes) const {
669 // Create new type
670 3642 const Type *newType = type->getWithBaseTemplateTypes(templateTypes);
671 // Return the new qualified type
672 3642 return {newType, qualifiers};
673 }
674
675 /**
676 * Retrieve the same type, but with new function parameter and return types
677 *
678 * @param paramAndReturnTypes New parameter types
679 * @return Same type with new parameter types
680 */
681 10580 QualType QualType::getWithFunctionParamAndReturnTypes(const QualTypeList &paramAndReturnTypes) const {
682 // Create new type
683 10580 const Type *newType = type->getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
684 // Return the new qualified type
685 10580 return {newType, qualifiers};
686 }
687
688 10528 QualType QualType::getWithFunctionParamAndReturnTypes(const QualType &returnType, const QualTypeList &paramTypes) const {
689
1/2
✓ Branch 0 (2→3) taken 10528 times.
✗ Branch 1 (2→15) not taken.
10528 QualTypeList paramAndReturnTypes = paramTypes;
690
1/2
✓ Branch 0 (5→6) taken 10528 times.
✗ Branch 1 (5→11) not taken.
10528 paramAndReturnTypes.insert(paramAndReturnTypes.begin(), returnType);
691
1/2
✓ Branch 0 (6→7) taken 10528 times.
✗ Branch 1 (6→13) not taken.
21056 return getWithFunctionParamAndReturnTypes(paramAndReturnTypes);
692 10528 }
693
694 /**
695 * Check if the current type is const
696 *
697 * Examples for const types:
698 * - const int
699 * - const TestStruct
700 * - const string
701 *
702 * Examples for non-const types:
703 * - double (reason: not marked const)
704 * - const int* (reason: pointer to const int is not const itself)
705 * - const TestStruct& (reason: reference to const TestStruct is not const itself)
706 *
707 * @return Is const or not
708 */
709
4/4
✓ Branch 0 (3→4) taken 23101 times.
✓ Branch 1 (3→6) taken 2292 times.
✓ Branch 2 (4→5) taken 3374 times.
✓ Branch 3 (4→6) taken 19727 times.
25393 bool QualType::isConst() const { return isExtendedPrimitive() && qualifiers.isConst; }
710
711 /**
712 * Check if the current type is marked signed
713 *
714 * @return Is signed or not
715 */
716 12229 bool QualType::isSigned() const {
717
2/4
✓ Branch 0 (2→3) taken 12229 times.
✗ Branch 1 (2→7) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 12229 times.
12229 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
718 12229 return qualifiers.isSigned;
719 }
720
721 /**
722 * Check if the current type is marked unsigned
723 *
724 * @return Is unsigned or not
725 */
726 bool QualType::isUnsigned() const {
727 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
728 return qualifiers.isUnsigned;
729 }
730
731 /**
732 * Check if the current type is marked inline
733 *
734 * @return Is inline or not
735 */
736 7907 bool QualType::isInline() const {
737
2/4
✓ Branch 0 (2→3) taken 7907 times.
✗ Branch 1 (2→7) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 7907 times.
7907 assert(isOneOf({TY_FUNCTION, TY_PROCEDURE}));
738 7907 return qualifiers.isInline;
739 }
740
741 /**
742 * Check if the current type is marked public
743 *
744 * @return Is public or not
745 */
746 31859 bool QualType::isPublic() const {
747
5/8
✓ Branch 0 (2→3) taken 31859 times.
✗ Branch 1 (2→9) not taken.
✓ Branch 2 (3→4) taken 30997 times.
✓ Branch 3 (3→7) taken 862 times.
✓ Branch 4 (4→5) taken 30997 times.
✗ Branch 5 (4→9) not taken.
✗ Branch 6 (5→6) not taken.
✓ Branch 7 (5→7) taken 30997 times.
31859 assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE}));
748 31859 return qualifiers.isPublic;
749 }
750
751 /**
752 * Check if the current type is marked heap
753 *
754 * @return Is heap or not
755 */
756 11182 bool QualType::isHeap() const { return qualifiers.isHeap; }
757
758 /**
759 * Check if the current type is marked as composition
760 *
761 * @return Is composition or not
762 */
763 41 bool QualType::isComposition() const { return qualifiers.isComposition; }
764
765 /**
766 * Make the current type const
767 *
768 * @param isConst Is const or not
769 */
770 3506 void QualType::makeConst(bool isConst) { qualifiers.isConst = isConst; }
771
772 /**
773 * Make the current type unsigned
774 *
775 * @param isUnsigned Is unsigned or not
776 */
777 11 void QualType::makeUnsigned(bool isUnsigned) {
778
2/4
✓ Branch 0 (2→3) taken 11 times.
✗ Branch 1 (2→6) not taken.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 11 times.
11 assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
779 11 qualifiers.isSigned = !isUnsigned;
780 11 qualifiers.isUnsigned = isUnsigned;
781 11 }
782
783 /**
784 * Make the current type public
785 *
786 * @param isPublic Is public or not
787 */
788 282 void QualType::makePublic(bool isPublic) {
789
4/8
✓ Branch 0 (2→3) taken 282 times.
✗ Branch 1 (2→8) not taken.
✓ Branch 2 (3→4) taken 282 times.
✗ Branch 3 (3→7) not taken.
✓ Branch 4 (4→5) taken 282 times.
✗ Branch 5 (4→8) not taken.
✗ Branch 6 (5→6) not taken.
✓ Branch 7 (5→7) taken 282 times.
282 assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE}));
790 282 qualifiers.isPublic = isPublic;
791 282 }
792
793 /**
794 * Make the current type heap
795 *
796 * @param isHeap Is heap or not
797 */
798 45 void QualType::makeHeap(bool isHeap) { qualifiers.isHeap = isHeap; }
799
800 /**
801 * Check if two types are equal
802 *
803 * @param lhs Left-hand side type
804 * @param rhs Right-hand side type
805 * @return Equal or not
806 */
807 24643 bool operator==(const QualType &lhs, const QualType &rhs) { return lhs.type == rhs.type; }
808
809 /**
810 * Check if two types are not equal
811 *
812 * @param lhs Left-hand side type
813 * @param rhs Right-hand side type
814 * @return Not equal or not
815 */
816 1498 bool operator!=(const QualType &lhs, const QualType &rhs) { return !(lhs == rhs); }
817
818 /**
819 * Remove pointers / arrays / references if both types have them as far as possible.
820 * Furthermore, remove reference wrappers if possible.
821 *
822 * @param typeA Candidate type
823 * @param typeB Requested type
824 */
825 64651 void QualType::unwrapBoth(QualType &typeA, QualType &typeB) { Type::unwrapBoth(typeA.type, typeB.type); }
826
827 } // namespace spice::compiler
828