GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 90.9% 219 / 5 / 246
Functions: 93.1% 27 / 0 / 29
Branches: 57.4% 309 / 0 / 538

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 <global/GlobalResourceManager.h>
9 #include <symboltablebuilder/SymbolTableBuilder.h>
10
11 namespace spice::compiler {
12
13 215788 Scope::Scope(Scope *parent, SourceFile *sourceFile, ScopeType scopeType, const CodeLoc *codeLoc)
14 215788 : parent(parent), sourceFile(sourceFile), scopeId(sourceFile->resourceManager.getNextScopeId()), codeLoc(codeLoc),
15
2/2
✓ Branch 4 → 5 taken 210229 times.
✓ Branch 4 → 6 taken 5559 times.
215788 type(scopeType) {}
16
17 /**
18 * Create a child scope and return it
19 *
20 * @param scopeName Name of the child scope
21 * @param scopeType Type of the child scope
22 * @param declCodeLoc Code location of the scope
23 * @return Child scope (heap allocated)
24 */
25 210229 Scope *Scope::createChildScope(const std::string &scopeName, ScopeType scopeType, const CodeLoc *declCodeLoc) {
26
2/4
✓ Branch 2 → 3 taken 210229 times.
✗ Branch 2 → 15 not taken.
✓ Branch 3 → 4 taken 210229 times.
✗ Branch 3 → 13 not taken.
210229 const auto &[scope, inserted] = children.emplace(scopeName, std::make_shared<Scope>(this, sourceFile, scopeType, declCodeLoc));
27
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 210229 times.
210229 assert(inserted);
28 420458 return scope->second.get();
29 }
30
31 /**
32 * Rename the child scope. This is useful for realizing function overloading by storing a function with not
33 * only its name, but also its signature
34 *
35 * @param oldName Old name of the child table
36 * @param newName New name of the child table
37 */
38 73192 void Scope::renameChildScope(const std::string &oldName, const std::string &newName) {
39
4/8
✓ Branch 2 → 3 taken 73192 times.
✗ Branch 2 → 20 not taken.
✓ Branch 3 → 4 taken 73192 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 73192 times.
✗ Branch 4 → 20 not taken.
✓ Branch 5 → 6 taken 73192 times.
✗ Branch 5 → 7 not taken.
73192 assert(children.contains(oldName) && !children.contains(newName));
40
1/2
✓ Branch 8 → 9 taken 73192 times.
✗ Branch 8 → 20 not taken.
73192 auto nodeHandler = children.extract(oldName);
41
1/2
✓ Branch 10 → 11 taken 73192 times.
✗ Branch 10 → 18 not taken.
73192 nodeHandler.key() = newName;
42
1/2
✓ Branch 13 → 14 taken 73192 times.
✗ Branch 13 → 17 not taken.
146384 children.insert(std::move(nodeHandler));
43 73192 }
44
45 /**
46 * Duplicates the child scope by copying it. The duplicated symbols point to the original ones.
47 *
48 * @param oldName Old name of the child block
49 * @param newName New block name
50 */
51 28957 Scope *Scope::copyChildScope(const std::string &oldName, const std::string &newName) {
52
4/8
✓ Branch 2 → 3 taken 28957 times.
✗ Branch 2 → 18 not taken.
✓ Branch 3 → 4 taken 28957 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 28957 times.
✗ Branch 4 → 18 not taken.
✓ Branch 5 → 6 taken 28957 times.
✗ Branch 5 → 7 not taken.
28957 assert(children.contains(oldName) && !children.contains(newName));
53 // Create copy
54
2/4
✓ Branch 8 → 9 taken 28957 times.
✗ Branch 8 → 18 not taken.
✓ Branch 10 → 11 taken 28957 times.
✗ Branch 10 → 18 not taken.
28957 const std::shared_ptr<Scope> newScope = children.at(oldName)->deepCopyScope();
55 // Save copy under new name
56
1/2
✓ Branch 11 → 12 taken 28957 times.
✗ Branch 11 → 16 not taken.
28957 children.emplace(newName, newScope);
57 57914 return newScope.get();
58 28957 }
59
60 /**
61 * Deep copy the current scope and all its children
62 *
63 * @return Deep copy of the current scope
64 */
65 155421 std::shared_ptr<Scope> Scope::deepCopyScope() { // NOLINT(misc-no-recursion)
66 155421 const auto newScope = std::make_shared<Scope>(*this);
67
1/2
✓ Branch 3 → 4 taken 155421 times.
✗ Branch 3 → 41 not taken.
155421 newScope->scopeId = sourceFile->resourceManager.getNextScopeId();
68
2/2
✓ Branch 32 → 7 taken 126464 times.
✓ Branch 32 → 33 taken 155421 times.
281885 for (const auto &[childName, oldChild] : children) {
69
2/4
✓ Branch 11 → 12 taken 126464 times.
✗ Branch 11 → 39 not taken.
✓ Branch 13 → 14 taken 126464 times.
✗ Branch 13 → 37 not taken.
126464 newScope->children[childName] = oldChild->deepCopyScope();
70
1/2
✓ Branch 18 → 19 taken 126464 times.
✗ Branch 18 → 40 not taken.
126464 newScope->children[childName]->parent = newScope.get();
71
2/4
✓ Branch 21 → 22 taken 126464 times.
✗ Branch 21 → 40 not taken.
✓ Branch 24 → 25 taken 126464 times.
✗ Branch 24 → 40 not taken.
126464 newScope->children[childName]->symbolTable.scope = newScope->children[childName].get();
72
1/2
✓ Branch 28 → 29 taken 126464 times.
✗ Branch 28 → 40 not taken.
126464 newScope->children[childName]->symbolTable.parent = &newScope->symbolTable;
73 }
74 155421 newScope->symbolTable.scope = newScope.get();
75 155421 return newScope;
76 − } // LCOV_EXCL_LINE - false positive
77
78 /**
79 * Get a child scope of the current scope by its name
80 *
81 * @param scopeName Child scope name
82 * @return Child scope
83 */
84 459047 Scope *Scope::getChildScope(const std::string &scopeName) const {
85
1/2
✓ Branch 2 → 3 taken 459047 times.
✗ Branch 2 → 12 not taken.
459047 const auto it = children.find(scopeName);
86
2/2
✓ Branch 5 → 6 taken 458969 times.
✓ Branch 5 → 8 taken 78 times.
918094 return it != children.end() ? it->second.get() : nullptr;
87 }
88
89 /**
90 * Retrieve all variables in the current scope, that have reached the end of their lifetime at the end of this scope
91 *
92 * @return Collection of EOL variables
93 */
94 204857 std::vector<SymbolTableEntry *> Scope::getVarsGoingOutOfScope() { // NOLINT(misc-no-recursion)
95
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 204857 times.
204857 assert(!isRootScope()); // Should not be called in root scope
96 204857 std::vector<SymbolTableEntry *> varsGoingOutOfScope;
97
98 // Collect all variables in this scope
99
2/2
✓ Branch 26 → 8 taken 216032 times.
✓ Branch 26 → 27 taken 204857 times.
420889 for (const auto &[name, entry] : symbolTable.symbols) {
100 // Skip 'this' and result variables
101
8/10
✓ Branch 11 → 12 taken 216032 times.
✗ Branch 11 → 52 not taken.
✓ Branch 12 → 13 taken 174643 times.
✓ Branch 12 → 15 taken 41389 times.
✓ Branch 13 → 14 taken 174643 times.
✗ Branch 13 → 52 not taken.
✓ Branch 14 → 15 taken 41440 times.
✓ Branch 14 → 16 taken 133203 times.
✓ Branch 17 → 18 taken 82829 times.
✓ Branch 17 → 19 taken 133203 times.
216032 if (name == THIS_VARIABLE_NAME || name == RETURN_VARIABLE_NAME)
102 82829 continue;
103 // Skip parameters (ToDo: Remove when copy constructors work for by-value argument passing)
104
2/2
✓ Branch 19 → 20 taken 78900 times.
✓ Branch 19 → 21 taken 54303 times.
133203 if (entry.isParam)
105 78900 continue;
106 // Found variable, that goes out of scope
107
2/4
✓ Branch 21 → 22 taken 54303 times.
✗ Branch 21 → 51 not taken.
✓ Branch 22 → 23 taken 54303 times.
✗ Branch 22 → 51 not taken.
54303 varsGoingOutOfScope.push_back(&symbolTable.symbols.at(name));
108 }
109
110 // If this is the scope of a dtor, also return all fields of the struct
111
2/2
✓ Branch 27 → 28 taken 1128 times.
✓ Branch 27 → 49 taken 203729 times.
204857 if (isDtorScope) {
112
2/4
✓ Branch 30 → 31 taken 1128 times.
✗ Branch 30 → 33 not taken.
✓ Branch 31 → 32 taken 1128 times.
✗ Branch 31 → 33 not taken.
1128 assert(!isRootScope() && parent->type == ScopeType::STRUCT);
113 // Get all fields of the struct
114
2/2
✓ Branch 47 → 36 taken 37100 times.
✓ Branch 47 → 48 taken 1128 times.
38228 for (const auto &[name, entry] : parent->symbolTable.symbols)
115
4/6
✓ Branch 39 → 40 taken 37100 times.
✗ Branch 39 → 55 not taken.
✓ Branch 40 → 41 taken 37100 times.
✗ Branch 40 → 53 not taken.
✓ Branch 41 → 42 taken 3652 times.
✓ Branch 41 → 45 taken 33448 times.
37100 if (!entry.getQualType().isOneOf({TY_FUNCTION, TY_PROCEDURE}))
116
2/4
✓ Branch 42 → 43 taken 3652 times.
✗ Branch 42 → 54 not taken.
✓ Branch 43 → 44 taken 3652 times.
✗ Branch 43 → 54 not taken.
3652 varsGoingOutOfScope.push_back(&parent->symbolTable.symbols.at(name));
117 }
118
119 204857 return varsGoingOutOfScope;
120 − } // LCOV_EXCL_LINE - false positive
121
122 /**
123 * Insert a new generic type in this scope
124 *
125 * @param typeName Generic type name
126 * @param genericType Generic type itself
127 */
128 28432 void Scope::insertGenericType(const std::string &typeName, const GenericType &genericType) {
129
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 28432 times.
28432 assert(!genericTypes.contains(typeName));
130 28432 genericTypes.emplace(typeName, genericType);
131 28432 }
132
133 /**
134 * Search for a generic type by its name in this scope.
135 * If the generic type is not found, a nullptr is returned.
136 *
137 * @param typeName Name of the generic type
138 * @return Generic type
139 */
140 220148 GenericType *Scope::lookupGenericTypeStrict(const std::string &typeName) {
141
1/2
✓ Branch 2 → 3 taken 220148 times.
✗ Branch 2 → 12 not taken.
220148 const auto it = genericTypes.find(typeName);
142
2/2
✓ Branch 5 → 6 taken 83375 times.
✓ Branch 5 → 8 taken 136773 times.
440296 return it != genericTypes.end() ? &it->second : nullptr;
143 }
144
145 /**
146 * Collect all warnings, produced within this scope
147 *
148 * @param warnings List of warnings
149 * @return Collection of warnings
150 */
151 8615 void Scope::collectWarnings(std::vector<CompilerWarning> &warnings) const { // NOLINT(misc-no-recursion)
152 // Visit own symbols
153
5/8
✓ Branch 2 → 3 taken 8615 times.
✗ Branch 2 → 239 not taken.
✓ Branch 3 → 4 taken 8615 times.
✗ Branch 3 → 239 not taken.
✓ Branch 4 → 5 taken 8615 times.
✗ Branch 4 → 239 not taken.
✓ Branch 163 → 6 taken 24844 times.
✓ Branch 163 → 164 taken 8615 times.
33459 for (const SymbolTableEntry &entry : symbolTable.symbols | std::views::values) {
154 // Do not produce a warning if the symbol is used or has a special name
155 24844 const std::string &name = entry.name;
156
6/6
✓ Branch 7 → 8 taken 785 times.
✓ Branch 7 → 10 taken 24059 times.
✓ Branch 9 → 10 taken 262 times.
✓ Branch 9 → 11 taken 523 times.
✓ Branch 12 → 13 taken 24321 times.
✓ Branch 12 → 14 taken 523 times.
24844 if (entry.used || name.starts_with(UNUSED_VARIABLE_NAME))
157 24469 continue;
158
159
1/2
✓ Branch 14 → 15 taken 523 times.
✗ Branch 14 → 238 not taken.
523 const QualType entryType = entry.getQualType();
160
161 // When compiling a static or shared library, publicly accessible symbols form part of the library's exported
162 // API. They may legitimately go unused within the library itself, since external consumers are expected to
163 // use them, so do not report them as unused. isPublic() is only defined for the type categories checked here
164 // (see the assertion in QualType::isPublic()), so guard the call accordingly.
165
12/18
✓ Branch 15 → 16 taken 523 times.
✗ Branch 15 → 238 not taken.
✓ Branch 16 → 17 taken 182 times.
✓ Branch 16 → 19 taken 341 times.
✓ Branch 17 → 18 taken 182 times.
✗ Branch 17 → 238 not taken.
✓ Branch 18 → 19 taken 4 times.
✓ Branch 18 → 24 taken 178 times.
✓ Branch 19 → 20 taken 345 times.
✗ Branch 19 → 238 not taken.
✓ Branch 20 → 21 taken 171 times.
✓ Branch 20 → 24 taken 174 times.
✓ Branch 21 → 22 taken 171 times.
✗ Branch 21 → 238 not taken.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 171 times.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 523 times.
523 if ((entryType.isExtendedPrimitive() || entryType.is(TY_ENUM)) && entryType.isPublic() && sourceFile->isLibraryOutput())
166 ✗ continue;
167
168 // Determine warning type and message by the scope type and the symbol type
169 523 CompilerWarningType warningType = UNUSED_VARIABLE;
170 523 std::string warningMessage;
171
4/4
✓ Branch 28 → 29 taken 36 times.
✓ Branch 28 → 112 taken 254 times.
✓ Branch 28 → 141 taken 8 times.
✓ Branch 28 → 147 taken 225 times.
523 switch (type) {
172 36 case ScopeType::GLOBAL: {
173 // Skip generic function/procedure/struct/interface/union entries
174
4/6
✓ Branch 29 → 30 taken 36 times.
✗ Branch 29 → 177 not taken.
✓ Branch 30 → 31 taken 22 times.
✓ Branch 30 → 35 taken 14 times.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 36 times.
58 if (entryType.isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_STRUCT, TY_INTERFACE, TY_UNION}) &&
175
2/4
✓ Branch 31 → 32 taken 22 times.
✗ Branch 31 → 177 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 22 times.
22 !entryType.getTemplateTypes().empty())
176 ✗ continue;
177
178
3/4
✓ Branch 38 → 39 taken 36 times.
✗ Branch 38 → 236 not taken.
✓ Branch 39 → 40 taken 10 times.
✓ Branch 39 → 50 taken 26 times.
36 if (entryType.is(TY_FUNCTION)) {
179
1/2
✓ Branch 40 → 41 taken 10 times.
✗ Branch 40 → 236 not taken.
10 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
180 10 warningType = UNUSED_FUNCTION;
181
3/6
✓ Branch 42 → 43 taken 10 times.
✗ Branch 42 → 182 not taken.
✓ Branch 43 → 44 taken 10 times.
✗ Branch 43 → 180 not taken.
✓ Branch 44 → 45 taken 10 times.
✗ Branch 44 → 178 not taken.
10 warningMessage = "'" + fctManifestations->front()->getSignature() + "' is unused";
182
3/4
✓ Branch 50 → 51 taken 26 times.
✗ Branch 50 → 236 not taken.
✓ Branch 51 → 52 taken 6 times.
✓ Branch 51 → 62 taken 20 times.
26 } else if (entryType.is(TY_PROCEDURE)) {
183
1/2
✓ Branch 52 → 53 taken 6 times.
✗ Branch 52 → 236 not taken.
6 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
184 6 warningType = UNUSED_PROCEDURE;
185
3/6
✓ Branch 54 → 55 taken 6 times.
✗ Branch 54 → 189 not taken.
✓ Branch 55 → 56 taken 6 times.
✗ Branch 55 → 187 not taken.
✓ Branch 56 → 57 taken 6 times.
✗ Branch 56 → 185 not taken.
6 warningMessage = "'" + fctManifestations->front()->getSignature() + "' is unused";
186
3/4
✓ Branch 62 → 63 taken 20 times.
✗ Branch 62 → 236 not taken.
✓ Branch 63 → 64 taken 2 times.
✓ Branch 63 → 70 taken 18 times.
20 } else if (entryType.is(TY_STRUCT)) {
187 2 warningType = UNUSED_STRUCT;
188
2/4
✓ Branch 64 → 65 taken 2 times.
✗ Branch 64 → 194 not taken.
✓ Branch 65 → 66 taken 2 times.
✗ Branch 65 → 192 not taken.
2 warningMessage = "The struct '" + entry.name + "' is unused";
189
3/4
✓ Branch 70 → 71 taken 18 times.
✗ Branch 70 → 236 not taken.
✓ Branch 71 → 72 taken 2 times.
✓ Branch 71 → 78 taken 16 times.
18 } else if (entryType.is(TY_INTERFACE)) {
190 2 warningType = UNUSED_INTERFACE;
191
2/4
✓ Branch 72 → 73 taken 2 times.
✗ Branch 72 → 198 not taken.
✓ Branch 73 → 74 taken 2 times.
✗ Branch 73 → 196 not taken.
2 warningMessage = "The interface '" + entry.name + "' is unused";
192
3/4
✓ Branch 78 → 79 taken 16 times.
✗ Branch 78 → 236 not taken.
✓ Branch 79 → 80 taken 2 times.
✓ Branch 79 → 86 taken 14 times.
16 } else if (entryType.is(TY_UNION)) {
193 2 warningType = UNUSED_UNION;
194
2/4
✓ Branch 80 → 81 taken 2 times.
✗ Branch 80 → 202 not taken.
✓ Branch 81 → 82 taken 2 times.
✗ Branch 81 → 200 not taken.
2 warningMessage = "The union '" + entry.name + "' is unused";
195
3/4
✓ Branch 86 → 87 taken 14 times.
✗ Branch 86 → 236 not taken.
✓ Branch 87 → 88 taken 4 times.
✓ Branch 87 → 89 taken 10 times.
14 } else if (entryType.is(TY_ENUM)) {
196 4 continue; // Do not report unused enums. Only unused enum items are reported
197
3/4
✓ Branch 89 → 90 taken 10 times.
✗ Branch 89 → 236 not taken.
✓ Branch 90 → 91 taken 8 times.
✓ Branch 90 → 97 taken 2 times.
10 } else if (entryType.is(TY_IMPORT)) {
198 8 warningType = UNUSED_IMPORT;
199
2/4
✓ Branch 91 → 92 taken 8 times.
✗ Branch 91 → 206 not taken.
✓ Branch 92 → 93 taken 8 times.
✗ Branch 92 → 204 not taken.
8 warningMessage = "The import '" + entry.name + "' is unused";
200
2/4
✓ Branch 97 → 98 taken 2 times.
✗ Branch 97 → 236 not taken.
✓ Branch 98 → 99 taken 2 times.
✗ Branch 98 → 105 not taken.
2 } else if (entryType.is(TY_ALIAS)) {
201 2 warningType = UNUSED_ALIAS;
202
2/4
✓ Branch 99 → 100 taken 2 times.
✗ Branch 99 → 210 not taken.
✓ Branch 100 → 101 taken 2 times.
✗ Branch 100 → 208 not taken.
2 warningMessage = "The type alias '" + entry.name + "' is unused";
203 } else {
204 ✗ warningType = UNUSED_VARIABLE;
205 ✗ warningMessage = "The variable '" + entry.name + "' is unused";
206 }
207
208 32 break;
209 }
210 254 case ScopeType::STRUCT: // fall-through
211 case ScopeType::INTERFACE: // fall-through
212 case ScopeType::UNION: {
213
3/4
✓ Branch 112 → 113 taken 254 times.
✗ Branch 112 → 236 not taken.
✓ Branch 113 → 114 taken 90 times.
✓ Branch 113 → 120 taken 164 times.
254 if (entry.isField()) {
214 90 warningType = UNUSED_FIELD;
215
2/4
✓ Branch 114 → 115 taken 90 times.
✗ Branch 114 → 218 not taken.
✓ Branch 115 → 116 taken 90 times.
✗ Branch 115 → 216 not taken.
90 warningMessage = "The field '" + entry.name + "' is unused";
216
2/4
✓ Branch 120 → 121 taken 164 times.
✗ Branch 120 → 220 not taken.
✓ Branch 121 → 122 taken 164 times.
✗ Branch 121 → 140 not taken.
164 } else if (entryType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
217 // Skip implicit method entries and generic templates
218
1/2
✓ Branch 122 → 123 taken 164 times.
✗ Branch 122 → 236 not taken.
164 const std::vector<Function *> *fctManifestations = entry.declNode->getFctManifestations(name);
219
5/6
✓ Branch 124 → 125 taken 20 times.
✓ Branch 124 → 127 taken 144 times.
✗ Branch 126 → 127 not taken.
✓ Branch 126 → 128 taken 20 times.
✓ Branch 129 → 130 taken 144 times.
✓ Branch 129 → 131 taken 20 times.
164 if (fctManifestations->empty() || fctManifestations->front()->implicitDefault)
220 144 continue;
221
222 20 warningType = UNUSED_METHOD;
223
3/6
✓ Branch 132 → 133 taken 20 times.
✗ Branch 132 → 225 not taken.
✓ Branch 133 → 134 taken 20 times.
✗ Branch 133 → 223 not taken.
✓ Branch 134 → 135 taken 20 times.
✗ Branch 134 → 221 not taken.
20 warningMessage = "The method '" + fctManifestations->front()->getSignature() + "' is unused";
224 }
225 110 break;
226 }
227 8 case ScopeType::ENUM: {
228 8 warningType = UNUSED_ENUM_ITEM;
229
2/4
✓ Branch 141 → 142 taken 8 times.
✗ Branch 141 → 230 not taken.
✓ Branch 142 → 143 taken 8 times.
✗ Branch 142 → 228 not taken.
8 warningMessage = "The enum item '" + entry.name + "' is unused";
230 8 break;
231 }
232 225 default: {
233 225 warningType = UNUSED_VARIABLE;
234
2/4
✓ Branch 147 → 148 taken 225 times.
✗ Branch 147 → 234 not taken.
✓ Branch 148 → 149 taken 225 times.
✗ Branch 148 → 232 not taken.
225 warningMessage = "The variable '" + entry.name + "' is unused";
235 225 break;
236 }
237 }
238
239 // Add warning
240
2/4
✓ Branch 153 → 154 taken 375 times.
✗ Branch 153 → 236 not taken.
✓ Branch 154 → 155 taken 375 times.
✗ Branch 154 → 236 not taken.
375 warnings.emplace_back(entry.getDeclCodeLoc(), warningType, warningMessage);
241
2/2
✓ Branch 157 → 158 taken 375 times.
✓ Branch 157 → 160 taken 148 times.
523 }
242
243 // Visit children
244
5/8
✓ Branch 164 → 165 taken 8615 times.
✗ Branch 164 → 240 not taken.
✓ Branch 165 → 166 taken 8615 times.
✗ Branch 165 → 240 not taken.
✓ Branch 166 → 167 taken 8615 times.
✗ Branch 166 → 240 not taken.
✓ Branch 175 → 168 taken 8057 times.
✓ Branch 175 → 176 taken 8615 times.
16672 for (const auto &childScope : children | std::views::values)
245
2/2
✓ Branch 170 → 171 taken 7629 times.
✓ Branch 170 → 173 taken 428 times.
8057 if (!childScope->isGenericScope)
246
1/2
✓ Branch 172 → 173 taken 7629 times.
✗ Branch 172 → 240 not taken.
7629 childScope->collectWarnings(warnings);
247 8615 }
248
249 /**
250 * Checks if all variables of this and all child scopes are of an explicit type.
251 * This is executed after type inference to check that all variables could be inferred correctly.
252 */
253 952189 void Scope::ensureSuccessfulTypeInference() const { // NOLINT(misc-no-recursion)
254 // Check symbols in this scope
255
2/2
✓ Branch 19 → 4 taken 1408657 times.
✓ Branch 19 → 20 taken 952187 times.
2360844 for (auto &[name, entry] : symbolTable.symbols)
256
4/6
✓ Branch 7 → 8 taken 1408657 times.
✗ Branch 7 → 40 not taken.
✓ Branch 8 → 9 taken 1408657 times.
✗ Branch 8 → 40 not taken.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 17 taken 1408655 times.
1408657 if (entry.getQualType().is(TY_DYN))
257
3/6
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 36 not taken.
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 34 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 31 not taken.
2 throw SemanticError(entry.declNode, UNEXPECTED_DYN_TYPE, "For the variable '" + name + "' no type could be inferred");
258
259 // Check child scopes
260
5/8
✓ Branch 20 → 21 taken 952187 times.
✗ Branch 20 → 41 not taken.
✓ Branch 21 → 22 taken 952187 times.
✗ Branch 21 → 41 not taken.
✓ Branch 22 → 23 taken 952187 times.
✗ Branch 22 → 41 not taken.
✓ Branch 29 → 24 taken 938514 times.
✓ Branch 29 → 30 taken 952185 times.
1890699 for (const auto &scope : children | std::views::values)
261
2/2
✓ Branch 26 → 27 taken 938512 times.
✓ Branch 26 → 41 taken 2 times.
938514 scope->ensureSuccessfulTypeInference();
262 952185 }
263
264 /**
265 * Get the number of fields if this is a struct scope
266 *
267 * @return Number of fields
268 */
269 410699 size_t Scope::getFieldCount() const {
270
3/4
✓ Branch 2 → 3 taken 164 times.
✓ Branch 2 → 5 taken 410535 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 164 times.
410699 assert(type == ScopeType::STRUCT || type == ScopeType::UNION);
271 410699 size_t fieldCount = 0;
272
5/8
✓ Branch 5 → 6 taken 410699 times.
✗ Branch 5 → 32 not taken.
✓ Branch 6 → 7 taken 410699 times.
✗ Branch 6 → 32 not taken.
✓ Branch 7 → 8 taken 410699 times.
✗ Branch 7 → 32 not taken.
✓ Branch 29 → 9 taken 8366428 times.
✓ Branch 29 → 30 taken 410699 times.
8777127 for (const auto &symbol : symbolTable.symbols | std::views::values) {
273
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 8366428 times.
8366428 if (symbol.anonymous)
274 ✗ continue;
275
1/2
✓ Branch 12 → 13 taken 8366428 times.
✗ Branch 12 → 32 not taken.
8366428 const QualType &symbolType = symbol.getQualType();
276
2/4
✓ Branch 13 → 14 taken 8366428 times.
✗ Branch 13 → 32 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 8366428 times.
8366428 if (symbolType.is(TY_IMPORT))
277 ✗ continue;
278 8366428 const ASTNode *declNode = symbol.declNode;
279
10/14
✓ Branch 16 → 17 taken 8366428 times.
✗ Branch 16 → 32 not taken.
✓ Branch 17 → 18 taken 1548178 times.
✓ Branch 17 → 22 taken 6818250 times.
✓ Branch 18 → 19 taken 1548178 times.
✗ Branch 18 → 32 not taken.
✓ Branch 19 → 20 taken 1387768 times.
✓ Branch 19 → 22 taken 160410 times.
✓ Branch 20 → 21 taken 1387768 times.
✗ Branch 20 → 32 not taken.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 1387768 times.
✓ Branch 24 → 25 taken 6978660 times.
✓ Branch 24 → 26 taken 1387768 times.
8366428 if (declNode->isFctOrProcDef() || declNode->isStructDef() || declNode->isUnionDef())
280 6978660 continue;
281 1387768 fieldCount++;
282 }
283 410699 return fieldCount;
284 }
285
286 /**
287 * Get all virtual methods in this scope, sorted by their VTable index
288 *
289 * The VTable index is assigned based on the declaration order of the methods in the implemented interface(s). This must match the
290 * order the call sites use to index into the VTable, which may differ from the order the methods are defined in within the struct.
291 *
292 * @return List of virtual method pointers
293 */
294 4800 std::vector<const Function *> Scope::getVirtualMethods() {
295
3/4
✓ Branch 2 → 3 taken 2148 times.
✓ Branch 2 → 5 taken 2652 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2148 times.
4800 assert(type == ScopeType::STRUCT || type == ScopeType::INTERFACE);
296
297 // Collect all virtual methods
298 4800 std::vector<const Function *> methods;
299
2/2
✓ Branch 37 → 7 taken 36398 times.
✓ Branch 37 → 38 taken 4800 times.
41197 for (auto &[fctId, manifestationList] : functions) {
300
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 36398 times.
36398 assert(!manifestationList.empty());
301
2/2
✓ Branch 34 → 15 taken 53552 times.
✓ Branch 34 → 35 taken 36397 times.
89950 for (auto &[mangledName, function] : manifestationList)
302
2/2
✓ Branch 27 → 28 taken 10940 times.
✓ Branch 27 → 32 taken 42612 times.
53552 if (function.isVirtualMethod())
303
3/6
✓ Branch 28 → 29 taken 10940 times.
✗ Branch 28 → 41 not taken.
✓ Branch 29 → 30 taken 10940 times.
✗ Branch 29 → 41 not taken.
✓ Branch 30 → 31 taken 10940 times.
✗ Branch 30 → 41 not taken.
10940 methods.push_back(&functions.at(fctId).at(mangledName));
304 }
305
306 // Sort the list by VTable index, so that the VTable layout matches the slot indices used at the call sites
307 13208 const auto pred = [](const Function *a, const Function *b) { return a->vtableIndex < b->vtableIndex; };
308
1/2
✓ Branch 38 → 39 taken 4800 times.
✗ Branch 38 → 44 not taken.
4800 std::ranges::sort(methods, pred);
309
310 4800 return methods;
311 − } // LCOV_EXCL_LINE - false positive
312
313 /**
314 * Retrieve all struct manifestations in this scope in the order of their declaration
315 *
316 * @return All struct manifestations in declaration order
317 */
318 5461 std::vector<Struct *> Scope::getAllStructManifestationsInDeclarationOrder() {
319 // Retrieve all struct manifestations in this scope
320 5461 std::vector<Struct *> manifestations;
321
1/2
✓ Branch 3 → 4 taken 5461 times.
✗ Branch 3 → 27 not taken.
5461 manifestations.reserve(structs.size()); // Reserve at least the size of individual generic structs
322
5/8
✓ Branch 4 → 5 taken 5461 times.
✗ Branch 4 → 26 not taken.
✓ Branch 5 → 6 taken 5461 times.
✗ Branch 5 → 26 not taken.
✓ Branch 6 → 7 taken 5461 times.
✗ Branch 6 → 26 not taken.
✓ Branch 20 → 8 taken 4428 times.
✓ Branch 20 → 21 taken 5461 times.
9889 for (auto &structManifestations : structs | std::views::values)
323
5/8
✓ Branch 9 → 10 taken 4428 times.
✗ Branch 9 → 25 not taken.
✓ Branch 10 → 11 taken 4428 times.
✗ Branch 10 → 25 not taken.
✓ Branch 11 → 12 taken 4428 times.
✗ Branch 11 → 25 not taken.
✓ Branch 17 → 13 taken 4452 times.
✓ Branch 17 → 18 taken 4428 times.
8880 for (auto &manifestation : structManifestations | std::views::values)
324
1/2
✓ Branch 14 → 15 taken 4452 times.
✗ Branch 14 → 24 not taken.
4452 manifestations.push_back(&manifestation);
325
326 // Sort manifestations by declaration code location
327
2/2
✓ Branch 4 → 5 taken 36 times.
✓ Branch 4 → 6 taken 2349 times.
4770 auto sortLambda = [](const Struct *lhs, const Struct *rhs) { return lhs->getDeclCodeLoc() < rhs->getDeclCodeLoc(); };
328
1/2
✓ Branch 21 → 22 taken 5461 times.
✗ Branch 21 → 27 not taken.
5461 std::ranges::sort(manifestations, sortLambda);
329 5461 return manifestations;
330 − } // LCOV_EXCL_LINE - false positive
331
332 /**
333 * Retrieve all union manifestations in this scope in the order of their declaration
334 *
335 * @return All union manifestations in declaration order
336 */
337 ✗ std::vector<Union *> Scope::getAllUnionManifestationsInDeclarationOrder() {
338 // Retrieve all union manifestations in this scope
339 ✗ std::vector<Union *> manifestations;
340 ✗ manifestations.reserve(unions.size()); // Reserve at least the size of individual generic unions
341 ✗ for (auto &unionManifestations : unions | std::views::values)
342 ✗ for (auto &manifestation : unionManifestations | std::views::values)
343 ✗ manifestations.push_back(&manifestation);
344
345 // Sort manifestations by declaration code location
346 ✗ auto sortLambda = [](const Union *lhs, const Union *rhs) { return lhs->getDeclCodeLoc() < rhs->getDeclCodeLoc(); };
347 ✗ std::ranges::sort(manifestations, sortLambda);
348 ✗ return manifestations;
349 − } // LCOV_EXCL_LINE - false positive
350
351 /**
352 * Append a fingerprint of the manifestations the IR generator emits into the object file of the owning source file.
353 * Only final once type checking has converged.
354 *
355 * @param fingerprint Stream to append to
356 */
357 24 void Scope::collectManifestationFingerprint(std::stringstream &fingerprint) const { // NOLINT(misc-no-recursion)
358 // Mirrors the emission conditions of the IR generator. The tag encodes the registry, lowercase if the manifestation is unused.
359 96 const auto append = [&](const auto &registry, char usedTag, char unusedTag) {
360
13/24
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > >(std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > const&, char, char) const:
✓ Branch 2 → 3 taken 24 times.
✗ Branch 2 → 28 not taken.
✓ Branch 3 → 4 taken 24 times.
✗ Branch 3 → 28 not taken.
✓ Branch 4 → 5 taken 24 times.
✗ Branch 4 → 28 not taken.
✗ Branch 25 → 6 not taken.
✓ Branch 25 → 26 taken 24 times.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > const&, char, char) const:
✓ Branch 2 → 3 taken 24 times.
✗ Branch 2 → 28 not taken.
✓ Branch 3 → 4 taken 24 times.
✗ Branch 3 → 28 not taken.
✓ Branch 4 → 5 taken 24 times.
✗ Branch 4 → 28 not taken.
✗ Branch 25 → 6 not taken.
✓ Branch 25 → 26 taken 24 times.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > const&, char, char) const:
✓ Branch 2 → 3 taken 24 times.
✗ Branch 2 → 28 not taken.
✓ Branch 3 → 4 taken 24 times.
✗ Branch 3 → 28 not taken.
✓ Branch 4 → 5 taken 24 times.
✗ Branch 4 → 28 not taken.
✓ Branch 25 → 6 taken 12 times.
✓ Branch 25 → 26 taken 24 times.
156 for (const auto &manifestations : registry | std::views::values)
361
2/6
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > >(std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > const&, char, char) const:
✗ Branch 22 → 9 not taken.
✗ Branch 22 → 23 not taken.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > const&, char, char) const:
✗ Branch 22 → 9 not taken.
✗ Branch 22 → 23 not taken.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > const&, char, char) const:
✓ Branch 22 → 9 taken 16 times.
✓ Branch 22 → 23 taken 12 times.
28 for (const auto &[mangledName, manifestation] : manifestations)
362
3/12
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > >(std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > const&, char, char) const:
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 27 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 20 not taken.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > const&, char, char) const:
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 27 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 20 not taken.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > const&, char, char) const:
✓ Branch 12 → 13 taken 16 times.
✗ Branch 12 → 27 not taken.
✓ Branch 13 → 14 taken 8 times.
✓ Branch 13 → 20 taken 8 times.
16 if (manifestation.isFullySubstantiated())
363
4/24
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > >(std::map<spice::compiler::CodeLoc, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > >, std::less<spice::compiler::CodeLoc>, std::allocator<std::pair<spice::compiler::CodeLoc const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Interface, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Interface> > > > > > const&, char, char) const:
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 27 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 27 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 27 not taken.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Struct, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Struct> > > > > > const&, char, char) const:
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 27 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 27 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 27 not taken.
auto spice::compiler::Scope::collectManifestationFingerprint(std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&) const::{lambda(auto:1 const&, char, char)#1}::operator()<std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > >(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, spice::compiler::Function, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, spice::compiler::Function> > > > > > const&, char, char) const:
✓ Branch 14 → 15 taken 8 times.
✗ Branch 14 → 16 not taken.
✓ Branch 17 → 18 taken 8 times.
✗ Branch 17 → 27 not taken.
✓ Branch 18 → 19 taken 8 times.
✗ Branch 18 → 27 not taken.
✓ Branch 19 → 20 taken 8 times.
✗ Branch 19 → 27 not taken.
8 fingerprint << (manifestation.used ? usedTag : unusedTag) << mangledName << '\n';
364 96 };
365
1/2
✓ Branch 2 → 3 taken 24 times.
✗ Branch 2 → 24 not taken.
24 append(functions, 'F', 'f');
366
1/2
✓ Branch 3 → 4 taken 24 times.
✗ Branch 3 → 24 not taken.
24 append(structs, 'S', 's');
367
1/2
✓ Branch 4 → 5 taken 24 times.
✗ Branch 4 → 24 not taken.
24 append(interfaces, 'I', 'i');
368
369 // Definitions cannot be nested into function bodies, so only struct and interface scopes hold further manifestations
370
5/8
✓ Branch 5 → 6 taken 24 times.
✗ Branch 5 → 23 not taken.
✓ Branch 6 → 7 taken 24 times.
✗ Branch 6 → 23 not taken.
✓ Branch 7 → 8 taken 24 times.
✗ Branch 7 → 23 not taken.
✓ Branch 21 → 9 taken 28 times.
✓ Branch 21 → 22 taken 24 times.
52 for (const std::shared_ptr<Scope> &child : children | std::views::values)
371
3/6
✓ Branch 11 → 12 taken 28 times.
✗ Branch 11 → 14 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 28 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 28 times.
28 if (child->type == ScopeType::STRUCT || child->type == ScopeType::INTERFACE)
372 ✗ child->collectManifestationFingerprint(fingerprint);
373 24 }
374
375 /**
376 * Get the current number of nested loops
377 *
378 * @return Number of loops
379 */
380 15992 unsigned int Scope::getLoopNestingDepth() const { // NOLINT(misc-no-recursion)
381
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 15992 times.
15992 assert(!isRootScope());
382
2/2
✓ Branch 6 → 7 taken 3068 times.
✓ Branch 6 → 8 taken 12924 times.
15992 if (parent->parent == nullptr)
383 3068 return 0;
384 12924 unsigned int loopCount = parent->getLoopNestingDepth();
385
6/6
✓ Branch 9 → 10 taken 11791 times.
✓ Branch 9 → 12 taken 1133 times.
✓ Branch 10 → 11 taken 8441 times.
✓ Branch 10 → 12 taken 3350 times.
✓ Branch 11 → 12 taken 392 times.
✓ Branch 11 → 13 taken 8049 times.
12924 if (type == ScopeType::WHILE_BODY || type == ScopeType::FOR_BODY || type == ScopeType::FOREACH_BODY)
386 4875 loopCount++;
387 12924 return loopCount;
388 }
389
390 /**
391 * Get the nearest enclosing function/procedure/lambda body scope, including this scope itself
392 *
393 * @return Nearest enclosing function/procedure/lambda body scope
394 */
395 108731 Scope *Scope::getFunctionScope() { // NOLINT(misc-no-recursion)
396
4/4
✓ Branch 2 → 3 taken 38300 times.
✓ Branch 2 → 4 taken 70431 times.
✓ Branch 3 → 4 taken 121 times.
✓ Branch 3 → 5 taken 38179 times.
108731 if (type == ScopeType::FUNC_PROC_BODY || type == ScopeType::LAMBDA_BODY)
397 70552 return this;
398
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 38179 times.
38179 assert(!isRootScope());
399 38179 return parent->getFunctionScope();
400 }
401
402 /**
403 * Check if this scope is one of the child scopes of a switch statement
404 *
405 * @return Child scope of switch statement or not
406 */
407 14 bool Scope::isInCaseBranch() const { // NOLINT(misc-no-recursion)
408
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 14 times.
14 assert(!isRootScope());
409
2/2
✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 8 taken 10 times.
14 if (parent->parent == nullptr)
410 4 return false;
411
2/2
✓ Branch 8 → 9 taken 8 times.
✓ Branch 8 → 10 taken 2 times.
10 if (type == ScopeType::CASE_BODY)
412 8 return true;
413 2 return parent->isInCaseBranch();
414 }
415
416 /**
417 * Check if this scope is within an async scope
418 *
419 * @return Within async scope or not
420 */
421 362 bool Scope::isInAsyncScope() const { // NOLINT(misc-no-recursion)
422
2/2
✓ Branch 2 → 3 taken 42 times.
✓ Branch 2 → 4 taken 320 times.
362 if (isAsyncScope)
423 42 return true;
424
3/4
✓ Branch 6 → 7 taken 205 times.
✓ Branch 6 → 10 taken 115 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 205 times.
320 return !isRootScope() && parent->isInAsyncScope();
425 }
426
427 /**
428 * Check if unsafe operations are allowed in this scope
429 *
430 * @return Allowed or not
431 */
432 129656 bool Scope::doesAllowUnsafeOperations() const { // NOLINT(misc-no-recursion)
433
2/2
✓ Branch 2 → 3 taken 28544 times.
✓ Branch 2 → 4 taken 101112 times.
129656 if (type == ScopeType::UNSAFE_BODY)
434 28544 return true;
435
4/4
✓ Branch 6 → 7 taken 75389 times.
✓ Branch 6 → 10 taken 25723 times.
✓ Branch 8 → 9 taken 16507 times.
✓ Branch 8 → 10 taken 58882 times.
101112 return !isRootScope() && parent->doesAllowUnsafeOperations();
436 }
437
438 /**
439 * Checks if this scope is imported
440 *
441 * @param askingScope Scope, which asks whether the current one is imported from its point of view or not
442 *
443 * @return Imported / not imported
444 */
445 627581 bool Scope::isImportedBy(const Scope *askingScope) const { return askingScope->sourceFile->imports(sourceFile); }
446
447 /**
448 * Get JSON representation of the symbol table
449 *
450 * @return Symbol table as JSON object
451 */
452 952265 nlohmann::json Scope::getSymbolTableJSON() const { // NOLINT(misc-no-recursion)
453
1/2
✓ Branch 2 → 3 taken 952265 times.
✗ Branch 2 → 42 not taken.
952265 nlohmann::json result = symbolTable.toJSON();
454
455 // Collect all children
456 952265 std::vector<nlohmann::json> jsonChildren;
457
1/2
✓ Branch 4 → 5 taken 952265 times.
✗ Branch 4 → 38 not taken.
952265 jsonChildren.reserve(children.size());
458
2/2
✓ Branch 20 → 7 taken 938600 times.
✓ Branch 20 → 21 taken 952265 times.
1890865 for (const auto &[name, childScope] : children) {
459
1/2
✓ Branch 11 → 12 taken 938600 times.
✗ Branch 11 → 33 not taken.
938600 nlohmann::json c = childScope->getSymbolTableJSON();
460
2/4
✓ Branch 12 → 13 taken 938600 times.
✗ Branch 12 → 30 not taken.
✓ Branch 13 → 14 taken 938600 times.
✗ Branch 13 → 28 not taken.
938600 c["name"] = name; // Inject symbol table name into JSON object
461
1/2
✓ Branch 16 → 17 taken 938600 times.
✗ Branch 16 → 31 not taken.
938600 jsonChildren.emplace_back(c);
462 938600 }
463
2/4
✓ Branch 21 → 22 taken 952265 times.
✗ Branch 21 → 37 not taken.
✓ Branch 22 → 23 taken 952265 times.
✗ Branch 22 → 35 not taken.
952265 result["children"] = jsonChildren;
464
465 952265 return result;
466 952265 }
467
468 } // namespace spice::compiler
469