GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 99.0% 189 / 4 / 195
Functions: 100.0% 22 / 0 / 22
Branches: 65.5% 254 / 0 / 388

src/symboltablebuilder/Scope.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 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 46392 Scope::Scope(Scope *parent, SourceFile *sourceFile, ScopeType scopeType, const CodeLoc *codeLoc)
13
2/2
✓ Branch 3 → 4 taken 44540 times.
✓ Branch 3 → 5 taken 1852 times.
46392 : parent(parent), sourceFile(sourceFile), codeLoc(codeLoc), type(scopeType) {}
14
15 /**
16 * Create a child scope and return it
17 *
18 * @param scopeName Name of the child scope
19 * @param scopeType Type of the child scope
20 * @param declCodeLoc Code location of the scope
21 * @return Child scope (heap allocated)
22 */
23 44540 Scope *Scope::createChildScope(const std::string &scopeName, ScopeType scopeType, const CodeLoc *declCodeLoc) {
24
2/4
✓ Branch 2 → 3 taken 44540 times.
✗ Branch 2 → 15 not taken.
✓ Branch 3 → 4 taken 44540 times.
✗ Branch 3 → 13 not taken.
44540 const auto &[scope, inserted] = children.emplace(scopeName, std::make_shared<Scope>(this, sourceFile, scopeType, declCodeLoc));
25
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 44540 times.
44540 assert(inserted);
26 89080 return scope->second.get();
27 }
28
29 /**
30 * Rename the child scope. This is useful for realizing function overloading by storing a function with not
31 * only its name, but also its signature
32 *
33 * @param oldName Old name of the child table
34 * @param newName New name of the child table
35 */
36 23358 void Scope::renameChildScope(const std::string &oldName, const std::string &newName) {
37
4/8
✓ Branch 2 → 3 taken 23358 times.
✗ Branch 2 → 20 not taken.
✓ Branch 3 → 4 taken 23358 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 23358 times.
✗ Branch 4 → 20 not taken.
✓ Branch 5 → 6 taken 23358 times.
✗ Branch 5 → 7 not taken.
23358 assert(children.contains(oldName) && !children.contains(newName));
38
1/2
✓ Branch 8 → 9 taken 23358 times.
✗ Branch 8 → 20 not taken.
23358 auto nodeHandler = children.extract(oldName);
39
1/2
✓ Branch 10 → 11 taken 23358 times.
✗ Branch 10 → 18 not taken.
23358 nodeHandler.key() = newName;
40
1/2
✓ Branch 13 → 14 taken 23358 times.
✗ Branch 13 → 17 not taken.
46716 children.insert(std::move(nodeHandler));
41 23358 }
42
43 /**
44 * Duplicates the child scope by copying it. The duplicated symbols point to the original ones.
45 *
46 * @param oldName Old name of the child block
47 * @param newName New block name
48 */
49 9958 Scope *Scope::copyChildScope(const std::string &oldName, const std::string &newName) {
50
4/8
✓ Branch 2 → 3 taken 9958 times.
✗ Branch 2 → 18 not taken.
✓ Branch 3 → 4 taken 9958 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 9958 times.
✗ Branch 4 → 18 not taken.
✓ Branch 5 → 6 taken 9958 times.
✗ Branch 5 → 7 not taken.
9958 assert(children.contains(oldName) && !children.contains(newName));
51 // Create copy
52
2/4
✓ Branch 8 → 9 taken 9958 times.
✗ Branch 8 → 18 not taken.
✓ Branch 10 → 11 taken 9958 times.
✗ Branch 10 → 18 not taken.
9958 const std::shared_ptr<Scope> newScope = children.at(oldName)->deepCopyScope();
53 // Save copy under new name
54
1/2
✓ Branch 11 → 12 taken 9958 times.
✗ Branch 11 → 16 not taken.
9958 children.emplace(newName, newScope);
55 19916 return newScope.get();
56 9958 }
57
58 /**
59 * Deep copy the current scope and all its children
60 *
61 * @return Deep copy of the current scope
62 */
63 34569 std::shared_ptr<Scope> Scope::deepCopyScope() { // NOLINT(misc-no-recursion)
64 34569 const auto newScope = std::make_shared<Scope>(*this);
65
2/2
✓ Branch 30 → 5 taken 24611 times.
✓ Branch 30 → 31 taken 34569 times.
59180 for (const auto &[childName, oldChild] : children) {
66
2/4
✓ Branch 9 → 10 taken 24611 times.
✗ Branch 9 → 37 not taken.
✓ Branch 11 → 12 taken 24611 times.
✗ Branch 11 → 35 not taken.
24611 newScope->children[childName] = oldChild->deepCopyScope();
67
1/2
✓ Branch 16 → 17 taken 24611 times.
✗ Branch 16 → 38 not taken.
24611 newScope->children[childName]->parent = newScope.get();
68
2/4
✓ Branch 19 → 20 taken 24611 times.
✗ Branch 19 → 38 not taken.
✓ Branch 22 → 23 taken 24611 times.
✗ Branch 22 → 38 not taken.
24611 newScope->children[childName]->symbolTable.scope = newScope->children[childName].get();
69
1/2
✓ Branch 26 → 27 taken 24611 times.
✗ Branch 26 → 38 not taken.
24611 newScope->children[childName]->symbolTable.parent = &newScope->symbolTable;
70 }
71 34569 newScope->symbolTable.scope = newScope.get();
72 34569 return newScope;
73 } // LCOV_EXCL_LINE - false positive
74
75 /**
76 * Get a child scope of the current scope by its name
77 *
78 * @param scopeName Child scope name
79 * @return Child scope
80 */
81 96074 Scope *Scope::getChildScope(const std::string &scopeName) const {
82
1/2
✓ Branch 2 → 3 taken 96074 times.
✗ Branch 2 → 12 not taken.
96074 const auto it = children.find(scopeName);
83
2/2
✓ Branch 5 → 6 taken 96073 times.
✓ Branch 5 → 8 taken 1 time.
192148 return it != children.end() ? it->second.get() : nullptr;
84 }
85
86 /**
87 * Retrieve all variables in the current scope, that have reached the end of their lifetime at the end of this scope
88 *
89 * @return Collection of EOL variables
90 */
91 40537 std::vector<SymbolTableEntry *> Scope::getVarsGoingOutOfScope() { // NOLINT(misc-no-recursion)
92
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 40537 times.
40537 assert(!isRootScope()); // Should not be called in root scope
93 40537 std::vector<SymbolTableEntry *> varsGoingOutOfScope;
94
95 // Collect all variables in this scope
96
2/2
✓ Branch 26 → 8 taken 70992 times.
✓ Branch 26 → 27 taken 40537 times.
111529 for (const auto &[name, entry] : symbolTable.symbols) {
97 // Skip 'this' and result variables
98
8/10
✓ Branch 11 → 12 taken 70992 times.
✗ Branch 11 → 52 not taken.
✓ Branch 12 → 13 taken 57667 times.
✓ Branch 12 → 15 taken 13325 times.
✓ Branch 13 → 14 taken 57667 times.
✗ Branch 13 → 52 not taken.
✓ Branch 14 → 15 taken 15018 times.
✓ Branch 14 → 16 taken 42649 times.
✓ Branch 17 → 18 taken 28343 times.
✓ Branch 17 → 19 taken 42649 times.
70992 if (name == THIS_VARIABLE_NAME || name == RETURN_VARIABLE_NAME)
99 28343 continue;
100 // Skip parameters (ToDo: Remove when copy constructors work for by-value argument passing)
101
2/2
✓ Branch 19 → 20 taken 25549 times.
✓ Branch 19 → 21 taken 17100 times.
42649 if (entry.isParam)
102 25549 continue;
103 // Found variable, that goes out of scope
104
2/4
✓ Branch 21 → 22 taken 17100 times.
✗ Branch 21 → 51 not taken.
✓ Branch 22 → 23 taken 17100 times.
✗ Branch 22 → 51 not taken.
17100 varsGoingOutOfScope.push_back(&symbolTable.symbols.at(name));
105 }
106
107 // If this is the scope of a dtor, also return all fields of the struct
108
2/2
✓ Branch 27 → 28 taken 189 times.
✓ Branch 27 → 49 taken 40348 times.
40537 if (isDtorScope) {
109
2/4
✓ Branch 30 → 31 taken 189 times.
✗ Branch 30 → 33 not taken.
✓ Branch 31 → 32 taken 189 times.
✗ Branch 31 → 33 not taken.
189 assert(!isRootScope() && parent->type == ScopeType::STRUCT);
110 // Get all fields of the struct
111
2/2
✓ Branch 47 → 36 taken 5899 times.
✓ Branch 47 → 48 taken 189 times.
6088 for (const auto &[name, entry] : parent->symbolTable.symbols)
112
4/6
✓ Branch 39 → 40 taken 5899 times.
✗ Branch 39 → 55 not taken.
✓ Branch 40 → 41 taken 5899 times.
✗ Branch 40 → 53 not taken.
✓ Branch 41 → 42 taken 490 times.
✓ Branch 41 → 45 taken 5409 times.
5899 if (!entry.getQualType().isOneOf({TY_FUNCTION, TY_PROCEDURE}))
113
2/4
✓ Branch 42 → 43 taken 490 times.
✗ Branch 42 → 54 not taken.
✓ Branch 43 → 44 taken 490 times.
✗ Branch 43 → 54 not taken.
490 varsGoingOutOfScope.push_back(&parent->symbolTable.symbols.at(name));
114 }
115
116 40537 return varsGoingOutOfScope;
117 } // LCOV_EXCL_LINE - false positive
118
119 /**
120 * Insert a new generic type in this scope
121 *
122 * @param typeName Generic type name
123 * @param genericType Generic type itself
124 */
125 10365 void Scope::insertGenericType(const std::string &typeName, const GenericType &genericType) {
126
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 10365 times.
10365 assert(!genericTypes.contains(typeName));
127 10365 genericTypes.emplace(typeName, genericType);
128 10365 }
129
130 /**
131 * Search for a generic type by its name in this scope.
132 * If the generic type is not found, a nullptr is returned.
133 *
134 * @param typeName Name of the generic type
135 * @return Generic type
136 */
137 73951 GenericType *Scope::lookupGenericTypeStrict(const std::string &typeName) {
138
1/2
✓ Branch 2 → 3 taken 73951 times.
✗ Branch 2 → 12 not taken.
73951 const auto it = genericTypes.find(typeName);
139
2/2
✓ Branch 5 → 6 taken 29466 times.
✓ Branch 5 → 8 taken 44485 times.
147902 return it != genericTypes.end() ? &it->second : nullptr;
140 }
141
142 /**
143 * Collect all warnings, produced within this scope
144 *
145 * @param warnings List of warnings
146 * @return Collection of warnings
147 */
148 12574 void Scope::collectWarnings(std::vector<CompilerWarning> &warnings) const { // NOLINT(misc-no-recursion)
149 // Visit own symbols
150
5/8
✓ Branch 2 → 3 taken 12574 times.
✗ Branch 2 → 215 not taken.
✓ Branch 3 → 4 taken 12574 times.
✗ Branch 3 → 215 not taken.
✓ Branch 4 → 5 taken 12574 times.
✗ Branch 4 → 215 not taken.
✓ Branch 143 → 6 taken 34761 times.
✓ Branch 143 → 144 taken 12574 times.
47335 for (const SymbolTableEntry &entry : symbolTable.symbols | std::views::values) {
151 // Do not produce a warning if the symbol is used or has a special name
152 34761 const std::string &name = entry.name;
153
6/6
✓ Branch 7 → 8 taken 4277 times.
✓ Branch 7 → 10 taken 30484 times.
✓ Branch 9 → 10 taken 118 times.
✓ Branch 9 → 11 taken 4159 times.
✓ Branch 12 → 13 taken 30602 times.
✓ Branch 12 → 14 taken 4159 times.
34761 if (entry.used || name.starts_with(UNUSED_VARIABLE_NAME))
154 31275 continue;
155
156
1/2
✓ Branch 14 → 15 taken 4159 times.
✗ Branch 14 → 214 not taken.
4159 const QualType entryType = entry.getQualType();
157
158 // Determine warning type and message by the scope type and the symbol type
159 4159 CompilerWarningType warningType = UNUSED_VARIABLE;
160 4159 std::string warningMessage;
161
4/4
✓ Branch 16 → 17 taken 1042 times.
✓ Branch 16 → 92 taken 1758 times.
✓ Branch 16 → 121 taken 1086 times.
✓ Branch 16 → 127 taken 273 times.
4159 switch (type) {
162 1042 case ScopeType::GLOBAL: {
163 // Skip generic function/procedure/struct/interface entries
164
6/10
✓ Branch 17 → 18 taken 1042 times.
✗ Branch 17 → 157 not taken.
✓ Branch 18 → 19 taken 42 times.
✓ Branch 18 → 23 taken 1000 times.
✓ Branch 19 → 20 taken 42 times.
✗ Branch 19 → 157 not taken.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 42 times.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 1042 times.
1042 if (entryType.isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_STRUCT, TY_INTERFACE}) && !entryType.getTemplateTypes().empty())
165 continue;
166
167
3/4
✓ Branch 26 → 27 taken 1042 times.
✗ Branch 26 → 212 not taken.
✓ Branch 27 → 28 taken 17 times.
✓ Branch 27 → 38 taken 1025 times.
1042 if (entryType.is(TY_FUNCTION)) {
168
1/2
✓ Branch 28 → 29 taken 17 times.
✗ Branch 28 → 212 not taken.
17 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
169 17 warningType = UNUSED_FUNCTION;
170
3/6
✓ Branch 30 → 31 taken 17 times.
✗ Branch 30 → 162 not taken.
✓ Branch 31 → 32 taken 17 times.
✗ Branch 31 → 160 not taken.
✓ Branch 32 → 33 taken 17 times.
✗ Branch 32 → 158 not taken.
17 warningMessage = "'" + fctManifestations->front()->getSignature() + "' is unused";
171
3/4
✓ Branch 38 → 39 taken 1025 times.
✗ Branch 38 → 212 not taken.
✓ Branch 39 → 40 taken 23 times.
✓ Branch 39 → 50 taken 1002 times.
1025 } else if (entryType.is(TY_PROCEDURE)) {
172
1/2
✓ Branch 40 → 41 taken 23 times.
✗ Branch 40 → 212 not taken.
23 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
173 23 warningType = UNUSED_PROCEDURE;
174
3/6
✓ Branch 42 → 43 taken 23 times.
✗ Branch 42 → 169 not taken.
✓ Branch 43 → 44 taken 23 times.
✗ Branch 43 → 167 not taken.
✓ Branch 44 → 45 taken 23 times.
✗ Branch 44 → 165 not taken.
23 warningMessage = "'" + fctManifestations->front()->getSignature() + "' is unused";
175
3/4
✓ Branch 50 → 51 taken 1002 times.
✗ Branch 50 → 212 not taken.
✓ Branch 51 → 52 taken 1 time.
✓ Branch 51 → 58 taken 1001 times.
1002 } else if (entryType.is(TY_STRUCT)) {
176 1 warningType = UNUSED_STRUCT;
177
2/4
✓ Branch 52 → 53 taken 1 time.
✗ Branch 52 → 174 not taken.
✓ Branch 53 → 54 taken 1 time.
✗ Branch 53 → 172 not taken.
1 warningMessage = "The struct '" + entry.name + "' is unused";
178
3/4
✓ Branch 58 → 59 taken 1001 times.
✗ Branch 58 → 212 not taken.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 66 taken 1000 times.
1001 } else if (entryType.is(TY_INTERFACE)) {
179 1 warningType = UNUSED_INTERFACE;
180
2/4
✓ Branch 60 → 61 taken 1 time.
✗ Branch 60 → 178 not taken.
✓ Branch 61 → 62 taken 1 time.
✗ Branch 61 → 176 not taken.
1 warningMessage = "The interface '" + entry.name + "' is unused";
181
3/4
✓ Branch 66 → 67 taken 1000 times.
✗ Branch 66 → 212 not taken.
✓ Branch 67 → 68 taken 3 times.
✓ Branch 67 → 69 taken 997 times.
1000 } else if (entryType.is(TY_ENUM)) {
182 3 continue; // Do not report unused enums. Only unused enum items are reported
183
3/4
✓ Branch 69 → 70 taken 997 times.
✗ Branch 69 → 212 not taken.
✓ Branch 70 → 71 taken 20 times.
✓ Branch 70 → 77 taken 977 times.
997 } else if (entryType.is(TY_IMPORT)) {
184 20 warningType = UNUSED_IMPORT;
185
2/4
✓ Branch 71 → 72 taken 20 times.
✗ Branch 71 → 182 not taken.
✓ Branch 72 → 73 taken 20 times.
✗ Branch 72 → 180 not taken.
20 warningMessage = "The import '" + entry.name + "' is unused";
186
3/4
✓ Branch 77 → 78 taken 977 times.
✗ Branch 77 → 212 not taken.
✓ Branch 78 → 79 taken 10 times.
✓ Branch 78 → 85 taken 967 times.
977 } else if (entryType.is(TY_ALIAS)) {
187 10 warningType = UNUSED_ALIAS;
188
2/4
✓ Branch 79 → 80 taken 10 times.
✗ Branch 79 → 186 not taken.
✓ Branch 80 → 81 taken 10 times.
✗ Branch 80 → 184 not taken.
10 warningMessage = "The type alias '" + entry.name + "' is unused";
189 } else {
190 967 warningType = UNUSED_VARIABLE;
191
2/4
✓ Branch 85 → 86 taken 967 times.
✗ Branch 85 → 190 not taken.
✓ Branch 86 → 87 taken 967 times.
✗ Branch 86 → 188 not taken.
967 warningMessage = "The variable '" + entry.name + "' is unused";
192 }
193
194 1039 break;
195 }
196 1758 case ScopeType::STRUCT: // fall-through
197 case ScopeType::INTERFACE: {
198
3/4
✓ Branch 92 → 93 taken 1758 times.
✗ Branch 92 → 212 not taken.
✓ Branch 93 → 94 taken 372 times.
✓ Branch 93 → 100 taken 1386 times.
1758 if (entry.isField()) {
199 372 warningType = UNUSED_FIELD;
200
2/4
✓ Branch 94 → 95 taken 372 times.
✗ Branch 94 → 194 not taken.
✓ Branch 95 → 96 taken 372 times.
✗ Branch 95 → 192 not taken.
372 warningMessage = "The field '" + entry.name + "' is unused";
201
2/4
✓ Branch 100 → 101 taken 1386 times.
✗ Branch 100 → 196 not taken.
✓ Branch 101 → 102 taken 1386 times.
✗ Branch 101 → 120 not taken.
1386 } else if (entryType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
202 // Skip implicit method entries and generic templates
203
1/2
✓ Branch 102 → 103 taken 1386 times.
✗ Branch 102 → 212 not taken.
1386 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
204
5/6
✓ Branch 104 → 105 taken 716 times.
✓ Branch 104 → 107 taken 670 times.
✗ Branch 106 → 107 not taken.
✓ Branch 106 → 108 taken 716 times.
✓ Branch 109 → 110 taken 670 times.
✓ Branch 109 → 111 taken 716 times.
1386 if (fctManifestations->empty() || fctManifestations->front()->implicitDefault)
205 670 continue;
206
207 716 warningType = UNUSED_METHOD;
208
3/6
✓ Branch 112 → 113 taken 716 times.
✗ Branch 112 → 201 not taken.
✓ Branch 113 → 114 taken 716 times.
✗ Branch 113 → 199 not taken.
✓ Branch 114 → 115 taken 716 times.
✗ Branch 114 → 197 not taken.
716 warningMessage = "The method '" + fctManifestations->front()->getSignature() + "' is unused";
209 }
210 1088 break;
211 }
212 1086 case ScopeType::ENUM: {
213 1086 warningType = UNUSED_ENUM_ITEM;
214
2/4
✓ Branch 121 → 122 taken 1086 times.
✗ Branch 121 → 206 not taken.
✓ Branch 122 → 123 taken 1086 times.
✗ Branch 122 → 204 not taken.
1086 warningMessage = "The enum item '" + entry.name + "' is unused";
215 1086 break;
216 }
217 273 default: {
218 273 warningType = UNUSED_VARIABLE;
219
2/4
✓ Branch 127 → 128 taken 273 times.
✗ Branch 127 → 210 not taken.
✓ Branch 128 → 129 taken 273 times.
✗ Branch 128 → 208 not taken.
273 warningMessage = "The variable '" + entry.name + "' is unused";
220 273 break;
221 }
222 }
223
224 // Add warning
225
2/4
✓ Branch 133 → 134 taken 3486 times.
✗ Branch 133 → 212 not taken.
✓ Branch 134 → 135 taken 3486 times.
✗ Branch 134 → 212 not taken.
3486 warnings.emplace_back(entry.getDeclCodeLoc(), warningType, warningMessage);
226
2/2
✓ Branch 137 → 138 taken 3486 times.
✓ Branch 137 → 140 taken 673 times.
4159 }
227
228 // Visit children
229
5/8
✓ Branch 144 → 145 taken 12574 times.
✗ Branch 144 → 216 not taken.
✓ Branch 145 → 146 taken 12574 times.
✗ Branch 145 → 216 not taken.
✓ Branch 146 → 147 taken 12574 times.
✗ Branch 146 → 216 not taken.
✓ Branch 155 → 148 taken 11784 times.
✓ Branch 155 → 156 taken 12574 times.
24358 for (const auto &childScope : children | std::views::values)
230
2/2
✓ Branch 150 → 151 taken 11653 times.
✓ Branch 150 → 153 taken 131 times.
11784 if (!childScope->isGenericScope)
231
1/2
✓ Branch 152 → 153 taken 11653 times.
✗ Branch 152 → 216 not taken.
11653 childScope->collectWarnings(warnings);
232 12574 }
233
234 /**
235 * Checks if all variables of this and all child scopes are of an explicit type.
236 * This is executed after type inference to check that all variables could be inferred correctly.
237 */
238 209081 void Scope::ensureSuccessfulTypeInference() const { // NOLINT(misc-no-recursion)
239 // Check symbols in this scope
240
2/2
✓ Branch 19 → 4 taken 472027 times.
✓ Branch 19 → 20 taken 209080 times.
681107 for (auto &[name, entry] : symbolTable.symbols)
241
4/6
✓ Branch 7 → 8 taken 472027 times.
✗ Branch 7 → 40 not taken.
✓ Branch 8 → 9 taken 472027 times.
✗ Branch 8 → 40 not taken.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 17 taken 472026 times.
472027 if (entry.getQualType().is(TY_DYN))
242
3/6
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 36 not taken.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 34 not taken.
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 31 not taken.
1 throw SemanticError(entry.declNode, UNEXPECTED_DYN_TYPE, "For the variable '" + name + "' no type could be inferred");
243
244 // Check child scopes
245
5/8
✓ Branch 20 → 21 taken 209080 times.
✗ Branch 20 → 41 not taken.
✓ Branch 21 → 22 taken 209080 times.
✗ Branch 21 → 41 not taken.
✓ Branch 22 → 23 taken 209080 times.
✗ Branch 22 → 41 not taken.
✓ Branch 29 → 24 taken 204792 times.
✓ Branch 29 → 30 taken 209079 times.
413871 for (const auto &scope : children | std::views::values)
246
2/2
✓ Branch 26 → 27 taken 204791 times.
✓ Branch 26 → 41 taken 1 time.
204792 scope->ensureSuccessfulTypeInference();
247 209079 }
248
249 /**
250 * Get the number of fields if this is a struct scope
251 *
252 * @return Number of fields
253 */
254 128175 size_t Scope::getFieldCount() const {
255
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 128175 times.
128175 assert(type == ScopeType::STRUCT);
256 128175 size_t fieldCount = 0;
257
5/8
✓ Branch 4 → 5 taken 128175 times.
✗ Branch 4 → 29 not taken.
✓ Branch 5 → 6 taken 128175 times.
✗ Branch 5 → 29 not taken.
✓ Branch 6 → 7 taken 128175 times.
✗ Branch 6 → 29 not taken.
✓ Branch 26 → 8 taken 2363046 times.
✓ Branch 26 → 27 taken 128175 times.
2491221 for (const auto &symbol : symbolTable.symbols | std::views::values) {
258
2/2
✓ Branch 9 → 10 taken 1084 times.
✓ Branch 9 → 11 taken 2361962 times.
2363046 if (symbol.anonymous)
259 1084 continue;
260
1/2
✓ Branch 11 → 12 taken 2361962 times.
✗ Branch 11 → 29 not taken.
2361962 const QualType &symbolType = symbol.getQualType();
261
2/4
✓ Branch 12 → 13 taken 2361962 times.
✗ Branch 12 → 29 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 2361962 times.
2361962 if (symbolType.is(TY_IMPORT))
262 continue;
263 2361962 const ASTNode *declNode = symbol.declNode;
264
8/10
✓ Branch 15 → 16 taken 2361962 times.
✗ Branch 15 → 29 not taken.
✓ Branch 16 → 17 taken 529385 times.
✓ Branch 16 → 19 taken 1832577 times.
✓ Branch 17 → 18 taken 529385 times.
✗ Branch 17 → 29 not taken.
✓ Branch 18 → 19 taken 103222 times.
✓ Branch 18 → 20 taken 426163 times.
✓ Branch 21 → 22 taken 1935799 times.
✓ Branch 21 → 23 taken 426163 times.
2361962 if (declNode->isFctOrProcDef() || declNode->isStructDef())
265 1935799 continue;
266 426163 fieldCount++;
267 }
268 128175 return fieldCount;
269 }
270
271 /**
272 * Get all virtual methods in this scope, sorted by declaration code location
273 *
274 * @return List of virtual method pointers
275 */
276 2116 std::vector<Function *> Scope::getVirtualMethods() {
277
3/4
✓ Branch 2 → 3 taken 1022 times.
✓ Branch 2 → 5 taken 1094 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1022 times.
2116 assert(type == ScopeType::STRUCT || type == ScopeType::INTERFACE);
278
279 // Collect all virtual methods
280 2116 std::vector<Function *> methods;
281
2/2
✓ Branch 37 → 7 taken 15196 times.
✓ Branch 37 → 38 taken 2116 times.
17312 for (auto &[fctId, manifestationList] : functions) {
282
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 15196 times.
15196 assert(!manifestationList.empty());
283
2/2
✓ Branch 34 → 15 taken 21824 times.
✓ Branch 34 → 35 taken 15196 times.
37020 for (auto &[mangledName, function] : manifestationList)
284
2/2
✓ Branch 27 → 28 taken 5154 times.
✓ Branch 27 → 32 taken 16670 times.
21824 if (function.isVirtualMethod())
285
3/6
✓ Branch 28 → 29 taken 5154 times.
✗ Branch 28 → 41 not taken.
✓ Branch 29 → 30 taken 5154 times.
✗ Branch 29 → 41 not taken.
✓ Branch 30 → 31 taken 5154 times.
✗ Branch 30 → 41 not taken.
5154 methods.push_back(&functions.at(fctId).at(mangledName));
286 }
287
288 // Sort the list
289
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7328 times.
14656 const auto pred = [](const Function *a, const Function *b) { return a->getDeclCodeLoc() < b->getDeclCodeLoc(); };
290
1/2
✓ Branch 38 → 39 taken 2116 times.
✗ Branch 38 → 44 not taken.
2116 std::ranges::sort(methods, pred);
291
292 2116 return methods;
293 } // LCOV_EXCL_LINE - false positive
294
295 /**
296 * Retrieve all struct manifestations in this scope in the order of their declaration
297 *
298 * @return All struct manifestations in declaration order
299 */
300 1811 std::vector<const Struct *> Scope::getAllStructManifestationsInDeclarationOrder() const {
301 // Retrieve all struct manifestations in this scope
302 1811 std::vector<const Struct *> manifestations;
303
1/2
✓ Branch 3 → 4 taken 1811 times.
✗ Branch 3 → 27 not taken.
1811 manifestations.reserve(structs.size()); // Reserve at least the size of individual generic structs
304
5/8
✓ Branch 4 → 5 taken 1811 times.
✗ Branch 4 → 26 not taken.
✓ Branch 5 → 6 taken 1811 times.
✗ Branch 5 → 26 not taken.
✓ Branch 6 → 7 taken 1811 times.
✗ Branch 6 → 26 not taken.
✓ Branch 20 → 8 taken 1642 times.
✓ Branch 20 → 21 taken 1811 times.
3453 for (const auto &structManifestations : structs | std::views::values)
305
5/8
✓ Branch 9 → 10 taken 1642 times.
✗ Branch 9 → 25 not taken.
✓ Branch 10 → 11 taken 1642 times.
✗ Branch 10 → 25 not taken.
✓ Branch 11 → 12 taken 1642 times.
✗ Branch 11 → 25 not taken.
✓ Branch 17 → 13 taken 1645 times.
✓ Branch 17 → 18 taken 1642 times.
3287 for (const auto &manifestation : structManifestations | std::views::values)
306
1/2
✓ Branch 14 → 15 taken 1645 times.
✗ Branch 14 → 24 not taken.
1645 manifestations.push_back(&manifestation);
307
308 // Sort manifestations by declaration code location
309
2/2
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 3728 times.
7464 auto sortLambda = [](const Struct *lhs, const Struct *rhs) { return lhs->getDeclCodeLoc() < rhs->getDeclCodeLoc(); };
310
1/2
✓ Branch 21 → 22 taken 1811 times.
✗ Branch 21 → 27 not taken.
1811 std::ranges::sort(manifestations, sortLambda);
311 1811 return manifestations;
312 } // LCOV_EXCL_LINE - false positive
313
314 /**
315 * Get the current number of nested loops
316 *
317 * @return Number of loops
318 */
319 4603 unsigned int Scope::getLoopNestingDepth() const { // NOLINT(misc-no-recursion)
320
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 4603 times.
4603 assert(!isRootScope());
321
2/2
✓ Branch 6 → 7 taken 865 times.
✓ Branch 6 → 8 taken 3738 times.
4603 if (parent->parent == nullptr)
322 865 return 0;
323 3738 unsigned int loopCount = parent->getLoopNestingDepth();
324
6/6
✓ Branch 9 → 10 taken 3524 times.
✓ Branch 9 → 12 taken 214 times.
✓ Branch 10 → 11 taken 2341 times.
✓ Branch 10 → 12 taken 1183 times.
✓ Branch 11 → 12 taken 92 times.
✓ Branch 11 → 13 taken 2249 times.
3738 if (type == ScopeType::WHILE_BODY || type == ScopeType::FOR_BODY || type == ScopeType::FOREACH_BODY)
325 1489 loopCount++;
326 3738 return loopCount;
327 }
328
329 /**
330 * Check if this scope is one of the child scopes of a switch statement
331 *
332 * @return Child scope of switch statement or not
333 */
334 7 bool Scope::isInCaseBranch() const { // NOLINT(misc-no-recursion)
335
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
7 assert(!isRootScope());
336
2/2
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 8 taken 5 times.
7 if (parent->parent == nullptr)
337 2 return false;
338
2/2
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 10 taken 1 time.
5 if (type == ScopeType::CASE_BODY)
339 4 return true;
340 1 return parent->isInCaseBranch();
341 }
342
343 /**
344 * Check if this scope is within an async scope
345 *
346 * @return Within async scope or not
347 */
348 179 bool Scope::isInAsyncScope() const { // NOLINT(misc-no-recursion)
349
2/2
✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 4 taken 171 times.
179 if (isAsyncScope)
350 8 return true;
351
3/4
✓ Branch 6 → 7 taken 121 times.
✓ Branch 6 → 10 taken 50 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 121 times.
171 return !isRootScope() && parent->isInAsyncScope();
352 }
353
354 /**
355 * Check if unsafe operations are allowed in this scope
356 *
357 * @return Allowed or not
358 */
359 8874 bool Scope::doesAllowUnsafeOperations() const { // NOLINT(misc-no-recursion)
360
2/2
✓ Branch 2 → 3 taken 5880 times.
✓ Branch 2 → 4 taken 2994 times.
8874 if (type == ScopeType::UNSAFE_BODY)
361 5880 return true;
362
4/4
✓ Branch 6 → 7 taken 2984 times.
✓ Branch 6 → 10 taken 10 times.
✓ Branch 8 → 9 taken 2968 times.
✓ Branch 8 → 10 taken 16 times.
2994 return !isRootScope() && parent->doesAllowUnsafeOperations();
363 }
364
365 /**
366 * Checks if this scope is imported
367 *
368 * @param askingScope Scope, which asks whether the current one is imported from its point of view or not
369 *
370 * @return Imported / not imported
371 */
372 193585 bool Scope::isImportedBy(const Scope *askingScope) const { return askingScope->sourceFile->imports(sourceFile); }
373
374 /**
375 * Get JSON representation of the symbol table
376 *
377 * @return Symbol table as JSON object
378 */
379 209145 nlohmann::json Scope::getSymbolTableJSON() const { // NOLINT(misc-no-recursion)
380
1/2
✓ Branch 2 → 3 taken 209145 times.
✗ Branch 2 → 42 not taken.
209145 nlohmann::json result = symbolTable.toJSON();
381
382 // Collect all children
383 209145 std::vector<nlohmann::json> jsonChildren;
384
1/2
✓ Branch 4 → 5 taken 209145 times.
✗ Branch 4 → 38 not taken.
209145 jsonChildren.reserve(children.size());
385
2/2
✓ Branch 20 → 7 taken 204848 times.
✓ Branch 20 → 21 taken 209145 times.
413993 for (const auto &[name, childScope] : children) {
386
1/2
✓ Branch 11 → 12 taken 204848 times.
✗ Branch 11 → 33 not taken.
204848 nlohmann::json c = childScope->getSymbolTableJSON();
387
2/4
✓ Branch 12 → 13 taken 204848 times.
✗ Branch 12 → 30 not taken.
✓ Branch 13 → 14 taken 204848 times.
✗ Branch 13 → 28 not taken.
204848 c["name"] = name; // Inject symbol table name into JSON object
388
1/2
✓ Branch 16 → 17 taken 204848 times.
✗ Branch 16 → 31 not taken.
204848 jsonChildren.emplace_back(c);
389 204848 }
390
2/4
✓ Branch 21 → 22 taken 209145 times.
✗ Branch 21 → 37 not taken.
✓ Branch 22 → 23 taken 209145 times.
✗ Branch 22 → 35 not taken.
209145 result["children"] = jsonChildren;
391
392 209145 return result;
393 209145 }
394
395 } // namespace spice::compiler
396