GCC Code Coverage Report


Directory: ../
File: src/ast/ASTNodes.cpp
Date: 2025-10-09 06:28:01
Coverage Exec Excl Total
Lines: 69.3% 224 0 323
Functions: 100.0% 64 0 64
Branches: 45.5% 230 0 506

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include <ast/ASTNodes.h>
4
5 #include "SourceFile.h"
6 #include <ast/Attributes.h>
7 #include <exception/SemanticError.h>
8 #include <symboltablebuilder/SymbolTableBuilder.h>
9
10 namespace spice::compiler {
11
12 // Constant definitions
13 static constexpr size_t ERROR_MESSAGE_CONTEXT = 20;
14
15 845 std::string ASTNode::getErrorMessage() const {
16 845 antlr4::CharStream *inputStream = codeLoc.sourceFile->antlrCtx.inputStream.get();
17 845 const antlr4::misc::Interval &sourceInterval = codeLoc.sourceInterval;
18 845 antlr4::misc::Interval extSourceInterval(sourceInterval);
19
20 // If we have a multi-line interval, only use the first line
21
3/4
✓ Branch 3 → 4 taken 845 times.
✗ Branch 3 → 77 not taken.
✓ Branch 6 → 7 taken 19 times.
✓ Branch 6 → 8 taken 826 times.
845 if (const size_t offset = inputStream->getText(extSourceInterval).find('\n'); offset != std::string::npos)
22 19 extSourceInterval.b = extSourceInterval.a + static_cast<ssize_t>(offset);
23
24 845 size_t markerIndentation = 0;
25
2/2
✓ Branch 20 → 9 taken 9152 times.
✓ Branch 20 → 21 taken 212 times.
9364 for (; markerIndentation < ERROR_MESSAGE_CONTEXT; markerIndentation++) {
26 9152 extSourceInterval.a--;
27
9/12
✓ Branch 9 → 10 taken 9138 times.
✓ Branch 9 → 13 taken 14 times.
✓ Branch 10 → 11 taken 9138 times.
✗ Branch 10 → 78 not taken.
✓ Branch 12 → 13 taken 619 times.
✓ Branch 12 → 14 taken 8519 times.
✓ Branch 15 → 16 taken 9138 times.
✓ Branch 15 → 17 taken 14 times.
✓ Branch 17 → 18 taken 633 times.
✓ Branch 17 → 19 taken 8519 times.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
9152 if (extSourceInterval.a < 0 || inputStream->getText(extSourceInterval).find('\n') != std::string::npos) {
28 633 extSourceInterval.a++;
29 633 break;
30 }
31 }
32
2/2
✓ Branch 34 → 22 taken 2411 times.
✓ Branch 34 → 35 taken 8 times.
2419 for (size_t suffixContext = 0; suffixContext < ERROR_MESSAGE_CONTEXT; suffixContext++) {
33 2411 extSourceInterval.b++;
34
4/6
✓ Branch 22 → 23 taken 2411 times.
✗ Branch 22 → 82 not taken.
✓ Branch 23 → 24 taken 2411 times.
✗ Branch 23 → 27 not taken.
✓ Branch 26 → 27 taken 837 times.
✓ Branch 26 → 28 taken 1574 times.
4822 if (static_cast<size_t>(extSourceInterval.b) > inputStream->size() ||
35
4/8
✓ Branch 24 → 25 taken 2411 times.
✗ Branch 24 → 82 not taken.
✓ Branch 29 → 30 taken 2411 times.
✗ Branch 29 → 31 not taken.
✓ Branch 31 → 32 taken 837 times.
✓ Branch 31 → 33 taken 1574 times.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
4822 inputStream->getText(extSourceInterval).find('\n') != std::string::npos) {
36 837 extSourceInterval.b--;
37 837 break;
38 }
39 }
40
41 // Trim start
42
3/4
✓ Branch 37 → 38 taken 4825 times.
✗ Branch 37 → 86 not taken.
✓ Branch 40 → 36 taken 3980 times.
✓ Branch 40 → 41 taken 845 times.
4825 while (inputStream->getText(extSourceInterval)[0] == ' ') {
43 3980 extSourceInterval.a++;
44 3980 markerIndentation--;
45 }
46
47 // Trim end
48
3/4
✓ Branch 41 → 42 taken 845 times.
✗ Branch 41 → 87 not taken.
✓ Branch 45 → 46 taken 19 times.
✓ Branch 45 → 47 taken 826 times.
845 if (inputStream->getText(extSourceInterval)[extSourceInterval.length() - 1] == '\n')
49 19 extSourceInterval.b--;
50
51 845 const std::string lineNumberStr = std::to_string(codeLoc.line);
52 845 markerIndentation += lineNumberStr.length() + 2;
53
54 // Build error message
55
1/2
✓ Branch 49 → 50 taken 845 times.
✗ Branch 49 → 107 not taken.
845 std::stringstream ss;
56
5/10
✓ Branch 50 → 51 taken 845 times.
✗ Branch 50 → 105 not taken.
✓ Branch 51 → 52 taken 845 times.
✗ Branch 51 → 105 not taken.
✓ Branch 52 → 53 taken 845 times.
✗ Branch 52 → 90 not taken.
✓ Branch 53 → 54 taken 845 times.
✗ Branch 53 → 88 not taken.
✓ Branch 54 → 55 taken 845 times.
✗ Branch 54 → 88 not taken.
845 ss << lineNumberStr << " " << inputStream->getText(extSourceInterval) << "\n";
57
2/4
✓ Branch 58 → 59 taken 845 times.
✗ Branch 58 → 93 not taken.
✓ Branch 59 → 60 taken 845 times.
✗ Branch 59 → 91 not taken.
1690 ss << std::string(markerIndentation, ' ');
58
2/4
✓ Branch 67 → 68 taken 845 times.
✗ Branch 67 → 99 not taken.
✓ Branch 68 → 69 taken 845 times.
✗ Branch 68 → 97 not taken.
845 ss << std::string(std::min(sourceInterval.length(), extSourceInterval.length()), '^');
59
1/2
✓ Branch 71 → 72 taken 845 times.
✗ Branch 71 → 105 not taken.
1690 return ss.str();
60 845 }
61
62 30938 const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion)
63
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 30938 times.
30938 assert(parent != nullptr && "Could not find next outer statement list");
64
2/2
✓ Branch 5 → 6 taken 18664 times.
✓ Branch 5 → 14 taken 12274 times.
49602 return isStmtLst() ? spice_pointer_cast<const StmtLstNode *>(this) : parent->getNextOuterStmtLst();
65 }
66
67 368 bool MainFctDefNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
68 368 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
69 }
70
71 11250 bool FctDefBaseNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
72 11250 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
73 }
74
75 46 CompileTimeValue GlobalVarDefNode::getCompileTimeValue() const { return constant->getCompileTimeValue(); }
76
77 1108 bool ForLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
78 // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths,
79 // we can assume that the loop itself will always return
80
3/4
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 7 taken 1107 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
1108 const bool loopConditionAlwaysTrue = condAssign->hasCompileTimeValue() && condAssign->getCompileTimeValue().boolValue;
81
1/4
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 12 taken 1108 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
1108 return loopConditionAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
82 }
83
84 725 bool WhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
85 // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths,
86 // we can assume that the loop itself will always return
87
3/4
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 7 taken 721 times.
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 7 not taken.
725 const bool loopConditionAlwaysTrue = condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue;
88
3/4
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 12 taken 721 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 4 times.
725 return loopConditionAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
89 }
90
91 9 bool DoWhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
92 // Do-while loops will always be executed at least once. So if the body returns on all control paths, the loop will as well
93 9 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
94 }
95
96 3313 bool IfStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion)
97 // If the condition always evaluates to 'true' the then block must return
98
6/6
✓ Branch 3 → 4 taken 13 times.
✓ Branch 3 → 7 taken 3300 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 9 times.
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 11 taken 3309 times.
3313 if (condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue)
99 4 return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
100
101 // If the condition always evaluates to 'false' the else block must return
102
5/6
✓ Branch 12 → 13 taken 9 times.
✓ Branch 12 → 16 taken 3300 times.
✓ Branch 14 → 15 taken 9 times.
✗ Branch 14 → 16 not taken.
✓ Branch 17 → 18 taken 9 times.
✓ Branch 17 → 24 taken 3300 times.
3309 if (condition->hasCompileTimeValue() && !condition->getCompileTimeValue().boolValue)
103
3/4
✓ Branch 18 → 19 taken 4 times.
✓ Branch 18 → 22 taken 5 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 4 times.
9 return elseStmt != nullptr && elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
104
105 // If the condition does not always evaluate to 'true' or 'false' we need to check both branches
106
4/4
✓ Branch 25 → 26 taken 2472 times.
✓ Branch 25 → 30 taken 828 times.
✓ Branch 26 → 27 taken 30 times.
✓ Branch 26 → 30 taken 2442 times.
3330 return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable) && elseStmt != nullptr &&
107
1/2
✓ Branch 28 → 29 taken 30 times.
✗ Branch 28 → 30 not taken.
3330 elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
108 }
109
110 34 bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion)
111
2/2
✓ Branch 2 → 3 taken 11 times.
✓ Branch 2 → 5 taken 23 times.
34 if (isElseIf)
112 11 return ifStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
113 23 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
114 }
115
116 12 bool SwitchStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
117 42 const auto pred = [=](const CaseBranchNode *node) { return node->returnsOnAllControlPaths(doSetPredecessorsUnreachable); };
118
1/2
✓ Branch 2 → 3 taken 12 times.
✗ Branch 2 → 15 not taken.
12 const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches, pred);
119
4/6
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 6 taken 6 times.
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 15 not taken.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 7 not taken.
12 const bool defaultBranchReturns = !defaultBranch || defaultBranch->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
120
3/4
✓ Branch 8 → 9 taken 9 times.
✓ Branch 8 → 11 taken 3 times.
✓ Branch 9 → 10 taken 9 times.
✗ Branch 9 → 11 not taken.
24 return allCaseBranchesReturn && defaultBranchReturns;
121 }
122
123 42 bool CaseBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
124 42 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
125 }
126
127 6 bool DefaultBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
128 6 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
129 }
130
131 17215 bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
132 // An empty statement list does not return at all
133
2/2
✓ Branch 3 → 4 taken 32 times.
✓ Branch 3 → 5 taken 17183 times.
17215 if (statements.empty())
134 32 return false;
135 // A statement list returns on all control paths, if the one direct child statement returns on all control paths
136 17183 bool returnsOnAllControlPaths = false;
137
2/2
✓ Branch 18 → 7 taken 32849 times.
✓ Branch 18 → 19 taken 17183 times.
50032 for (StmtNode *child : statements) {
138
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 32849 times.
32849 assert(child != nullptr);
139
140 // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false
141
4/4
✓ Branch 10 → 11 taken 882 times.
✓ Branch 10 → 13 taken 31967 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 875 times.
32849 if (returnsOnAllControlPaths && *doSetPredecessorsUnreachable)
142 7 child->unreachable = true;
143
144
3/4
✓ Branch 13 → 14 taken 32849 times.
✗ Branch 13 → 21 not taken.
✓ Branch 14 → 15 taken 10653 times.
✓ Branch 14 → 16 taken 22196 times.
32849 if (child->returnsOnAllControlPaths(doSetPredecessorsUnreachable))
145 10653 returnsOnAllControlPaths = true;
146 }
147 17183 return returnsOnAllControlPaths;
148 }
149
150 2419 std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const {
151
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2419 times.
2419 assert(ATTR_CONFIGS.contains(key));
152
153 2419 std::vector<const CompileTimeValue *> attributeValues;
154
2/2
✓ Branch 19 → 7 taken 3765 times.
✓ Branch 19 → 20 taken 2419 times.
6184 for (const AttrNode *attrNode : attributes) {
155 // Skip attributes with different keys
156
2/2
✓ Branch 9 → 10 taken 2821 times.
✓ Branch 9 → 11 taken 944 times.
3765 if (attrNode->key != key)
157 2821 continue;
158
159 // Found a matching attribute
160 944 const CompileTimeValue *value = attrNode->getValue();
161
2/2
✓ Branch 12 → 13 taken 57 times.
✓ Branch 12 → 15 taken 887 times.
944 if (!value) {
162 // If the attribute has no value, we use the default value
163
1/2
✓ Branch 13 → 14 taken 57 times.
✗ Branch 13 → 22 not taken.
57 attributeValues.push_back(&DEFAULT_BOOL_COMPILE_VALUE);
164 } else {
165 // If the attribute has a value, we use the value
166
1/2
✓ Branch 15 → 16 taken 887 times.
✗ Branch 15 → 23 not taken.
887 attributeValues.push_back(value);
167 }
168 }
169
170 2419 return attributeValues;
171 }
172
173 1441 const CompileTimeValue *AttrLstNode::getAttrValueByName(const std::string &key) const {
174
1/2
✓ Branch 2 → 3 taken 1441 times.
✗ Branch 2 → 12 not taken.
1441 const std::vector<const CompileTimeValue *> attrs = getAttrValuesByName(key);
175
2/2
✓ Branch 4 → 5 taken 928 times.
✓ Branch 4 → 6 taken 513 times.
2882 return attrs.empty() ? nullptr : attrs.back();
176 1441 }
177
178 1288 bool AttrLstNode::hasAttr(const std::string &key) const {
179 3453 return std::ranges::any_of(attributes, [&](const AttrNode *attr) { return attr->key == key; });
180 }
181
182
2/2
✓ Branch 2 → 3 taken 887 times.
✓ Branch 2 → 4 taken 57 times.
944 const CompileTimeValue *AttrNode::getValue() const { return value ? &value->compileTimeValue : nullptr; }
183
184 706 bool AssertStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
185 // If the expression, passed to the assert statement is always evaluated to false, the assert statement will never succeed
186
4/4
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 7 taken 702 times.
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 1 time.
706 return assignExpr->hasCompileTimeValue() && !assignExpr->getCompileTimeValue().boolValue;
187 }
188
189 13325 bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
190 // If it's a ternary, do the default thing
191
2/2
✓ Branch 2 → 3 taken 7604 times.
✓ Branch 2 → 5 taken 5721 times.
13325 if (op == AssignOp::OP_NONE)
192 7604 return ternaryExpr->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
193
194 // If it's a modification on the result variable, we technically return from the function, but at the end of the function.
195
2/2
✓ Branch 5 → 6 taken 5716 times.
✓ Branch 5 → 7 taken 5 times.
5721 const AtomicExprNode *atomicExpr = lhs->postfixUnaryExpr ? lhs->postfixUnaryExpr->atomicExpr : nullptr;
196
6/6
✓ Branch 8 → 9 taken 1230 times.
✓ Branch 8 → 12 taken 4491 times.
✓ Branch 10 → 11 taken 616 times.
✓ Branch 10 → 12 taken 614 times.
✓ Branch 13 → 14 taken 616 times.
✓ Branch 13 → 15 taken 5105 times.
5721 if (atomicExpr && atomicExpr->fqIdentifier == RETURN_VARIABLE_NAME) {
197 // If we assign the result variable, we technically return from the function, but at the end of the function.
198 // Therefore, the following code is not unreachable, but will be executed in any case.
199 616 *doSetPredecessorsUnreachable = false;
200 616 return true;
201 }
202
203 5105 return false;
204 }
205
206 10097 bool TernaryExprNode::hasCompileTimeValue() const {
207
4/4
✓ Branch 2 → 3 taken 7 times.
✓ Branch 2 → 5 taken 10090 times.
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 3 times.
10097 const bool trueExprHasCompileTimeValue = !trueExpr || trueExpr->hasCompileTimeValue();
208
4/4
✓ Branch 7 → 8 taken 7 times.
✓ Branch 7 → 10 taken 10090 times.
✓ Branch 9 → 10 taken 5 times.
✓ Branch 9 → 11 taken 2 times.
10097 const bool falseExprHasCompileTimeValue = !falseExpr || falseExpr->hasCompileTimeValue();
209
4/6
✓ Branch 13 → 14 taken 219 times.
✓ Branch 13 → 17 taken 9878 times.
✓ Branch 14 → 15 taken 219 times.
✗ Branch 14 → 17 not taken.
✓ Branch 15 → 16 taken 219 times.
✗ Branch 15 → 17 not taken.
10097 return condition->hasCompileTimeValue() && trueExprHasCompileTimeValue && falseExprHasCompileTimeValue;
210 }
211
212 82 CompileTimeValue TernaryExprNode::getCompileTimeValue() const {
213
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 82 times.
82 assert(condition != nullptr);
214
2/4
✓ Branch 4 → 5 taken 82 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 82 times.
✗ Branch 5 → 7 not taken.
82 if (!trueExpr && !falseExpr)
215 82 return condition->getCompileTimeValue();
216
217 // If the condition has no compile time value, we do not need to evaluate the true and false values
218 if (!condition->hasCompileTimeValue())
219 return {};
220
221 // Check if the condition always evaluates to 'true'
222 if (condition->getCompileTimeValue().boolValue) {
223 const LogicalOrExprNode *trueValue = isShortened ? condition : trueExpr;
224 assert(trueValue != nullptr);
225 return trueValue->getCompileTimeValue();
226 }
227
228 assert(falseExpr != nullptr);
229 return falseExpr->getCompileTimeValue();
230 }
231
232 10694 bool LogicalOrExprNode::hasCompileTimeValue() const {
233 21390 return std::ranges::all_of(operands, [](const LogicalAndExprNode *node) { return node->hasCompileTimeValue(); });
234 }
235
236 82 CompileTimeValue LogicalOrExprNode::getCompileTimeValue() const {
237
2/2
✓ Branch 3 → 4 taken 80 times.
✓ Branch 3 → 6 taken 2 times.
82 if (operands.size() == 1)
238 80 return operands.front()->getCompileTimeValue();
239
240 // Check if one expression evaluates to 'true'
241
2/2
✓ Branch 17 → 8 taken 4 times.
✓ Branch 17 → 18 taken 2 times.
6 for (const LogicalAndExprNode *op : operands) {
242
2/4
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 21 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 4 times.
4 assert(op->hasCompileTimeValue());
243 // If one operand evaluates to 'true' the whole expression is 'true'
244
2/4
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 20 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 4 times.
4 if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); opCompileTimeValue.boolValue)
245 return CompileTimeValue{.boolValue = true};
246 }
247
248 // Return 'false'
249 2 return CompileTimeValue{.boolValue = false};
250 }
251
252 10700 bool LogicalAndExprNode::hasCompileTimeValue() const {
253 21402 return std::ranges::all_of(operands, [](const BitwiseOrExprNode *node) { return node->hasCompileTimeValue(); });
254 }
255
256 84 CompileTimeValue LogicalAndExprNode::getCompileTimeValue() const {
257
2/2
✓ Branch 3 → 4 taken 82 times.
✓ Branch 3 → 6 taken 2 times.
84 if (operands.size() == 1)
258 82 return operands.front()->getCompileTimeValue();
259
260 // Check if all expressions evaluate to 'true'
261
1/2
✓ Branch 17 → 8 taken 4 times.
✗ Branch 17 → 18 not taken.
4 for (const BitwiseOrExprNode *op : operands) {
262
2/4
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 21 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 4 times.
4 assert(op->hasCompileTimeValue());
263 // If one operand evaluates to 'false' the whole expression is 'false'
264
3/4
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 20 not taken.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 15 taken 2 times.
4 if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); !opCompileTimeValue.boolValue)
265 2 return CompileTimeValue{.boolValue = false};
266 }
267
268 // Return 'false'
269 return CompileTimeValue{.boolValue = false};
270 }
271
272 10706 bool BitwiseOrExprNode::hasCompileTimeValue() const {
273 21412 return std::ranges::all_of(operands, [](const BitwiseXorExprNode *node) { return node->hasCompileTimeValue(); });
274 }
275
276 86 CompileTimeValue BitwiseOrExprNode::getCompileTimeValue() const {
277
1/2
✓ Branch 3 → 4 taken 86 times.
✗ Branch 3 → 7 not taken.
86 if (operands.size() == 1)
278
1/2
✓ Branch 5 → 6 taken 86 times.
✗ Branch 5 → 23 not taken.
86 return operands.front()->getCompileTimeValue();
279
280 CompileTimeValue result = operands.front()->getCompileTimeValue();
281 for (size_t i = 1; i < operands.size(); i++) {
282 assert(operands.at(i)->hasCompileTimeValue());
283 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
284 result.longValue |= opCompileTimeValue.longValue;
285 }
286
287 return result;
288 }
289
290 10706 bool BitwiseXorExprNode::hasCompileTimeValue() const {
291 21412 return std::ranges::all_of(operands, [](const BitwiseAndExprNode *node) { return node->hasCompileTimeValue(); });
292 }
293
294 86 CompileTimeValue BitwiseXorExprNode::getCompileTimeValue() const {
295
1/2
✓ Branch 3 → 4 taken 86 times.
✗ Branch 3 → 7 not taken.
86 if (operands.size() == 1)
296
1/2
✓ Branch 5 → 6 taken 86 times.
✗ Branch 5 → 23 not taken.
86 return operands.front()->getCompileTimeValue();
297
298 CompileTimeValue result = operands.front()->getCompileTimeValue();
299 for (size_t i = 1; i < operands.size(); i++) {
300 assert(operands.at(i)->hasCompileTimeValue());
301 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
302 result.longValue ^= opCompileTimeValue.longValue;
303 }
304
305 return result;
306 }
307
308 10706 bool BitwiseAndExprNode::hasCompileTimeValue() const {
309 21412 return std::ranges::all_of(operands, [](const EqualityExprNode *node) { return node->hasCompileTimeValue(); });
310 }
311
312 86 CompileTimeValue BitwiseAndExprNode::getCompileTimeValue() const {
313
1/2
✓ Branch 3 → 4 taken 86 times.
✗ Branch 3 → 7 not taken.
86 if (operands.size() == 1)
314
1/2
✓ Branch 5 → 6 taken 86 times.
✗ Branch 5 → 23 not taken.
86 return operands.front()->getCompileTimeValue();
315
316 CompileTimeValue result = operands.front()->getCompileTimeValue();
317 for (size_t i = 1; i < operands.size(); i++) {
318 assert(operands.at(i)->hasCompileTimeValue());
319 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
320 result.longValue &= opCompileTimeValue.longValue;
321 }
322
323 return result;
324 }
325
326 10706 bool EqualityExprNode::hasCompileTimeValue() const {
327 21422 return std::ranges::all_of(operands, [](const RelationalExprNode *node) { return node->hasCompileTimeValue(); });
328 }
329
330 86 CompileTimeValue EqualityExprNode::getCompileTimeValue() const {
331
2/2
✓ Branch 3 → 4 taken 76 times.
✓ Branch 3 → 7 taken 10 times.
86 if (operands.size() == 1)
332
1/2
✓ Branch 5 → 6 taken 76 times.
✗ Branch 5 → 34 not taken.
76 return operands.front()->getCompileTimeValue();
333
334
2/4
✓ Branch 7 → 8 taken 10 times.
✗ Branch 7 → 34 not taken.
✓ Branch 8 → 9 taken 10 times.
✗ Branch 8 → 34 not taken.
10 const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue();
335
2/4
✓ Branch 9 → 10 taken 10 times.
✗ Branch 9 → 34 not taken.
✓ Branch 10 → 11 taken 10 times.
✗ Branch 10 → 34 not taken.
10 const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue();
336
2/2
✓ Branch 11 → 12 taken 6 times.
✓ Branch 11 → 13 taken 4 times.
10 if (op == EqualityOp::OP_EQUAL)
337 6 return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue};
338
1/2
✓ Branch 13 → 14 taken 4 times.
✗ Branch 13 → 15 not taken.
4 if (op == EqualityOp::OP_NOT_EQUAL)
339 4 return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue};
340
341 throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()");
342 }
343
344 10716 bool RelationalExprNode::hasCompileTimeValue() const {
345 21433 return std::ranges::all_of(operands, [](const ShiftExprNode *node) { return node->hasCompileTimeValue(); });
346 }
347
348 96 CompileTimeValue RelationalExprNode::getCompileTimeValue() const {
349
2/2
✓ Branch 3 → 4 taken 95 times.
✓ Branch 3 → 7 taken 1 time.
96 if (operands.size() == 1)
350
1/2
✓ Branch 5 → 6 taken 95 times.
✗ Branch 5 → 38 not taken.
95 return operands.front()->getCompileTimeValue();
351
352
2/4
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 38 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 38 not taken.
1 const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue();
353
2/4
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 38 not taken.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 38 not taken.
1 const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue();
354
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
1 if (op == RelationalOp::OP_LESS)
355 return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue};
356
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 1 time.
1 if (op == RelationalOp::OP_GREATER)
357 return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue};
358
1/2
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
1 if (op == RelationalOp::OP_LESS_EQUAL)
359 1 return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue};
360 if (op == RelationalOp::OP_GREATER_EQUAL)
361 return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue};
362
363 throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()");
364 }
365
366 10717 bool ShiftExprNode::hasCompileTimeValue() const {
367 21434 return std::ranges::all_of(operands, [](const AdditiveExprNode *node) { return node->hasCompileTimeValue(); });
368 }
369
370 97 CompileTimeValue ShiftExprNode::getCompileTimeValue() const {
371
1/2
✓ Branch 3 → 4 taken 97 times.
✗ Branch 3 → 7 not taken.
97 if (operands.size() == 1)
372
1/2
✓ Branch 5 → 6 taken 97 times.
✗ Branch 5 → 49 not taken.
97 return operands.front()->getCompileTimeValue();
373
374 CompileTimeValue result = operands.front()->getCompileTimeValue();
375 OpQueue opQueueCopy = opQueue;
376 for (size_t i = 1; i < operands.size(); i++) {
377 assert(operands.at(i)->hasCompileTimeValue());
378 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
379 const ShiftOp op = opQueueCopy.front().first;
380 opQueueCopy.pop();
381 if (op == ShiftOp::OP_SHIFT_LEFT)
382 result.longValue <<= opCompileTimeValue.longValue;
383 else if (op == ShiftOp::OP_SHIFT_RIGHT)
384 result.longValue >>= opCompileTimeValue.longValue;
385 else
386 throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()");
387 }
388 return result;
389 }
390
391 10717 bool AdditiveExprNode::hasCompileTimeValue() const {
392 21434 return std::ranges::all_of(operands, [](const MultiplicativeExprNode *node) { return node->hasCompileTimeValue(); });
393 }
394
395 97 CompileTimeValue AdditiveExprNode::getCompileTimeValue() const {
396
1/2
✓ Branch 3 → 4 taken 97 times.
✗ Branch 3 → 7 not taken.
97 if (operands.size() == 1)
397
1/2
✓ Branch 5 → 6 taken 97 times.
✗ Branch 5 → 49 not taken.
97 return operands.front()->getCompileTimeValue();
398
399 CompileTimeValue result = operands.front()->getCompileTimeValue();
400 OpQueue opQueueCopy = opQueue;
401 for (size_t i = 1; i < operands.size(); i++) {
402 assert(operands.at(i)->hasCompileTimeValue());
403 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
404 const AdditiveOp op = opQueueCopy.front().first;
405 opQueueCopy.pop();
406 if (op == AdditiveOp::OP_PLUS)
407 result.longValue += opCompileTimeValue.longValue;
408 else if (op == AdditiveOp::OP_MINUS)
409 result.longValue -= opCompileTimeValue.longValue;
410 else
411 throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()");
412 }
413 return result;
414 }
415
416 10717 bool MultiplicativeExprNode::hasCompileTimeValue() const {
417 21434 return std::ranges::all_of(operands, [](const CastExprNode *node) { return node->hasCompileTimeValue(); });
418 }
419
420 97 CompileTimeValue MultiplicativeExprNode::getCompileTimeValue() const {
421
1/2
✓ Branch 3 → 4 taken 97 times.
✗ Branch 3 → 7 not taken.
97 if (operands.size() == 1)
422
1/2
✓ Branch 5 → 6 taken 97 times.
✗ Branch 5 → 70 not taken.
97 return operands.front()->getCompileTimeValue();
423
424 CompileTimeValue result = operands.front()->getCompileTimeValue();
425 OpQueue opQueueCopy = opQueue;
426 for (size_t i = 1; i < operands.size(); i++) {
427 assert(operands.at(i)->hasCompileTimeValue());
428 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
429 const MultiplicativeOp op = opQueueCopy.front().first;
430 opQueueCopy.pop();
431 if (op == MultiplicativeOp::OP_MUL) {
432 result.longValue *= opCompileTimeValue.longValue;
433 } else if (op == MultiplicativeOp::OP_DIV) {
434 if (opCompileTimeValue.longValue == 0)
435 throw SemanticError(operands.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed.");
436 result.longValue /= opCompileTimeValue.longValue;
437 } else if (op == MultiplicativeOp::OP_REM) {
438 result.longValue %= opCompileTimeValue.longValue;
439 } else {
440 throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()");
441 }
442 }
443 return result;
444 }
445
446 10717 bool CastExprNode::hasCompileTimeValue() const {
447
2/2
✓ Branch 2 → 3 taken 371 times.
✓ Branch 2 → 5 taken 10346 times.
10717 return isCast ? assignExpr->hasCompileTimeValue() : prefixUnaryExpr->hasCompileTimeValue();
448 }
449
450 97 CompileTimeValue CastExprNode::getCompileTimeValue() const {
451
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 97 times.
97 return isCast ? assignExpr->getCompileTimeValue() : prefixUnaryExpr->getCompileTimeValue();
452 }
453
454 10702 bool PrefixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
455
2/2
✓ Branch 2 → 3 taken 10330 times.
✓ Branch 2 → 5 taken 372 times.
10702 if (postfixUnaryExpr)
456 10330 return postfixUnaryExpr->hasCompileTimeValue();
457
458
3/4
✓ Branch 6 → 7 taken 364 times.
✓ Branch 6 → 11 taken 8 times.
✓ Branch 7 → 8 taken 364 times.
✗ Branch 7 → 11 not taken.
372 const bool isSupported = op == PrefixUnaryOp::OP_NONE || op == PrefixUnaryOp::OP_MINUS || op == PrefixUnaryOp::OP_PLUS_PLUS ||
459
4/6
✓ Branch 5 → 6 taken 372 times.
✗ Branch 5 → 11 not taken.
✓ Branch 8 → 9 taken 364 times.
✗ Branch 8 → 11 not taken.
✓ Branch 9 → 10 taken 16 times.
✓ Branch 9 → 11 taken 348 times.
760 op == PrefixUnaryOp::OP_MINUS_MINUS || op == PrefixUnaryOp::OP_NOT ||
460
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 16 times.
16 op == PrefixUnaryOp::OP_BITWISE_NOT;
461
3/4
✓ Branch 13 → 14 taken 356 times.
✓ Branch 13 → 17 taken 16 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 356 times.
372 return isSupported && prefixUnaryExpr->hasCompileTimeValue();
462 }
463
464 97 CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
465
1/2
✓ Branch 2 → 3 taken 97 times.
✗ Branch 2 → 5 not taken.
97 if (postfixUnaryExpr)
466
1/2
✓ Branch 3 → 4 taken 97 times.
✗ Branch 3 → 35 not taken.
97 return postfixUnaryExpr->getCompileTimeValue();
467
468 CompileTimeValue opValue = prefixUnaryExpr->getCompileTimeValue();
469 if (op == PrefixUnaryOp::OP_MINUS)
470 return CompileTimeValue{.longValue = -opValue.longValue};
471 if (op == PrefixUnaryOp::OP_PLUS_PLUS)
472 return CompileTimeValue{.longValue = ++opValue.longValue};
473 if (op == PrefixUnaryOp::OP_MINUS_MINUS)
474 return CompileTimeValue{.longValue = --opValue.longValue};
475 if (op == PrefixUnaryOp::OP_NOT)
476 return CompileTimeValue{.boolValue = !opValue.boolValue};
477 if (op == PrefixUnaryOp::OP_BITWISE_NOT)
478 return CompileTimeValue{.longValue = ~opValue.longValue};
479
480 throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()");
481 }
482
483 10330 bool PostfixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
484
2/2
✓ Branch 2 → 3 taken 8038 times.
✓ Branch 2 → 5 taken 2292 times.
10330 if (atomicExpr)
485 8038 return atomicExpr->hasCompileTimeValue();
486
487 2292 const bool isSupported =
488
3/6
✓ Branch 5 → 6 taken 2292 times.
✗ Branch 5 → 8 not taken.
✓ Branch 6 → 7 taken 2292 times.
✗ Branch 6 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 2292 times.
2292 op == PostfixUnaryOp::OP_NONE || op == PostfixUnaryOp::OP_PLUS_PLUS || op == PostfixUnaryOp::OP_MINUS_MINUS;
489
1/4
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 14 taken 2292 times.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
2292 return isSupported && postfixUnaryExpr->hasCompileTimeValue();
490 }
491
492 97 CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
493
1/2
✓ Branch 2 → 3 taken 97 times.
✗ Branch 2 → 5 not taken.
97 if (atomicExpr)
494
1/2
✓ Branch 3 → 4 taken 97 times.
✗ Branch 3 → 29 not taken.
97 return atomicExpr->getCompileTimeValue();
495
496 CompileTimeValue opValue = postfixUnaryExpr->getCompileTimeValue();
497 if (op == PostfixUnaryOp::OP_PLUS_PLUS)
498 return CompileTimeValue{.longValue = opValue.longValue++};
499 if (op == PostfixUnaryOp::OP_MINUS_MINUS)
500 return CompileTimeValue{.longValue = opValue.longValue--};
501
502 throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()");
503 }
504
505 /**
506 * Check if right above the closest assign expression ancestor is a statement node
507 *
508 * @return Has return value receiver or not
509 */
510 9797 bool FctCallNode::hasReturnValueReceiver() const {
511 9797 const ASTNode *node = parent;
512
2/2
✓ Branch 10 → 3 taken 149200 times.
✓ Branch 10 → 11 taken 7486 times.
156686 while (!node->isAssignExpr()) {
513 // As soon as we have a node with more than one child, we know that the return value is used
514
3/4
✓ Branch 3 → 4 taken 149200 times.
✗ Branch 3 → 23 not taken.
✓ Branch 6 → 7 taken 2311 times.
✓ Branch 6 → 8 taken 146889 times.
149200 if (node->getChildren().size() > 1)
515 2311 return true;
516 146889 node = node->parent;
517 }
518 // Also check the condition of the assign expression
519
6/12
✓ Branch 11 → 12 taken 7486 times.
✗ Branch 11 → 24 not taken.
✓ Branch 13 → 14 taken 7486 times.
✗ Branch 13 → 16 not taken.
✓ Branch 14 → 15 taken 7486 times.
✗ Branch 14 → 24 not taken.
✓ Branch 15 → 16 taken 7252 times.
✓ Branch 15 → 17 taken 234 times.
✓ Branch 19 → 20 taken 7486 times.
✗ Branch 19 → 21 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 26 not taken.
7486 return node->getChildren().size() > 1 || !node->parent->isExprStmt();
520 }
521
522 12 bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
523 12 return body->returnsOnAllControlPaths(overrideUnreachable);
524 }
525
526 38 bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
527 38 return body->returnsOnAllControlPaths(overrideUnreachable);
528 }
529
530 1703 void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion)
531 // Set the current node to field type
532 1703 isFieldType = true;
533 // Do the same for all template nodes
534
4/4
✓ Branch 2 → 3 taken 785 times.
✓ Branch 2 → 12 taken 918 times.
✓ Branch 3 → 4 taken 181 times.
✓ Branch 3 → 12 taken 604 times.
1703 if (const CustomDataTypeNode *customType = baseDataType->customDataType; customType != nullptr && customType->templateTypeLst)
535
2/2
✓ Branch 10 → 6 taken 252 times.
✓ Branch 10 → 11 taken 181 times.
433 for (DataTypeNode *templateNode : customType->templateTypeLst->dataTypes)
536
1/2
✓ Branch 7 → 8 taken 252 times.
✗ Branch 7 → 13 not taken.
252 templateNode->setFieldTypeRecursive();
537 1703 }
538
539 } // namespace spice::compiler
540