GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.8% 241 / 0 / 249
Functions: 100.0% 15 / 0 / 15
Branches: 59.0% 340 / 0 / 576

src/typechecker/TypeCheckerImplicit.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "TypeChecker.h"
4
5 #include <SourceFile.h>
6 #include <ast/ASTBuilder.h>
7 #include <ast/ASTNodes.h>
8 #include <global/GlobalResourceManager.h>
9 #include <symboltablebuilder/SymbolTableBuilder.h>
10 #include <typechecker/TypeMatcher.h>
11
12 namespace spice::compiler {
13
14 static const char *const FCT_NAME_DEALLOC = "sDealloc";
15
16 /**
17 * Create a default struct method
18 * Checks if the given struct scope already has a user-defined constructor and creates a default one if not.
19 *
20 * @param spiceStruct Struct instance
21 * @param entryName Name of the symbol table entry
22 * @param name Name of the method to create
23 * @param params Parameter types of the method
24 */
25 370 void TypeChecker::createDefaultStructMethod(const Struct &spiceStruct, const std::string &entryName, const std::string &name,
26 const ParamList &params) const {
27 370 Scope *structScope = spiceStruct.scope;
28 370 ASTNode *node = spiceStruct.declNode;
29 370 const SymbolTableEntry *structEntry = spiceStruct.entry;
30
1/2
✓ Branch 2 → 3 taken 370 times.
✗ Branch 2 → 81 not taken.
370 const QualType &structType = structEntry->getQualType();
31
3/6
✓ Branch 3 → 4 taken 370 times.
✗ Branch 3 → 55 not taken.
✓ Branch 4 → 5 taken 370 times.
✗ Branch 4 → 55 not taken.
✓ Branch 5 → 6 taken 370 times.
✗ Branch 5 → 53 not taken.
370 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + name;
32
33 // Procedure type
34
1/2
✓ Branch 7 → 8 taken 370 times.
✗ Branch 7 → 79 not taken.
370 QualType procedureType(TY_PROCEDURE);
35
1/2
✓ Branch 8 → 9 taken 370 times.
✗ Branch 8 → 79 not taken.
370 procedureType.makePublic(); // Always public
36
37 // Insert symbol for function into the symbol table
38
1/2
✓ Branch 9 → 10 taken 370 times.
✗ Branch 9 → 79 not taken.
370 SymbolTableEntry *procEntry = structScope->insert(entryName, structEntry->declNode);
39
1/2
✓ Branch 12 → 13 taken 370 times.
✗ Branch 12 → 79 not taken.
370 procEntry->updateType(procedureType, true);
40
41 // Add to external name registry
42
1/2
✓ Branch 13 → 14 taken 370 times.
✗ Branch 13 → 79 not taken.
370 sourceFile->addNameRegistryEntry(fqFctName, TY_PROCEDURE, procEntry, structScope, true);
43
44 // Create the default method
45
1/2
✓ Branch 14 → 15 taken 370 times.
✗ Branch 14 → 79 not taken.
370 const std::vector<GenericType> templateTypes = spiceStruct.templateTypes;
46
1/2
✓ Branch 15 → 16 taken 370 times.
✗ Branch 15 → 77 not taken.
370 const QualType returnType(TY_DYN);
47
3/6
✓ Branch 16 → 17 taken 370 times.
✗ Branch 16 → 62 not taken.
✓ Branch 17 → 18 taken 370 times.
✗ Branch 17 → 59 not taken.
✓ Branch 18 → 19 taken 370 times.
✗ Branch 18 → 56 not taken.
370 Function defaultMethod(name, procEntry, structType, returnType, params, templateTypes, structEntry->declNode);
48 370 defaultMethod.implicitDefault = true;
49
50 // Fill type mapping for the case, that the template type list contains non-generic types
51
2/2
✓ Branch 33 → 25 taken 234 times.
✓ Branch 33 → 34 taken 370 times.
604 for (const GenericType &templateType : templateTypes)
52
3/4
✓ Branch 26 → 27 taken 234 times.
✗ Branch 26 → 64 not taken.
✓ Branch 27 → 28 taken 4 times.
✓ Branch 27 → 31 taken 230 times.
234 if (!templateType.is(TY_GENERIC))
53
2/4
✓ Branch 28 → 29 taken 4 times.
✗ Branch 28 → 63 not taken.
✓ Branch 29 → 30 taken 4 times.
✗ Branch 29 → 63 not taken.
4 defaultMethod.typeMapping[templateType.getSubType()] = static_cast<QualType>(templateType);
54
55 // Create function scope
56
2/4
✓ Branch 34 → 35 taken 370 times.
✗ Branch 34 → 67 not taken.
✓ Branch 35 → 36 taken 370 times.
✗ Branch 35 → 65 not taken.
370 Scope *procScope = structScope->createChildScope(defaultMethod.getScopeName(), ScopeType::FUNC_PROC_BODY, &node->codeLoc);
57 370 defaultMethod.bodyScope = procScope;
58
59 // Create 'this' symbol in the function scope
60
1/2
✓ Branch 39 → 40 taken 370 times.
✗ Branch 39 → 70 not taken.
1110 SymbolTableEntry *thisEntry = procScope->insert(THIS_VARIABLE_NAME, node);
61
2/4
✓ Branch 45 → 46 taken 370 times.
✗ Branch 45 → 74 not taken.
✓ Branch 46 → 47 taken 370 times.
✗ Branch 46 → 74 not taken.
370 thisEntry->updateType(structType.toPtr(node), true);
62 370 thisEntry->used = true; // Always set to used to not print warnings for non-existing code
63
64 // Hand it off to the function manager to register the function
65
2/4
✓ Branch 47 → 48 taken 370 times.
✗ Branch 47 → 75 not taken.
✓ Branch 48 → 49 taken 370 times.
✗ Branch 48 → 75 not taken.
370 FunctionManager::insert(structScope, defaultMethod, structEntry->declNode->getFctManifestations(name));
66 370 }
67
68 /**
69 * Checks if the given struct scope already has a user-defined constructor and creates a default one if not.
70 *
71 * For generating a default ctor, the following conditions need to be met:
72 * - No user-defined constructors (incl. copy/move ctors)
73 *
74 * @param spiceStruct Struct instance
75 * @param structScope Scope of the struct
76 */
77 730 void TypeChecker::createDefaultCtorIfRequired(const Struct &spiceStruct, Scope *structScope) const {
78
1/2
✓ Branch 2 → 3 taken 730 times.
✗ Branch 2 → 4 not taken.
730 const auto node = spice_pointer_cast<StructDefNode *>(spiceStruct.declNode);
79
2/4
✓ Branch 9 → 10 taken 730 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 730 times.
✗ Branch 10 → 12 not taken.
730 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
80
81 // Abort if the struct already has a user-defined constructor
82 730 const SymbolTableEntry *structEntry = spiceStruct.entry;
83
1/2
✓ Branch 13 → 14 taken 730 times.
✗ Branch 13 → 125 not taken.
730 const QualType &structType = structEntry->getQualType();
84
3/6
✓ Branch 14 → 15 taken 730 times.
✗ Branch 14 → 98 not taken.
✓ Branch 15 → 16 taken 730 times.
✗ Branch 15 → 98 not taken.
✓ Branch 16 → 17 taken 730 times.
✗ Branch 16 → 96 not taken.
730 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + CTOR_FUNCTION_NAME;
85
3/4
✓ Branch 18 → 19 taken 730 times.
✗ Branch 18 → 123 not taken.
✓ Branch 19 → 20 taken 565 times.
✓ Branch 19 → 21 taken 165 times.
730 if (sourceFile->getNameRegistryEntry(fqFctName))
86 565 return;
87
88 // Check if we have fields, that require us to do anything in the ctor
89
1/2
✓ Branch 21 → 22 taken 165 times.
✗ Branch 21 → 123 not taken.
165 const size_t fieldCount = structScope->getFieldCount();
90 165 bool hasFieldsWithDefaultValue = false;
91 165 bool hasFieldsToConstruct = false;
92
2/2
✓ Branch 74 → 23 taken 360 times.
✓ Branch 74 → 75 taken 157 times.
517 for (size_t i = 0; i < fieldCount; i++) {
93
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 360 times.
360 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
94
2/4
✓ Branch 28 → 29 taken 360 times.
✗ Branch 28 → 31 not taken.
✓ Branch 29 → 30 taken 360 times.
✗ Branch 29 → 31 not taken.
360 assert(fieldSymbol != nullptr && fieldSymbol->declNode != nullptr);
95
96
1/2
✓ Branch 32 → 33 taken 360 times.
✗ Branch 32 → 111 not taken.
360 QualType fieldType = fieldSymbol->getQualType();
97
5/8
✓ Branch 33 → 34 taken 360 times.
✗ Branch 33 → 111 not taken.
✓ Branch 34 → 35 taken 86 times.
✓ Branch 34 → 38 taken 274 times.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 86 times.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 360 times.
360 if (fieldType.hasAnyGenericParts() && !spiceStruct.typeMapping.empty())
98 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, spiceStruct.typeMapping, fieldSymbol->declNode);
99
100 // Abort if we have a field, that is a reference
101
3/4
✓ Branch 41 → 42 taken 360 times.
✗ Branch 41 → 111 not taken.
✓ Branch 42 → 43 taken 5 times.
✓ Branch 42 → 44 taken 355 times.
360 if (fieldType.isRef())
102 8 return;
103
104
3/4
✓ Branch 44 → 45 taken 355 times.
✗ Branch 44 → 46 not taken.
✓ Branch 47 → 48 taken 321 times.
✓ Branch 47 → 49 taken 34 times.
355 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldSymbol->declNode)) {
105 321 hasFieldsWithDefaultValue |= fieldNode->defaultValue != nullptr;
106 } else {
107
2/4
✓ Branch 49 → 50 taken 34 times.
✗ Branch 49 → 51 not taken.
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 54 taken 34 times.
34 assert(dynamic_cast<DataTypeNode *>(fieldSymbol->declNode) != nullptr);
108 }
109
110
3/4
✓ Branch 54 → 55 taken 355 times.
✗ Branch 54 → 111 not taken.
✓ Branch 55 → 56 taken 30 times.
✓ Branch 55 → 72 taken 325 times.
355 if (fieldType.is(TY_STRUCT)) {
111
1/2
✓ Branch 56 → 57 taken 30 times.
✗ Branch 56 → 111 not taken.
30 Scope *bodyScope = fieldType.getBodyScope();
112 // Check if we are required to call a ctor
113
1/2
✓ Branch 57 → 58 taken 30 times.
✗ Branch 57 → 111 not taken.
30 const bool isCtorCallRequired = !fieldType.isTriviallyConstructible(node);
114 // Lookup ctor function
115
2/4
✓ Branch 62 → 63 taken 30 times.
✗ Branch 62 → 101 not taken.
✓ Branch 63 → 64 taken 30 times.
✗ Branch 63 → 99 not taken.
90 const Function *ctorFct = FunctionManager::match(bodyScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, true, node);
116 // If we are required to construct, but no constructor is found, we can't generate a default ctor for the outer struct
117
4/4
✓ Branch 68 → 69 taken 12 times.
✓ Branch 68 → 71 taken 18 times.
✓ Branch 69 → 70 taken 3 times.
✓ Branch 69 → 71 taken 9 times.
30 if (!ctorFct && isCtorCallRequired)
118 3 return;
119 27 hasFieldsToConstruct |= ctorFct != nullptr;
120 }
121 }
122
123 // If we don't have any fields, that require us to do anything in the ctor, we can skip it
124
6/6
✓ Branch 75 → 76 taken 113 times.
✓ Branch 75 → 79 taken 44 times.
✓ Branch 76 → 77 taken 97 times.
✓ Branch 76 → 79 taken 16 times.
✓ Branch 77 → 78 taken 89 times.
✓ Branch 77 → 79 taken 8 times.
157 if (!hasFieldsWithDefaultValue && !hasFieldsToConstruct && !node->emitVTable)
125 89 return;
126
127 // Create the default ctor function
128
1/2
✓ Branch 79 → 80 taken 68 times.
✗ Branch 79 → 123 not taken.
68 const std::string entryName = Function::getSymbolTableEntryNameDefaultCtor(node->codeLoc);
129
2/4
✓ Branch 83 → 84 taken 68 times.
✗ Branch 83 → 114 not taken.
✓ Branch 84 → 85 taken 68 times.
✗ Branch 84 → 112 not taken.
204 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, {});
130
2/2
✓ Branch 91 → 92 taken 68 times.
✓ Branch 91 → 94 taken 662 times.
730 }
131
132 /**
133 * Checks if the given struct scope already has a user-defined constructor and creates a default one if not.
134 *
135 * For generating a default copy ctor, the following conditions need to be met:
136 * - No user-defined copy ctor
137 * - No user-defined move ctor
138 *
139 * @param spiceStruct Struct instance
140 * @param structScope Scope of the struct
141 */
142 730 void TypeChecker::createDefaultCopyCtorIfRequired(const Struct &spiceStruct, Scope *structScope) const {
143
1/2
✓ Branch 2 → 3 taken 730 times.
✗ Branch 2 → 4 not taken.
730 const auto node = spice_pointer_cast<const StructDefNode *>(spiceStruct.declNode);
144
2/4
✓ Branch 9 → 10 taken 730 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 730 times.
✗ Branch 10 → 12 not taken.
730 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
145
146 // Abort if the struct already has a user-defined copy constructor
147
1/2
✓ Branch 13 → 14 taken 730 times.
✗ Branch 13 → 154 not taken.
730 const QualType structType = spiceStruct.entry->getQualType();
148
2/4
✓ Branch 14 → 15 taken 730 times.
✗ Branch 14 → 111 not taken.
✓ Branch 18 → 19 taken 730 times.
✗ Branch 18 → 107 not taken.
2190 const ArgList lookupArgs = {{structType.toConstRef(node), true}};
149
2/4
✓ Branch 22 → 23 taken 730 times.
✗ Branch 22 → 115 not taken.
✓ Branch 23 → 24 taken 730 times.
✗ Branch 23 → 113 not taken.
730 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, structType, lookupArgs, true);
150
2/2
✓ Branch 26 → 27 taken 142 times.
✓ Branch 26 → 28 taken 588 times.
730 if (copyCtor != nullptr)
151 142 return;
152
153 // Abort if the struct has a user-defined move constructor
154 // ToDo: Check for move ctor
155
156 // Check if we have fields, that require us to do anything in the ctor
157
1/2
✓ Branch 28 → 29 taken 588 times.
✗ Branch 28 → 152 not taken.
588 const size_t fieldCount = structScope->getFieldCount();
158 588 bool copyCtorRequired = false;
159
2/2
✓ Branch 82 → 30 taken 1219 times.
✓ Branch 82 → 83 taken 549 times.
1768 for (size_t i = 0; i < fieldCount; i++) {
160
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 1219 times.
1219 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
161
2/4
✓ Branch 35 → 36 taken 1219 times.
✗ Branch 35 → 38 not taken.
✓ Branch 36 → 37 taken 1219 times.
✗ Branch 36 → 38 not taken.
1219 assert(fieldSymbol != nullptr && fieldSymbol->declNode != nullptr);
162
163
1/2
✓ Branch 39 → 40 taken 1219 times.
✗ Branch 39 → 137 not taken.
1219 QualType fieldType = fieldSymbol->getQualType();
164
5/8
✓ Branch 40 → 41 taken 1219 times.
✗ Branch 40 → 137 not taken.
✓ Branch 41 → 42 taken 416 times.
✓ Branch 41 → 45 taken 803 times.
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 416 times.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 48 taken 1219 times.
1219 if (fieldType.hasAnyGenericParts() && !spiceStruct.typeMapping.empty())
165 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, spiceStruct.typeMapping, fieldSymbol->declNode);
166
167 // If the field is of type struct, check if this struct has a copy ctor that has to be called
168
3/4
✓ Branch 48 → 49 taken 1219 times.
✗ Branch 48 → 137 not taken.
✓ Branch 49 → 50 taken 166 times.
✓ Branch 49 → 75 taken 1053 times.
1219 if (fieldType.is(TY_STRUCT)) {
169
1/2
✓ Branch 50 → 51 taken 166 times.
✗ Branch 50 → 136 not taken.
166 Scope *bodyScope = fieldType.getBodyScope();
170 // Check if we are required to call a ctor
171
1/2
✓ Branch 51 → 52 taken 166 times.
✗ Branch 51 → 136 not taken.
166 const bool isCopyCtorCallRequired = !structType.isTriviallyCopyable(node);
172 // Lookup copy ctor function
173
2/4
✓ Branch 52 → 53 taken 166 times.
✗ Branch 52 → 123 not taken.
✓ Branch 56 → 57 taken 166 times.
✗ Branch 56 → 119 not taken.
332 const ArgList args = {{fieldType.toConstRef(node), false /* we always have the field as storage */}};
174
2/4
✓ Branch 61 → 62 taken 166 times.
✗ Branch 61 → 127 not taken.
✓ Branch 62 → 63 taken 166 times.
✗ Branch 62 → 125 not taken.
498 const Function *ctorFct = FunctionManager::match(bodyScope, CTOR_FUNCTION_NAME, fieldType, args, {}, true, node);
175 // If we are required to construct, but no constructor is found, we can't generate a default ctor for the outer struct
176
4/4
✓ Branch 66 → 67 taken 102 times.
✓ Branch 66 → 69 taken 64 times.
✓ Branch 67 → 68 taken 39 times.
✓ Branch 67 → 69 taken 63 times.
166 if (!ctorFct && isCopyCtorCallRequired)
177 39 return;
178 127 copyCtorRequired |= ctorFct != nullptr;
179
2/2
✓ Branch 71 → 72 taken 127 times.
✓ Branch 71 → 74 taken 39 times.
166 }
180
181 // If we have an owning heap pointer, we need to do a memcpy of the heap storage and therefore need a default copy ctor
182
3/4
✓ Branch 75 → 76 taken 1180 times.
✗ Branch 75 → 137 not taken.
✓ Branch 76 → 77 taken 32 times.
✓ Branch 76 → 81 taken 1148 times.
1180 if (fieldType.isHeap()) {
183
2/4
✓ Branch 77 → 78 taken 32 times.
✗ Branch 77 → 137 not taken.
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 32 times.
32 assert(fieldType.isPtr());
184 32 copyCtorRequired = true;
185 }
186 }
187
188 // If we don't have any fields, that require us to do anything in the copy ctor, we can skip it
189
4/4
✓ Branch 83 → 84 taken 483 times.
✓ Branch 83 → 86 taken 66 times.
✓ Branch 84 → 85 taken 354 times.
✓ Branch 84 → 86 taken 129 times.
549 if (!copyCtorRequired && !node->emitVTable)
190 354 return;
191
192 // Create the default copy ctor function
193
1/2
✓ Branch 86 → 87 taken 195 times.
✗ Branch 86 → 152 not taken.
195 const std::string entryName = Function::getSymbolTableEntryNameDefaultCopyCtor(node->codeLoc);
194
2/4
✓ Branch 87 → 88 taken 195 times.
✗ Branch 87 → 141 not taken.
✓ Branch 90 → 91 taken 195 times.
✗ Branch 90 → 138 not taken.
585 const ParamList paramTypes = {{structType.toConstRef(node), false}};
195
2/4
✓ Branch 94 → 95 taken 195 times.
✗ Branch 94 → 144 not taken.
✓ Branch 95 → 96 taken 195 times.
✗ Branch 95 → 142 not taken.
195 createDefaultStructMethod(spiceStruct, entryName, CTOR_FUNCTION_NAME, paramTypes);
196
2/2
✓ Branch 102 → 103 taken 195 times.
✓ Branch 102 → 105 taken 535 times.
730 }
197
198 /**
199 * Checks if the given struct scope already has a user-defined destructor and creates a default one if not.
200 *
201 * For generating a default dtor, the following conditions need to be met:
202 * - No user-defined dtor
203 *
204 * @param spiceStruct Struct instance
205 * @param structScope Scope of the struct
206 */
207 730 void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope *structScope) const {
208 730 const ASTNode *node = spiceStruct.declNode;
209
2/4
✓ Branch 2 → 3 taken 730 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 730 times.
✗ Branch 3 → 5 not taken.
730 assert(structScope != nullptr && structScope->type == ScopeType::STRUCT);
210
211 // Abort if the struct already has a user-defined destructor
212 730 const SymbolTableEntry *structEntry = spiceStruct.entry;
213
1/2
✓ Branch 6 → 7 taken 730 times.
✗ Branch 6 → 153 not taken.
730 const QualType &structType = structEntry->getQualType();
214
3/6
✓ Branch 7 → 8 taken 730 times.
✗ Branch 7 → 107 not taken.
✓ Branch 8 → 9 taken 730 times.
✗ Branch 8 → 107 not taken.
✓ Branch 9 → 10 taken 730 times.
✗ Branch 9 → 105 not taken.
730 const std::string fqFctName = structType.getSubType() + MEMBER_ACCESS_TOKEN + DTOR_FUNCTION_NAME;
215
3/4
✓ Branch 11 → 12 taken 730 times.
✗ Branch 11 → 151 not taken.
✓ Branch 12 → 13 taken 119 times.
✓ Branch 12 → 14 taken 611 times.
730 if (sourceFile->getNameRegistryEntry(fqFctName))
216 119 return;
217
218 // Check we have field types, that require use to do anything in the destructor
219
1/2
✓ Branch 14 → 15 taken 611 times.
✗ Branch 14 → 151 not taken.
611 const size_t fieldCount = structScope->getFieldCount();
220 611 bool hasFieldsToDeAllocate = false;
221 611 bool hasFieldsToDestruct = false;
222
2/2
✓ Branch 50 → 16 taken 1384 times.
✓ Branch 50 → 51 taken 611 times.
1995 for (size_t i = 0; i < fieldCount; i++) {
223
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1384 times.
1384 const SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
224
2/4
✓ Branch 21 → 22 taken 1384 times.
✗ Branch 21 → 24 not taken.
✓ Branch 22 → 23 taken 1384 times.
✗ Branch 22 → 24 not taken.
1384 assert(fieldSymbol != nullptr && fieldSymbol->declNode != nullptr);
225
226
1/2
✓ Branch 25 → 26 taken 1384 times.
✗ Branch 25 → 120 not taken.
1384 QualType fieldType = fieldSymbol->getQualType();
227
5/8
✓ Branch 26 → 27 taken 1384 times.
✗ Branch 26 → 120 not taken.
✓ Branch 27 → 28 taken 504 times.
✓ Branch 27 → 31 taken 880 times.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 504 times.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 1384 times.
1384 if (fieldType.hasAnyGenericParts() && !spiceStruct.typeMapping.empty())
228 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, spiceStruct.typeMapping, fieldSymbol->declNode);
229
230
1/2
✓ Branch 34 → 35 taken 1384 times.
✗ Branch 34 → 120 not taken.
1384 hasFieldsToDeAllocate |= fieldType.needsDeAllocation();
231
3/4
✓ Branch 35 → 36 taken 1384 times.
✗ Branch 35 → 120 not taken.
✓ Branch 36 → 37 taken 170 times.
✓ Branch 36 → 49 taken 1214 times.
1384 if (fieldType.is(TY_STRUCT)) {
232
1/2
✓ Branch 37 → 38 taken 170 times.
✗ Branch 37 → 120 not taken.
170 Scope *fieldScope = fieldType.getBodyScope();
233 // Lookup dtor function
234
2/4
✓ Branch 42 → 43 taken 170 times.
✗ Branch 42 → 110 not taken.
✓ Branch 43 → 44 taken 170 times.
✗ Branch 43 → 108 not taken.
510 const Function *dtorFct = FunctionManager::match(fieldScope, DTOR_FUNCTION_NAME, fieldType, {}, {}, true, node);
235 170 hasFieldsToDestruct |= dtorFct != nullptr;
236
1/2
✓ Branch 48 → 49 taken 170 times.
✗ Branch 48 → 120 not taken.
170 requestRevisitIfRequired(dtorFct);
237 }
238 }
239
240 // If we don't have any fields, that require us to do anything in the dtor, we can skip it
241
4/4
✓ Branch 51 → 52 taken 548 times.
✓ Branch 51 → 54 taken 63 times.
✓ Branch 52 → 53 taken 504 times.
✓ Branch 52 → 54 taken 44 times.
611 if (!hasFieldsToDeAllocate && !hasFieldsToDestruct)
242 504 return;
243
244 // Create the default dtor function
245
1/2
✓ Branch 54 → 55 taken 107 times.
✗ Branch 54 → 151 not taken.
107 const std::string entryName = Function::getSymbolTableEntryNameDefaultDtor(node->codeLoc);
246
2/4
✓ Branch 58 → 59 taken 107 times.
✗ Branch 58 → 123 not taken.
✓ Branch 59 → 60 taken 107 times.
✗ Branch 59 → 121 not taken.
321 createDefaultStructMethod(spiceStruct, entryName, DTOR_FUNCTION_NAME, {});
247
248 // Request memory runtime if we have fields, that are allocated on the heap
249 // The string runtime does not use it, but allocates manually to avoid circular dependencies
250
6/8
✓ Branch 63 → 64 taken 63 times.
✓ Branch 63 → 69 taken 44 times.
✓ Branch 64 → 65 taken 63 times.
✗ Branch 64 → 149 not taken.
✓ Branch 67 → 68 taken 63 times.
✗ Branch 67 → 69 not taken.
✓ Branch 70 → 71 taken 63 times.
✓ Branch 70 → 97 taken 44 times.
170 if (hasFieldsToDeAllocate && !sourceFile->isStringRT()) {
251
1/2
✓ Branch 71 → 72 taken 63 times.
✗ Branch 71 → 148 not taken.
63 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
252
1/2
✗ Branch 72 → 73 not taken.
✓ Branch 72 → 74 taken 63 times.
63 assert(memoryRT != nullptr);
253 63 Scope *matchScope = memoryRT->globalScope.get();
254 // Set dealloc function to used
255
1/2
✓ Branch 75 → 76 taken 63 times.
✗ Branch 75 → 148 not taken.
63 const QualType thisType(TY_DYN);
256
3/6
✓ Branch 76 → 77 taken 63 times.
✗ Branch 76 → 130 not taken.
✓ Branch 77 → 78 taken 63 times.
✗ Branch 77 → 130 not taken.
✓ Branch 78 → 79 taken 63 times.
✗ Branch 78 → 130 not taken.
63 QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node);
257
1/2
✓ Branch 79 → 80 taken 63 times.
✗ Branch 79 → 148 not taken.
63 bytePtrRefType.makeHeap();
258
1/2
✓ Branch 83 → 84 taken 63 times.
✗ Branch 83 → 132 not taken.
126 const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}};
259
2/4
✓ Branch 88 → 89 taken 63 times.
✗ Branch 88 → 139 not taken.
✓ Branch 89 → 90 taken 63 times.
✗ Branch 89 → 137 not taken.
189 Function *deallocFct = FunctionManager::match(matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
260
1/2
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 63 times.
63 assert(deallocFct != nullptr);
261 63 deallocFct->used = true;
262 63 }
263
2/2
✓ Branch 100 → 101 taken 107 times.
✓ Branch 100 → 103 taken 623 times.
730 }
264
265 /**
266 * Prepare the generation of the ctor body preamble. This preamble is used to initialize the VTable, construct or initialize
267 * fields.
268 */
269 1492 void TypeChecker::createCtorBodyPreamble(const Scope *bodyScope) const {
270 // Retrieve struct scope
271 1492 Scope *structScope = bodyScope->parent;
272
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1492 times.
1492 assert(structScope != nullptr);
273
274 1492 const size_t fieldCount = structScope->getFieldCount();
275
2/2
✓ Branch 54 → 6 taken 3733 times.
✓ Branch 54 → 55 taken 1492 times.
5225 for (size_t i = 0; i < fieldCount; i++) {
276
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 3733 times.
3733 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
277
3/6
✓ Branch 11 → 12 taken 3733 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 3733 times.
✗ Branch 12 → 70 not taken.
✓ Branch 13 → 14 taken 3733 times.
✗ Branch 13 → 15 not taken.
3733 assert(fieldSymbol != nullptr && fieldSymbol->isField());
278
2/2
✓ Branch 16 → 17 taken 253 times.
✓ Branch 16 → 18 taken 3480 times.
3733 if (fieldSymbol->isImplicitField)
279 283 continue;
280
281
1/2
✓ Branch 18 → 19 taken 3480 times.
✗ Branch 18 → 70 not taken.
3480 QualType fieldType = fieldSymbol->getQualType();
282
3/4
✓ Branch 19 → 20 taken 3480 times.
✗ Branch 19 → 70 not taken.
✓ Branch 20 → 21 taken 530 times.
✓ Branch 20 → 22 taken 2950 times.
3480 if (fieldType.hasAnyGenericParts())
283
1/2
✓ Branch 21 → 22 taken 530 times.
✗ Branch 21 → 70 not taken.
530 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
284
285
3/4
✓ Branch 22 → 23 taken 3480 times.
✗ Branch 22 → 70 not taken.
✓ Branch 23 → 24 taken 455 times.
✓ Branch 23 → 50 taken 3025 times.
3480 if (fieldType.is(TY_STRUCT)) {
286
1/2
✓ Branch 24 → 25 taken 455 times.
✗ Branch 24 → 26 not taken.
455 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
287 // Match ctor function, create the concrete manifestation and set it to used
288
1/2
✓ Branch 31 → 32 taken 455 times.
✗ Branch 31 → 70 not taken.
455 Scope *matchScope = fieldType.getBodyScope();
289
2/4
✓ Branch 36 → 37 taken 455 times.
✗ Branch 36 → 58 not taken.
✓ Branch 37 → 38 taken 455 times.
✗ Branch 37 → 56 not taken.
1365 const Function *spiceFunc = FunctionManager::match(matchScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
290
2/2
✓ Branch 42 → 43 taken 404 times.
✓ Branch 42 → 47 taken 51 times.
455 if (spiceFunc != nullptr)
291
3/6
✓ Branch 43 → 44 taken 404 times.
✗ Branch 43 → 68 not taken.
✓ Branch 44 → 45 taken 404 times.
✗ Branch 44 → 68 not taken.
✓ Branch 45 → 46 taken 404 times.
✗ Branch 45 → 68 not taken.
404 fieldSymbol->updateType(fieldType.getWithBodyScope(spiceFunc->thisType.getBodyScope()), true);
292
3/4
✓ Branch 47 → 48 taken 51 times.
✗ Branch 47 → 70 not taken.
✓ Branch 48 → 49 taken 30 times.
✓ Branch 48 → 50 taken 21 times.
51 else if (!fieldType.isTriviallyConstructible(fieldNode))
293 30 continue;
294 }
295
296
1/2
✓ Branch 50 → 51 taken 3450 times.
✗ Branch 50 → 69 not taken.
3450 fieldSymbol->updateState(INITIALIZED, fieldSymbol->declNode);
297 }
298 1492 }
299
300 /**
301 * Prepare the generation of the copy ctor body preamble. This preamble is used to initialize the VTable, construct or initialize
302 * fields.
303 */
304 149 void TypeChecker::createCopyCtorBodyPreamble(const Scope *bodyScope) const {
305 // Retrieve struct scope
306 149 Scope *structScope = bodyScope->parent;
307
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 149 times.
149 assert(structScope != nullptr);
308
309 149 const size_t fieldCount = structScope->getFieldCount();
310
2/2
✓ Branch 64 → 6 taken 284 times.
✓ Branch 64 → 65 taken 149 times.
433 for (size_t i = 0; i < fieldCount; i++) {
311
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 284 times.
284 SymbolTableEntry *fieldSymbol = structScope->lookupField(i);
312
3/6
✓ Branch 11 → 12 taken 284 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 284 times.
✗ Branch 12 → 86 not taken.
✓ Branch 13 → 14 taken 284 times.
✗ Branch 13 → 15 not taken.
284 assert(fieldSymbol != nullptr && fieldSymbol->isField());
313
2/2
✓ Branch 16 → 17 taken 43 times.
✓ Branch 16 → 18 taken 241 times.
284 if (fieldSymbol->isImplicitField)
314 43 continue;
315
316
1/2
✓ Branch 18 → 19 taken 241 times.
✗ Branch 18 → 86 not taken.
241 QualType fieldType = fieldSymbol->getQualType();
317
2/4
✓ Branch 19 → 20 taken 241 times.
✗ Branch 19 → 86 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 241 times.
241 if (fieldType.hasAnyGenericParts())
318 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
319
320
3/4
✓ Branch 22 → 23 taken 241 times.
✗ Branch 22 → 86 not taken.
✓ Branch 23 → 24 taken 99 times.
✓ Branch 23 → 60 taken 142 times.
241 if (fieldType.is(TY_STRUCT)) {
321
1/2
✓ Branch 24 → 25 taken 99 times.
✗ Branch 24 → 26 not taken.
99 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
322 // Match ctor function, create the concrete manifestation and set it to used
323
1/2
✓ Branch 31 → 32 taken 99 times.
✗ Branch 31 → 84 not taken.
99 Scope *matchScope = fieldType.getBodyScope();
324
2/4
✓ Branch 32 → 33 taken 99 times.
✗ Branch 32 → 70 not taken.
✓ Branch 36 → 37 taken 99 times.
✗ Branch 36 → 66 not taken.
198 const ArgList args = {{fieldType.toConstRef(fieldNode), false /* we always have the field as storage */}};
325
2/4
✓ Branch 41 → 42 taken 99 times.
✗ Branch 41 → 74 not taken.
✓ Branch 42 → 43 taken 99 times.
✗ Branch 42 → 72 not taken.
297 const Function *copyCtorFct = FunctionManager::match(matchScope, CTOR_FUNCTION_NAME, fieldType, args, {}, false, fieldNode);
326
1/2
✓ Branch 46 → 47 taken 99 times.
✗ Branch 46 → 51 not taken.
99 if (copyCtorFct != nullptr)
327
3/6
✓ Branch 47 → 48 taken 99 times.
✗ Branch 47 → 81 not taken.
✓ Branch 48 → 49 taken 99 times.
✗ Branch 48 → 81 not taken.
✓ Branch 49 → 50 taken 99 times.
✗ Branch 49 → 81 not taken.
99 fieldSymbol->updateType(fieldType.getWithBodyScope(copyCtorFct->thisType.getBodyScope()), true);
328 else if (!fieldType.isTriviallyCopyable(fieldNode))
329 continue;
330
1/2
✓ Branch 56 → 57 taken 99 times.
✗ Branch 56 → 59 not taken.
99 }
331
332
1/2
✓ Branch 60 → 61 taken 241 times.
✗ Branch 60 → 85 not taken.
241 fieldSymbol->updateState(INITIALIZED, fieldSymbol->declNode);
333 }
334 149 }
335
336 /**
337 * Prepare the generation of the dtor body preamble. This preamble is used to destruct all fields and to free all heap fields.
338 */
339 231 void TypeChecker::createDtorBodyPreamble(const Scope *bodyScope) const {
340 // Retrieve struct scope
341 231 Scope *structScope = bodyScope->parent;
342
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 231 times.
231 assert(structScope != nullptr);
343
344 231 const size_t fieldCount = structScope->getFieldCount();
345
2/2
✓ Branch 45 → 6 taken 813 times.
✓ Branch 45 → 46 taken 231 times.
1044 for (size_t i = 0; i < fieldCount; i++) {
346 813 const size_t fieldIdx = fieldCount - 1 - i; // Destruct fields in reverse order
347
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 813 times.
813 const SymbolTableEntry *fieldSymbol = structScope->lookupField(fieldIdx);
348
3/6
✓ Branch 11 → 12 taken 813 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 813 times.
✗ Branch 12 → 59 not taken.
✓ Branch 13 → 14 taken 813 times.
✗ Branch 13 → 15 not taken.
813 assert(fieldSymbol != nullptr && fieldSymbol->isField());
349
2/2
✓ Branch 16 → 17 taken 150 times.
✓ Branch 16 → 18 taken 663 times.
813 if (fieldSymbol->isImplicitField)
350 150 continue;
351
352
1/2
✓ Branch 18 → 19 taken 663 times.
✗ Branch 18 → 59 not taken.
663 QualType fieldType = fieldSymbol->getQualType();
353
2/4
✓ Branch 19 → 20 taken 663 times.
✗ Branch 19 → 59 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 663 times.
663 if (fieldType.hasAnyGenericParts())
354 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, fieldSymbol->declNode);
355
356
3/4
✓ Branch 22 → 23 taken 663 times.
✗ Branch 22 → 59 not taken.
✓ Branch 23 → 24 taken 159 times.
✓ Branch 23 → 43 taken 504 times.
663 if (fieldType.is(TY_STRUCT)) {
357
1/2
✓ Branch 24 → 25 taken 159 times.
✗ Branch 24 → 26 not taken.
159 const auto fieldNode = spice_pointer_cast<const FieldNode *>(fieldSymbol->declNode);
358 // Match ctor function, create the concrete manifestation and set it to used
359
1/2
✓ Branch 31 → 32 taken 159 times.
✗ Branch 31 → 59 not taken.
159 Scope *matchScope = fieldType.getBodyScope();
360
2/4
✓ Branch 36 → 37 taken 159 times.
✗ Branch 36 → 49 not taken.
✓ Branch 37 → 38 taken 159 times.
✗ Branch 37 → 47 not taken.
477 FunctionManager::match(matchScope, DTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
361 }
362 }
363 231 }
364
365 /**
366 * Prepare the generation of a call to a method of a given struct
367 *
368 * @param entry Symbol entry to use as 'this' pointer for the method call
369 * @param methodName Name of the method to call
370 * @param args Provided arguments by the caller
371 * @param node AST node
372 */
373 1460 Function *TypeChecker::implicitlyCallStructMethod(const SymbolTableEntry *entry, const std::string &methodName,
374 const ArgList &args, const ASTNode *node) const {
375
3/6
✓ Branch 2 → 3 taken 1460 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 1460 times.
✗ Branch 3 → 9 not taken.
✓ Branch 4 → 5 taken 1460 times.
✗ Branch 4 → 9 not taken.
1460 const QualType thisType = entry->getQualType().removeReferenceWrapper().toNonConst();
376
1/2
✓ Branch 5 → 6 taken 1460 times.
✗ Branch 5 → 10 not taken.
2920 return implicitlyCallStructMethod(thisType, methodName, args, node);
377 }
378
379 /**
380 * Prepare the generation of a call to a method of a given struct
381 *
382 * @param thisType Struct type to call the method on
383 * @param methodName Name of the method to call
384 * @param args Provided arguments by the caller
385 * @param node AST node
386 */
387 1718 Function *TypeChecker::implicitlyCallStructMethod(QualType thisType, const std::string &methodName, const ArgList &args,
388 const ASTNode *node) const {
389
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1718 times.
1718 assert(thisType.is(TY_STRUCT));
390 1718 Scope *matchScope = thisType.getBodyScope();
391
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1718 times.
1718 assert(matchScope->type == ScopeType::STRUCT);
392
393 // Search for dtor
394
2/2
✓ Branch 9 → 10 taken 914 times.
✓ Branch 9 → 12 taken 804 times.
1718 if (matchScope->isImportedBy(rootScope))
395
1/2
✓ Branch 10 → 11 taken 914 times.
✗ Branch 10 → 18 not taken.
914 thisType = mapLocalTypeToImportedScopeType(matchScope, thisType);
396
1/2
✓ Branch 13 → 14 taken 1718 times.
✗ Branch 13 → 19 not taken.
1718 return FunctionManager::match(matchScope, methodName, thisType, args, {}, true, node);
397 }
398
399 /**
400 * Prepare the generation of a call to the copy ctor of a given struct
401 *
402 * @param entry Symbol entry to use as 'this' pointer for the copy ctor call
403 * @param node Current AST node
404 */
405 5 Function *TypeChecker::implicitlyCallStructCopyCtor(const SymbolTableEntry *entry, const ASTNode *node) const {
406
2/4
✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 7 not taken.
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 7 not taken.
5 assert(entry != nullptr && entry->getQualType().is(TY_STRUCT));
407 5 return implicitlyCallStructCopyCtor(entry->getQualType(), node);
408 }
409
410 /**
411 * Prepare the generation of a call to the copy ctor of a given struct
412 *
413 * @param thisType Struct type to call the copy ctor on
414 * @param node Current AST node
415 */
416 258 Function *TypeChecker::implicitlyCallStructCopyCtor(const QualType &thisType, const ASTNode *node) const {
417
2/4
✓ Branch 2 → 3 taken 258 times.
✗ Branch 2 → 19 not taken.
✓ Branch 3 → 4 taken 258 times.
✗ Branch 3 → 19 not taken.
258 const QualType argType = thisType.removeReferenceWrapper().toConstRef(node);
418
1/2
✓ Branch 7 → 8 taken 258 times.
✗ Branch 7 → 20 not taken.
774 const ArgList args = {{argType, false /* we always have an entry here */}};
419
2/4
✓ Branch 11 → 12 taken 258 times.
✗ Branch 11 → 27 not taken.
✓ Branch 12 → 13 taken 258 times.
✗ Branch 12 → 25 not taken.
516 return implicitlyCallStructMethod(thisType, CTOR_FUNCTION_NAME, args, node);
420 258 }
421
422 /**
423 * Prepare the generation of a call to the dtor of a given struct
424 *
425 * @param entry Symbol entry to use as 'this' pointer for the dtor call
426 * @param node StmtLstNode for the current scope
427 */
428 1460 void TypeChecker::implicitlyCallStructDtor(SymbolTableEntry *entry, StmtLstNode *node) const {
429 // Add the dtor to the stmt list node to call it later in codegen
430
4/6
✓ Branch 5 → 6 taken 1460 times.
✗ Branch 5 → 16 not taken.
✓ Branch 6 → 7 taken 1460 times.
✗ Branch 6 → 14 not taken.
✓ Branch 10 → 11 taken 1077 times.
✓ Branch 10 → 13 taken 383 times.
4380 if (Function *dtor = implicitlyCallStructMethod(entry, DTOR_FUNCTION_NAME, {}, node))
431
2/4
✓ Branch 11 → 12 taken 1077 times.
✗ Branch 11 → 23 not taken.
✓ Branch 12 → 13 taken 1077 times.
✗ Branch 12 → 23 not taken.
1077 node->resourcesToCleanup.at(manIdx).dtorFunctionsToCall.emplace_back(entry, dtor);
432 1460 }
433
434 /**
435 * Prepare the generation of a call to the deallocate function for a heap-allocated variable
436 *
437 * @param node Current AST node for error messages
438 */
439 4 void TypeChecker::implicitlyCallDeallocate(const ASTNode *node) const {
440
1/2
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 46 not taken.
4 const SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT);
441
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 assert(memoryRT != nullptr);
442 4 Scope *matchScope = memoryRT->globalScope.get();
443 // Set dealloc function to used
444
1/2
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 46 not taken.
4 const QualType thisType(TY_DYN);
445
3/6
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 28 not taken.
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 28 not taken.
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 28 not taken.
4 QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node);
446
1/2
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 46 not taken.
4 bytePtrRefType.makeHeap();
447
1/2
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 30 not taken.
8 const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}};
448
2/4
✓ Branch 19 → 20 taken 4 times.
✗ Branch 19 → 37 not taken.
✓ Branch 20 → 21 taken 4 times.
✗ Branch 20 → 35 not taken.
12 Function *deallocFct = FunctionManager::match(matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node);
449
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 4 times.
4 assert(deallocFct != nullptr);
450 4 deallocFct->used = true;
451 4 }
452
453 /**
454 * Consider calls to destructors for the given scope
455 *
456 * @param node StmtLstNode for the current scope
457 */
458 21747 void TypeChecker::doScopeCleanup(StmtLstNode *node) const {
459 // Get all variables, that are approved for de-allocation
460
1/2
✓ Branch 2 → 3 taken 21747 times.
✗ Branch 2 → 61 not taken.
21747 std::vector<SymbolTableEntry *> vars = currentScope->getVarsGoingOutOfScope();
461 // Sort by reverse declaration order
462
2/2
✓ Branch 2 → 3 taken 142 times.
✓ Branch 2 → 4 taken 6526 times.
13336 auto comp = [](const SymbolTableEntry *a, const SymbolTableEntry *b) { return a->declNode->codeLoc > b->declNode->codeLoc; };
463
1/2
✓ Branch 3 → 4 taken 21747 times.
✗ Branch 3 → 59 not taken.
21747 std::ranges::sort(vars, comp);
464 // Call the dtor of each variable. We call the dtor in reverse declaration order
465
2/2
✓ Branch 54 → 6 taken 8946 times.
✓ Branch 54 → 55 taken 21747 times.
30693 for (SymbolTableEntry *var : vars) {
466 // Check if we have a heap-allocated pointer
467
10/14
✓ Branch 7 → 8 taken 8946 times.
✗ Branch 7 → 57 not taken.
✓ Branch 8 → 9 taken 8946 times.
✗ Branch 8 → 57 not taken.
✓ Branch 9 → 10 taken 1200 times.
✓ Branch 9 → 14 taken 7746 times.
✓ Branch 10 → 11 taken 1200 times.
✗ Branch 10 → 57 not taken.
✓ Branch 11 → 12 taken 1200 times.
✗ Branch 11 → 57 not taken.
✓ Branch 12 → 13 taken 1167 times.
✓ Branch 12 → 14 taken 33 times.
✓ Branch 15 → 16 taken 1167 times.
✓ Branch 15 → 35 taken 7779 times.
8946 if (var->getQualType().isHeap() && var->getQualType().isOneOf({TY_PTR, TY_STRING, TY_FUNCTION, TY_PROCEDURE})) {
468 // The memory runtime is ignored, because it manually allocates to avoid circular dependencies.
469 // Same goes for the string runtime.
470
8/10
✓ Branch 16 → 17 taken 1167 times.
✗ Branch 16 → 58 not taken.
✓ Branch 19 → 20 taken 1003 times.
✓ Branch 19 → 24 taken 164 times.
✓ Branch 20 → 21 taken 1003 times.
✗ Branch 20 → 58 not taken.
✓ Branch 23 → 24 taken 960 times.
✓ Branch 23 → 25 taken 43 times.
✓ Branch 26 → 27 taken 1124 times.
✓ Branch 26 → 28 taken 43 times.
3337 if (sourceFile->isMemoryRT() || sourceFile->isStringRT())
471 1124 continue;
472 // If the local variable currently does not have the ownership, we must not deallocate its memory
473
3/4
✓ Branch 29 → 30 taken 43 times.
✗ Branch 29 → 58 not taken.
✓ Branch 30 → 31 taken 39 times.
✓ Branch 30 → 32 taken 4 times.
43 if (!var->getLifecycle().isInOwningState())
474 39 continue;
475
476
1/2
✓ Branch 32 → 33 taken 4 times.
✗ Branch 32 → 58 not taken.
4 implicitlyCallDeallocate(node); // Required to request the memory runtime
477
2/4
✓ Branch 33 → 34 taken 4 times.
✗ Branch 33 → 58 not taken.
✓ Branch 34 → 35 taken 4 times.
✗ Branch 34 → 58 not taken.
4 node->resourcesToCleanup.at(manIdx).heapVarsToFree.push_back(var);
478 }
479 // Only generate dtor call for structs and if not omitted
480
8/10
✓ Branch 35 → 36 taken 7783 times.
✗ Branch 35 → 58 not taken.
✓ Branch 36 → 37 taken 7783 times.
✗ Branch 36 → 58 not taken.
✓ Branch 37 → 38 taken 1573 times.
✓ Branch 37 → 39 taken 6210 times.
✓ Branch 38 → 39 taken 113 times.
✓ Branch 38 → 40 taken 1460 times.
✓ Branch 41 → 42 taken 6323 times.
✓ Branch 41 → 43 taken 1460 times.
7783 if (!var->getQualType().is(TY_STRUCT) || var->omitDtorCall)
481 6323 continue;
482 // Variable must be either initialized or a struct field
483
3/8
✓ Branch 44 → 45 taken 1460 times.
✗ Branch 44 → 58 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 48 taken 1460 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 1460 times.
1460 if (!var->getLifecycle().isInitialized() && var->scope->type != ScopeType::STRUCT)
484 continue;
485 // Call dtor
486
1/2
✓ Branch 51 → 52 taken 1460 times.
✗ Branch 51 → 58 not taken.
1460 implicitlyCallStructDtor(var, node);
487 }
488 21747 }
489
490 } // namespace spice::compiler
491