GCC Code Coverage Report


Directory: ../
File: src/symboltablebuilder/Scope.cpp
Date: 2024-11-22 23:10:59
Exec Total Coverage
Lines: 186 198 93.9%
Functions: 22 22 100.0%
Branches: 256 401 63.8%

Line Branch Exec Source
1 // Copyright (c) 2021-2024 ChilliBits. All rights reserved.
2
3 #include "Scope.h"
4
5 #include <SourceFile.h>
6 #include <ast/ASTNodes.h>
7 #include <exception/SemanticError.h>
8 #include <symboltablebuilder/SymbolTableBuilder.h>
9
10 namespace spice::compiler {
11
12 /**
13 * Create a child scope and return it
14 *
15 * @param scopeName Name of the child scope
16 * @param scopeType Type of the child scope
17 * @param declCodeLoc Code location of the scope
18 * @return Child scope (heap allocated)
19 */
20 15340 Scope *Scope::createChildScope(const std::string &scopeName, ScopeType scopeType, const CodeLoc *declCodeLoc) {
21
3/6
✓ Branch 1 taken 15340 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15340 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15340 times.
✗ Branch 8 not taken.
15340 children.insert({scopeName, std::make_shared<Scope>(this, sourceFile, scopeType, declCodeLoc)});
22 15340 return children.at(scopeName).get();
23 }
24
25 /**
26 * Rename the child scope. This is useful for realizing function overloading by storing a function with not
27 * only its name, but also its signature
28 *
29 * @param oldName Old name of the child table
30 * @param newName New name of the child table
31 */
32 7634 void Scope::renameChildScope(const std::string &oldName, const std::string &newName) {
33
4/8
✓ Branch 1 taken 7634 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7634 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7634 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7634 times.
✗ Branch 9 not taken.
7634 assert(children.contains(oldName) && !children.contains(newName));
34
1/2
✓ Branch 1 taken 7634 times.
✗ Branch 2 not taken.
7634 auto nodeHandler = children.extract(oldName);
35
1/2
✓ Branch 2 taken 7634 times.
✗ Branch 3 not taken.
7634 nodeHandler.key() = newName;
36
1/2
✓ Branch 2 taken 7634 times.
✗ Branch 3 not taken.
7634 children.insert(std::move(nodeHandler));
37 7634 }
38
39 /**
40 * Duplicates the child scope by copying it. The duplicated symbols point to the original ones.
41 *
42 * @param oldName Old name of the child block
43 * @param newName New block name
44 */
45 2556 Scope *Scope::copyChildScope(const std::string &oldName, const std::string &newName) {
46
4/8
✓ Branch 1 taken 2556 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2556 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2556 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2556 times.
✗ Branch 9 not taken.
2556 assert(children.contains(oldName) && !children.contains(newName));
47 // Create copy
48
2/4
✓ Branch 1 taken 2556 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2556 times.
✗ Branch 6 not taken.
2556 const std::shared_ptr<Scope> newScope = children.at(oldName)->deepCopyScope();
49 // Save copy under new name
50
2/4
✓ Branch 1 taken 2556 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2556 times.
✗ Branch 5 not taken.
2556 children.insert({newName, newScope});
51 5112 return newScope.get();
52 2556 }
53
54 /**
55 * Deep copy the current scope and all its children
56 *
57 * @return Deep copy of the current scope
58 */
59 8999 std::shared_ptr<Scope> Scope::deepCopyScope() { // NOLINT(misc-no-recursion)
60 8999 const std::shared_ptr<Scope> newScope = std::make_shared<Scope>(*this);
61
2/2
✓ Branch 6 taken 6443 times.
✓ Branch 7 taken 8999 times.
15442 for (const auto &[childName, oldChild] : children) {
62
2/4
✓ Branch 2 taken 6443 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6443 times.
✗ Branch 7 not taken.
6443 newScope->children[childName] = oldChild->deepCopyScope();
63
1/2
✓ Branch 3 taken 6443 times.
✗ Branch 4 not taken.
6443 newScope->children[childName]->parent = newScope.get();
64
2/4
✓ Branch 2 taken 6443 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 6443 times.
✗ Branch 8 not taken.
6443 newScope->children[childName]->symbolTable.scope = newScope->children[childName].get();
65
1/2
✓ Branch 3 taken 6443 times.
✗ Branch 4 not taken.
6443 newScope->children[childName]->symbolTable.parent = &newScope->symbolTable;
66 }
67 8999 newScope->symbolTable.scope = newScope.get();
68 8999 return newScope;
69 }
70
71 /**
72 * Get a child scope of the current scope by its name
73 *
74 * @param scopeName Child scope name
75 * @return Child scope
76 */
77 32470 Scope *Scope::getChildScope(const std::string &scopeName) const {
78
5/6
✓ Branch 1 taken 32469 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 32469 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 32469 times.
✓ Branch 7 taken 1 times.
32470 if (!children.empty() && children.contains(scopeName))
79 32469 return children.at(scopeName).get();
80 1 return nullptr;
81 }
82
83 /**
84 * Retrieve all variables in the current scope, that have reached the end of their lifetime at the end of this scope
85 *
86 * @return Collection of EOL variables
87 */
88 13222 std::vector<SymbolTableEntry *> Scope::getVarsGoingOutOfScope() { // NOLINT(misc-no-recursion)
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13222 times.
13222 assert(parent != nullptr); // Should not be called in root scope
90 13222 std::vector<SymbolTableEntry *> varsGoingOutOfScope;
91
92 // Collect all variables in this scope
93
2/2
✓ Branch 7 taken 22958 times.
✓ Branch 8 taken 13222 times.
36180 for (const auto &[name, entry] : symbolTable.symbols) {
94 // Skip 'this' and result variables
95
8/10
✓ Branch 1 taken 22958 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18180 times.
✓ Branch 4 taken 4778 times.
✓ Branch 6 taken 18180 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4405 times.
✓ Branch 9 taken 13775 times.
✓ Branch 10 taken 9183 times.
✓ Branch 11 taken 13775 times.
22958 if (name == THIS_VARIABLE_NAME || name == RETURN_VARIABLE_NAME)
96 9183 continue;
97 // Skip parameters (ToDo: Remove when copy constructors work for by-value argument passing)
98
2/2
✓ Branch 0 taken 7344 times.
✓ Branch 1 taken 6431 times.
13775 if (entry.isParam)
99 7344 continue;
100 // Found variable, that goes out of scope
101
2/4
✓ Branch 1 taken 6431 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6431 times.
✗ Branch 5 not taken.
6431 varsGoingOutOfScope.push_back(&symbolTable.symbols.at(name));
102 }
103
104 // If this is the scope of a dtor, also return all fields of the struct
105
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 13134 times.
13222 if (isDtorScope) {
106
2/4
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
88 assert(parent != nullptr && parent->type == ScopeType::STRUCT);
107 // Get all fields of the struct
108
2/2
✓ Branch 7 taken 2769 times.
✓ Branch 8 taken 88 times.
2857 for (const auto &[name, entry] : parent->symbolTable.symbols)
109
4/6
✓ Branch 1 taken 2769 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2769 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 247 times.
✓ Branch 7 taken 2522 times.
2769 if (!entry.getQualType().isOneOf({TY_FUNCTION, TY_PROCEDURE}))
110
2/4
✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 247 times.
✗ Branch 5 not taken.
247 varsGoingOutOfScope.push_back(&parent->symbolTable.symbols.at(name));
111 }
112
113 13222 return varsGoingOutOfScope;
114 }
115
116 /**
117 * Insert a new generic type in this scope
118 *
119 * @param typeName Generic type name
120 * @param genericType Generic type itself
121 */
122 2489 void Scope::insertGenericType(const std::string &typeName, const GenericType &genericType) {
123
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2489 times.
2489 assert(!genericTypes.contains(typeName));
124
2/4
✓ Branch 1 taken 2489 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2489 times.
✗ Branch 5 not taken.
2489 genericTypes.insert({typeName, genericType});
125 2489 }
126
127 /**
128 * Search for a generic type by its name. If it was not found, the parent scopes will be searched.
129 * If the generic type does not exist at all, the function will return a nullptr.
130 *
131 * @param typeName Name of the generic type
132 * @return Generic type
133 */
134 22375 GenericType *Scope::lookupGenericType(const std::string &typeName) { // NOLINT(misc-no-recursion)
135
2/2
✓ Branch 1 taken 8383 times.
✓ Branch 2 taken 13992 times.
22375 if (genericTypes.contains(typeName))
136 8383 return &genericTypes.at(typeName);
137
2/2
✓ Branch 0 taken 1721 times.
✓ Branch 1 taken 12271 times.
13992 return parent ? parent->lookupGenericType(typeName) : nullptr;
138 }
139
140 /**
141 * Collect all warnings, produced within this scope
142 *
143 * @param warnings List of warnings
144 * @return Collection of warnings
145 */
146 1269 void Scope::collectWarnings(std::vector<CompilerWarning> &warnings) const { // NOLINT(misc-no-recursion)
147 // Visit own symbols
148 CompilerWarningType warningType;
149 1269 std::string warningMessage;
150
5/8
✓ Branch 1 taken 1269 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1269 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1269 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 2621 times.
✓ Branch 13 taken 1269 times.
3890 for (const auto &entry : symbolTable.symbols | std::views::values) {
151 // Do not produce a warning if the symbol is used or has a special name
152 2621 const std::string &name = entry.name;
153
6/6
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 2455 times.
✓ Branch 3 taken 61 times.
✓ Branch 4 taken 105 times.
✓ Branch 5 taken 2516 times.
✓ Branch 6 taken 105 times.
2621 if (entry.used || name.starts_with(UNUSED_VARIABLE_NAME))
154 2532 continue;
155
156
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
105 const QualType entryType = entry.getQualType();
157
158 // Determine warning type and message by the scope type and the symbol type
159
4/5
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
105 switch (type) {
160 23 case ScopeType::GLOBAL: {
161 // Skip generic function/procedure/struct/interface entries
162
6/10
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 7 times.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 16 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 23 times.
23 if (entryType.isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_STRUCT, TY_INTERFACE}) && !entryType.getTemplateTypes().empty())
163 continue;
164
165
3/4
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 12 times.
23 if (entryType.is(TY_FUNCTION)) {
166
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
167 11 warningType = UNUSED_FUNCTION;
168
3/6
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
11 warningMessage = "'" + fctManifestations->front()->getSignature() + "' is unused";
169
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
12 } else if (entryType.is(TY_PROCEDURE)) {
170
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
171 2 warningType = UNUSED_PROCEDURE;
172
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
2 warningMessage = "'" + fctManifestations->front()->getSignature() + "' is unused";
173
3/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
10 } else if (entryType.is(TY_STRUCT)) {
174 2 warningType = UNUSED_STRUCT;
175
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 warningMessage = "The struct '" + entry.name + "' is unused";
176
3/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 7 times.
8 } else if (entryType.is(TY_INTERFACE)) {
177 1 warningType = UNUSED_INTERFACE;
178
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 warningMessage = "The interface '" + entry.name + "' is unused";
179
3/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 5 times.
7 } else if (entryType.is(TY_ENUM)) {
180 2 continue; // Do not report unused enums. Only unused enum items are reported
181
3/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
5 } else if (entryType.is(TY_IMPORT)) {
182 4 warningType = UNUSED_IMPORT;
183
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 warningMessage = "The import '" + entry.name + "' is unused";
184
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 } else if (entryType.is(TY_ALIAS)) {
185 1 warningType = UNUSED_ALIAS;
186
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 warningMessage = "The type alias '" + entry.name + "' is unused";
187 } else {
188 warningType = UNUSED_VARIABLE;
189 warningMessage = "The variable '" + entry.name + "' is unused";
190 }
191
192 21 break;
193 }
194 43 case ScopeType::STRUCT: // fall-through
195 case ScopeType::INTERFACE: {
196
3/4
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 10 times.
43 if (entryType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
197 // Skip implicit method entries and generic templates
198
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
199
5/6
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 14 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 19 times.
33 if (fctManifestations->empty() || fctManifestations->front()->implicitDefault)
200 14 continue;
201
202 19 warningType = UNUSED_METHOD;
203
3/6
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 19 times.
✗ Branch 9 not taken.
19 warningMessage = "The method '" + fctManifestations->front()->getSignature() + "' is unused";
204 } else {
205 10 warningType = UNUSED_FIELD;
206
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 warningMessage = "The field '" + entry.name + "' is unused";
207 }
208 29 break;
209 }
210 18 case ScopeType::ENUM: {
211 18 warningType = UNUSED_ENUM_ITEM;
212
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 warningMessage = "The enum item '" + entry.name + "' is unused";
213 18 break;
214 }
215 case ScopeType::FOREACH_BODY: {
216 // Skip idx variables
217 if (entry.name == FOREACH_DEFAULT_IDX_VARIABLE_NAME)
218 continue;
219 [[fallthrough]];
220 }
221 default: {
222 21 warningType = UNUSED_VARIABLE;
223
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
21 warningMessage = "The variable '" + entry.name + "' is unused";
224 21 break;
225 }
226 }
227
228 // Add warning
229
2/4
✓ Branch 1 taken 89 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 89 times.
✗ Branch 5 not taken.
89 warnings.emplace_back(entry.getDeclCodeLoc(), warningType, warningMessage);
230 }
231
232 // Visit children
233
5/8
✓ Branch 1 taken 1269 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1269 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1269 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 1064 times.
✓ Branch 13 taken 1269 times.
2333 for (const auto &childScope : children | std::views::values)
234
2/2
✓ Branch 1 taken 1029 times.
✓ Branch 2 taken 35 times.
1064 if (!childScope->isGenericScope)
235
1/2
✓ Branch 2 taken 1029 times.
✗ Branch 3 not taken.
1029 childScope->collectWarnings(warnings);
236 1269 }
237
238 /**
239 * Checks if all variables of this and all child scopes are of an explicit type.
240 * This is executed after type inference to check that all variables could be inferred correctly.
241 */
242 147051 void Scope::ensureSuccessfulTypeInference() const { // NOLINT(misc-no-recursion)
243 // Check symbols in this scope
244
2/2
✓ Branch 7 taken 322945 times.
✓ Branch 8 taken 147050 times.
469995 for (auto &[name, entry] : symbolTable.symbols)
245
4/6
✓ Branch 1 taken 322945 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 322945 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 322944 times.
322945 if (entry.getQualType().is(TY_DYN))
246
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 throw SemanticError(entry.declNode, UNEXPECTED_DYN_TYPE, "For the variable '" + name + "' no type could be inferred");
247
248 // Check child scopes
249
5/8
✓ Branch 1 taken 147050 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 147050 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 147050 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 143752 times.
✓ Branch 13 taken 147049 times.
290801 for (const auto &scope : children | std::views::values)
250
2/2
✓ Branch 2 taken 143751 times.
✓ Branch 3 taken 1 times.
143752 scope->ensureSuccessfulTypeInference();
251 147049 }
252
253 /**
254 * Get the number of fields if this is a struct scope
255 *
256 * @return Number of fields
257 */
258 37621 size_t Scope::getFieldCount() const {
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37621 times.
37621 assert(type == ScopeType::STRUCT);
260 37621 size_t fieldCount = 0;
261
5/8
✓ Branch 1 taken 37621 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37621 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 37621 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 656707 times.
✓ Branch 13 taken 37621 times.
694328 for (const auto &symbol : symbolTable.symbols | std::views::values) {
262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 656707 times.
656707 if (symbol.anonymous)
263 continue;
264
1/2
✓ Branch 1 taken 656707 times.
✗ Branch 2 not taken.
656707 const QualType &symbolType = symbol.getQualType();
265
2/4
✓ Branch 1 taken 656707 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 656707 times.
656707 if (symbolType.is(TY_IMPORT))
266 continue;
267 656707 const ASTNode *declNode = symbol.declNode;
268
8/10
✓ Branch 1 taken 656707 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 154720 times.
✓ Branch 4 taken 501987 times.
✓ Branch 6 taken 154720 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 27558 times.
✓ Branch 9 taken 127162 times.
✓ Branch 10 taken 529545 times.
✓ Branch 11 taken 127162 times.
656707 if (declNode->isFctOrProcDef() || declNode->isStructDef())
269 529545 continue;
270 127162 fieldCount++;
271 }
272 37621 return fieldCount;
273 }
274
275 /**
276 * Get all virtual methods in this scope, sorted by declaration code location
277 *
278 * @return List of virtual method pointers
279 */
280 498 std::vector<Function *> Scope::getVirtualMethods() {
281
3/4
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 216 times.
498 assert(type == ScopeType::STRUCT || type == ScopeType::INTERFACE);
282
283 // Collect all virtual methods
284 498 std::vector<Function *> methods;
285
2/2
✓ Branch 7 taken 3254 times.
✓ Branch 8 taken 498 times.
3752 for (auto &[fctId, manifestationList] : functions) {
286
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3254 times.
3254 assert(!manifestationList.empty());
287
2/2
✓ Branch 7 taken 4774 times.
✓ Branch 8 taken 3254 times.
8028 for (auto &[mangledName, function] : manifestationList)
288
2/2
✓ Branch 0 taken 1104 times.
✓ Branch 1 taken 3670 times.
4774 if (function.isVirtualMethod())
289
3/6
✓ Branch 1 taken 1104 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1104 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1104 times.
✗ Branch 8 not taken.
1104 methods.push_back(&functions.at(fctId).at(mangledName));
290 }
291
292 // Sort the list
293
2/4
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1360 times.
3218 std::ranges::sort(methods, [](const Function *a, const Function *b) { return a->getDeclCodeLoc() < b->getDeclCodeLoc(); });
294
295 498 return methods;
296 }
297
298 /**
299 * Retrieve all struct manifestations in this scope in the order of their declaration
300 *
301 * @return All struct manifestations in declaration order
302 */
303 854 std::vector<const Struct *> Scope::getAllStructManifestationsInDeclarationOrder() const {
304 // Retrieve all struct manifestations in this scope
305 854 std::vector<const Struct *> manifestations;
306
1/2
✓ Branch 2 taken 854 times.
✗ Branch 3 not taken.
854 manifestations.reserve(structs.size()); // Reserve at least the size of individual generic structs
307
5/8
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 854 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 854 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 538 times.
✓ Branch 13 taken 854 times.
1392 for (const auto &structManifestations : structs | std::views::values)
308
5/8
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 538 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 538 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 539 times.
✓ Branch 12 taken 538 times.
1077 for (const auto &manifestation : structManifestations | std::views::values)
309
1/2
✓ Branch 1 taken 539 times.
✗ Branch 2 not taken.
539 manifestations.push_back(&manifestation);
310
311 // Sort manifestations by declaration code location
312
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 208 times.
420 auto sortLambda = [](const Struct *lhs, const Struct *rhs) { return lhs->getDeclCodeLoc() < rhs->getDeclCodeLoc(); };
313
1/2
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
854 std::ranges::sort(manifestations, sortLambda);
314 1708 return manifestations;
315 }
316
317 /**
318 * Check if this struct has any reference fields
319 *
320 * @return Has reference fields or not
321 */
322 183 bool Scope::hasRefFields() {
323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
183 assert(type == ScopeType::STRUCT);
324
2/2
✓ Branch 1 taken 452 times.
✓ Branch 2 taken 176 times.
628 for (size_t i = 0; i < getFieldCount(); i++)
325
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 452 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 445 times.
904 if (lookupField(i)->getQualType().isRef())
326 7 return true;
327 176 return false;
328 }
329
330 /**
331 * Get the current number of nested loops
332 *
333 * @return Number of loops
334 */
335 2372 unsigned int Scope::getLoopNestingDepth() const { // NOLINT(misc-no-recursion)
336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2372 times.
2372 assert(parent != nullptr);
337
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 1938 times.
2372 if (parent->parent == nullptr)
338 434 return 0;
339 1938 unsigned int loopCount = parent->getLoopNestingDepth();
340
6/6
✓ Branch 0 taken 1839 times.
✓ Branch 1 taken 99 times.
✓ Branch 2 taken 1189 times.
✓ Branch 3 taken 650 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 1165 times.
1938 if (type == ScopeType::WHILE_BODY || type == ScopeType::FOR_BODY || type == ScopeType::FOREACH_BODY)
341 773 loopCount++;
342 1938 return loopCount;
343 }
344
345 /**
346 * Check if this scope is one of the child scopes of a switch statement
347 *
348 * @return Child scope of switch statement or not
349 */
350 7 bool Scope::isInCaseBranch() const { // NOLINT(misc-no-recursion)
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(parent != nullptr);
352
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (parent->parent == nullptr)
353 2 return false;
354
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (type == ScopeType::CASE_BODY)
355 4 return true;
356 1 return parent->isInCaseBranch();
357 }
358
359 /**
360 * Check if this scope is within an async scope
361 *
362 * @return Within async scope or not
363 */
364 67 bool Scope::isInAsyncScope() const { // NOLINT(misc-no-recursion)
365
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 59 times.
67 if (isAsyncScope)
366 8 return true;
367
3/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
59 return parent != nullptr && parent->isInAsyncScope();
368 }
369
370 /**
371 * Check if unsafe operations are allowed in this scope
372 *
373 * @return Allowed or not
374 */
375 3772 bool Scope::doesAllowUnsafeOperations() const { // NOLINT(misc-no-recursion)
376
2/2
✓ Branch 0 taken 2299 times.
✓ Branch 1 taken 1473 times.
3772 if (type == ScopeType::UNSAFE_BODY)
377 2299 return true;
378
4/4
✓ Branch 0 taken 1472 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1471 times.
✓ Branch 4 taken 1 times.
1473 return parent != nullptr && parent->doesAllowUnsafeOperations();
379 }
380
381 /**
382 * Checks if this scope is imported
383 *
384 * @param askingScope Scope, which asks whether the current one is imported from its point of view or not
385 *
386 * @return Imported / not imported
387 */
388 73014 bool Scope::isImportedBy(const Scope *askingScope) const { return askingScope->sourceFile->imports(sourceFile); }
389
390 /**
391 * Get JSON representation of the symbol table
392 *
393 * @return Symbol table as JSON object
394 */
395 147115 nlohmann::json Scope::getSymbolTableJSON() const { // NOLINT(misc-no-recursion)
396
1/2
✓ Branch 1 taken 147115 times.
✗ Branch 2 not taken.
147115 nlohmann::json result = symbolTable.toJSON();
397
398 // Collect all children
399 147115 std::vector<nlohmann::json> jsonChildren;
400
1/2
✓ Branch 2 taken 147115 times.
✗ Branch 3 not taken.
147115 jsonChildren.reserve(children.size());
401
2/2
✓ Branch 7 taken 143808 times.
✓ Branch 8 taken 147115 times.
290923 for (const auto &[name, childScope] : children) {
402
1/2
✓ Branch 2 taken 143808 times.
✗ Branch 3 not taken.
143808 nlohmann::json c = childScope->getSymbolTableJSON();
403
2/4
✓ Branch 1 taken 143808 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 143808 times.
✗ Branch 5 not taken.
143808 c["name"] = name; // Inject symbol table name into JSON object
404
1/2
✓ Branch 1 taken 143808 times.
✗ Branch 2 not taken.
143808 jsonChildren.emplace_back(c);
405 143808 }
406
2/4
✓ Branch 1 taken 147115 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 147115 times.
✗ Branch 5 not taken.
147115 result["children"] = jsonChildren;
407
408 294230 return result;
409 147115 }
410
411 } // namespace spice::compiler
412