GCC Code Coverage Report


Directory: ../
File: src/ast/ASTNodes.cpp
Date: 2024-11-22 23:10:59
Exec Total Coverage
Lines: 234 338 69.2%
Functions: 65 65 100.0%
Branches: 275 624 44.1%

Line Branch Exec Source
1 // Copyright (c) 2021-2024 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 533 std::string ASTNode::getErrorMessage() const {
16 533 antlr4::CharStream *inputStream = codeLoc.sourceFile->antlrCtx.inputStream.get();
17 533 const antlr4::misc::Interval &sourceInterval = codeLoc.sourceInterval;
18 533 antlr4::misc::Interval extSourceInterval(sourceInterval);
19
20 // If we have a multi-line interval, only use the first line
21
3/4
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 514 times.
533 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 533 size_t markerIndentation = 0;
25
2/2
✓ Branch 0 taken 5486 times.
✓ Branch 1 taken 125 times.
5611 for (; markerIndentation < ERROR_MESSAGE_CONTEXT; markerIndentation++) {
26 5486 extSourceInterval.a--;
27
9/12
✓ Branch 0 taken 5471 times.
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 5471 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 393 times.
✓ Branch 7 taken 5078 times.
✓ Branch 8 taken 5471 times.
✓ Branch 9 taken 15 times.
✓ Branch 11 taken 408 times.
✓ Branch 12 taken 5078 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
5486 if (extSourceInterval.a < 0 || inputStream->getText(extSourceInterval).find('\n') != std::string::npos) {
28 408 extSourceInterval.a++;
29 408 break;
30 }
31 }
32
2/2
✓ Branch 0 taken 1622 times.
✓ Branch 1 taken 8 times.
1630 for (size_t suffixContext = 0; suffixContext < ERROR_MESSAGE_CONTEXT; suffixContext++) {
33 1622 extSourceInterval.b++;
34
4/6
✓ Branch 1 taken 1622 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1622 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 525 times.
✓ Branch 6 taken 1097 times.
3244 if (static_cast<size_t>(extSourceInterval.b) > inputStream->size() ||
35
4/8
✓ Branch 1 taken 1622 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1622 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 525 times.
✓ Branch 8 taken 1097 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
3244 inputStream->getText(extSourceInterval).find('\n') != std::string::npos) {
36 525 extSourceInterval.b--;
37 525 break;
38 }
39 }
40
41 // Trim start
42
4/6
✓ Branch 1 taken 2713 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2713 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2180 times.
✓ Branch 8 taken 533 times.
2713 while (inputStream->getText(extSourceInterval)[0] == ' ') {
43 2180 extSourceInterval.a++;
44 2180 markerIndentation--;
45 }
46
47 // Trim end
48
4/6
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 533 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 19 times.
✓ Branch 9 taken 514 times.
533 if (inputStream->getText(extSourceInterval)[extSourceInterval.length() - 1] == '\n')
49 19 extSourceInterval.b--;
50
51 533 const std::string lineNumberStr = std::to_string(codeLoc.line);
52 533 markerIndentation += lineNumberStr.length() + 2;
53
54 // Build error message
55
1/2
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
533 std::stringstream ss;
56
5/10
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 533 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 533 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 533 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 533 times.
✗ Branch 14 not taken.
533 ss << lineNumberStr << " " << inputStream->getText(extSourceInterval) << "\n";
57
2/4
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 533 times.
✗ Branch 5 not taken.
1066 ss << std::string(markerIndentation, ' ');
58
2/4
✓ Branch 4 taken 533 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 533 times.
✗ Branch 8 not taken.
533 ss << std::string(std::min(sourceInterval.length(), extSourceInterval.length()), '^');
59
1/2
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
1066 return ss.str();
60 533 }
61
62 18388 const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion)
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18388 times.
18388 assert(parent != nullptr && "Could not find next outer statement list");
64
2/2
✓ Branch 1 taken 12472 times.
✓ Branch 2 taken 5916 times.
30860 return isStmtLstNode() ? spice_pointer_cast<const StmtLstNode *>(this) : parent->getNextOuterStmtLst();
65 }
66
67 343 bool MainFctDefNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
68 343 return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
69 }
70
71 6947 bool FctDefBaseNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
72 6947 return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
73 }
74
75 806 bool ForLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
76 // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths,
77 // we can assume that the loop itself will always return
78
7/12
✓ Branch 1 taken 806 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 806 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 805 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
806 const bool loopConditionAlwaysTrue = condAssign()->hasCompileTimeValue() && condAssign()->getCompileTimeValue().boolValue;
79
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 806 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
806 return loopConditionAlwaysTrue && body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
80 }
81
82 381 bool WhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
83 // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths,
84 // we can assume that the loop itself will always return
85
8/12
✓ Branch 1 taken 381 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 381 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 377 times.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 1 times.
381 const bool loopConditionAlwaysTrue = condition()->hasCompileTimeValue() && condition()->getCompileTimeValue().boolValue;
86
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 378 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
381 return loopConditionAlwaysTrue && body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
87 }
88
89 9 bool DoWhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
90 // Do-while loops will always be executed at least once. So if the body returns on all control paths, the loop will as well
91 9 return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
92 }
93
94 2339 bool IfStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion)
95 // If the condition always evaluates to 'true' the then block must return
96 2339 const AssignExprNode *cond = condition();
97
8/10
✓ Branch 1 taken 2339 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 2327 times.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 2335 times.
2339 if (cond->hasCompileTimeValue() && cond->getCompileTimeValue().boolValue)
98 4 return thenBody()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
99
100 // If the condition always evaluates to 'false' the else block must return
101
7/10
✓ Branch 1 taken 2335 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 2327 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 2327 times.
2335 if (cond->hasCompileTimeValue() && !cond->getCompileTimeValue().boolValue)
102
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
8 return elseStmt() != nullptr && elseStmt()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
103
104 // If the condition does not always evaluate to 'true' or 'false' we need to check both branches
105
4/4
✓ Branch 2 taken 1665 times.
✓ Branch 3 taken 662 times.
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 1636 times.
2356 return thenBody()->returnsOnAllControlPaths(doSetPredecessorsUnreachable) && elseStmt() != nullptr &&
106
1/2
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
2356 elseStmt()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
107 }
108
109 31 bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion)
110
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 21 times.
31 if (isElseIf)
111 10 return ifStmt()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
112 21 return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
113 }
114
115 8 bool SwitchStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
116 23 const auto pred = [=](const CaseBranchNode *node) { return node->returnsOnAllControlPaths(doSetPredecessorsUnreachable); };
117
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches(), pred);
118
6/10
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 5 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
8 const bool defaultBranchReturns = !defaultBranch() || defaultBranch()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
119
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
16 return allCaseBranchesReturn && defaultBranchReturns;
120 }
121
122 23 bool CaseBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
123 23 return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
124 }
125
126 3 bool DefaultBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
127 3 return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
128 }
129
130 11282 bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
131 // An empty statement list does not return at all
132
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 11254 times.
11282 if (children.empty())
133 28 return false;
134 // A statement list returns on all control paths, if the one direct child statement returns on all control paths
135 11254 bool returnsOnAllControlPaths = false;
136
2/2
✓ Branch 5 taken 22809 times.
✓ Branch 6 taken 11254 times.
34063 for (ASTNode *child : children) {
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22809 times.
22809 assert(child != nullptr);
138
139 // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false
140
4/4
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 22221 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 583 times.
22809 if (returnsOnAllControlPaths && *doSetPredecessorsUnreachable)
141 5 child->unreachable = true;
142
143
3/4
✓ Branch 1 taken 22809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6336 times.
✓ Branch 4 taken 16473 times.
22809 if (child->returnsOnAllControlPaths(doSetPredecessorsUnreachable))
144 6336 returnsOnAllControlPaths = true;
145 }
146 11254 return returnsOnAllControlPaths;
147 }
148
149 1304 std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const {
150
2/4
✓ Branch 1 taken 1304 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1304 times.
1304 assert(ATTR_CONFIGS.contains(key));
151
1/2
✓ Branch 1 taken 1304 times.
✗ Branch 2 not taken.
1304 const std::vector<AttrNode *> attrNodes = attributes();
152
153 1304 std::vector<const CompileTimeValue *> attributeValues;
154
2/2
✓ Branch 5 taken 1965 times.
✓ Branch 6 taken 1304 times.
3269 for (const AttrNode *attrNode : attrNodes) {
155 // Skip attributes with different keys
156
2/2
✓ Branch 1 taken 1314 times.
✓ Branch 2 taken 651 times.
1965 if (attrNode->key != key)
157 1314 continue;
158
159 // Found a matching attribute
160
1/2
✓ Branch 1 taken 651 times.
✗ Branch 2 not taken.
651 const CompileTimeValue *value = attrNode->getValue();
161
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 597 times.
651 if (!value) {
162 // If the attribute has no value, we use the default value
163
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 attributeValues.push_back(&DEFAULT_BOOL_COMPILE_VALUE);
164 } else {
165 // If the attribute has a value, we use the value
166
1/2
✓ Branch 1 taken 597 times.
✗ Branch 2 not taken.
597 attributeValues.push_back(value);
167 }
168 }
169
170 2608 return attributeValues;
171 1304 }
172
173 476 const CompileTimeValue *AttrLstNode::getAttrValueByName(const std::string &key) const {
174
1/2
✓ Branch 1 taken 476 times.
✗ Branch 2 not taken.
476 const std::vector<const CompileTimeValue *> attrs = getAttrValuesByName(key);
175
2/2
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 441 times.
952 return attrs.empty() ? nullptr : attrs.back();
176 476 }
177
178 788 bool AttrLstNode::hasAttr(const std::string &key) const {
179
1/2
✓ Branch 1 taken 788 times.
✗ Branch 2 not taken.
788 const std::vector<AttrNode *> attrs = attributes();
180
1/2
✓ Branch 1 taken 788 times.
✗ Branch 2 not taken.
2786 return std::ranges::any_of(attrs, [&](const AttrNode *attr) { return attr->key == key; });
181 788 }
182
183
2/2
✓ Branch 1 taken 597 times.
✓ Branch 2 taken 54 times.
651 const CompileTimeValue *AttrNode::getValue() const { return value() ? &value()->compileTimeValue : nullptr; }
184
185 607 bool AssertStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
186 // If the expression, passed to the assert statement is always evaluated to false, the assert statement will never succeed
187
8/12
✓ Branch 1 taken 607 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 607 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 604 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 1 times.
607 return assignExpr()->hasCompileTimeValue() && !assignExpr()->getCompileTimeValue().boolValue;
188 }
189
190 9852 bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
191 // If it's a ternary, do the default thing
192
2/2
✓ Branch 0 taken 5530 times.
✓ Branch 1 taken 4322 times.
9852 if (op == OP_NONE)
193 5530 return children.front()->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
194
195 // If it's a modification on the result variable, we technically return from the function, but at the end of the function.
196
4/4
✓ Branch 2 taken 4317 times.
✓ Branch 3 taken 5 times.
✓ Branch 7 taken 843 times.
✓ Branch 8 taken 3474 times.
4322 const bool hasAtomicExpr = lhs()->postfixUnaryExpr() && lhs()->postfixUnaryExpr()->atomicExpr();
197
6/6
✓ Branch 0 taken 843 times.
✓ Branch 1 taken 3479 times.
✓ Branch 6 taken 358 times.
✓ Branch 7 taken 485 times.
✓ Branch 8 taken 358 times.
✓ Branch 9 taken 3964 times.
4322 if (hasAtomicExpr && lhs()->postfixUnaryExpr()->atomicExpr()->fqIdentifier == RETURN_VARIABLE_NAME) {
198 // If we assign the result variable, we technically return from the function, but at the end of the function.
199 // Therefore, the following code is not unreachable, but will be executed in any case.
200 358 *doSetPredecessorsUnreachable = false;
201 358 return true;
202 }
203
204 3964 return false;
205 }
206
207 7048 bool TernaryExprNode::hasCompileTimeValue() const {
208
2/4
✓ Branch 1 taken 7048 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7048 times.
✗ Branch 5 not taken.
14096 return std::ranges::all_of(operands(), [](const LogicalOrExprNode *node) { return node->hasCompileTimeValue(); });
209 }
210
211 32 CompileTimeValue GlobalVarDefNode::getCompileTimeValue() const { return constant()->getCompileTimeValue(); }
212
213 79 CompileTimeValue TernaryExprNode::getCompileTimeValue() const {
214
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 if (children.size() == 1)
215
1/2
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
79 return children.front()->getCompileTimeValue();
216
217 const std::vector<LogicalOrExprNode *> &ops = operands();
218
219 // If the condition has no compile time value, we do not need to evaluate the true and false values
220 const LogicalOrExprNode *condition = ops[0];
221 if (!condition->hasCompileTimeValue())
222 return {};
223
224 // Check if condition always evaluates to 'true'
225 if (condition->getCompileTimeValue().boolValue) {
226 const LogicalOrExprNode *trueValue = isShortened ? condition : ops[1];
227 return trueValue->getCompileTimeValue();
228 } else {
229 const LogicalOrExprNode *falseValue = isShortened ? operands()[1] : ops[2];
230 return falseValue->getCompileTimeValue();
231 }
232 }
233
234 7048 bool LogicalOrExprNode::hasCompileTimeValue() const {
235
2/4
✓ Branch 1 taken 7048 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7048 times.
✗ Branch 5 not taken.
14098 return std::ranges::all_of(operands(), [](const LogicalAndExprNode *node) { return node->hasCompileTimeValue(); });
236 }
237
238 79 CompileTimeValue LogicalOrExprNode::getCompileTimeValue() const {
239
2/2
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 2 times.
79 if (children.size() == 1)
240 77 return children.front()->getCompileTimeValue();
241
242 // Check if one expression evaluates to 'true'
243
3/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 2 times.
6 for (const LogicalAndExprNode *op : operands()) {
244
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 assert(op->hasCompileTimeValue());
245 // If one operand evaluates to 'true' the whole expression is 'true'
246
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue();
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (opCompileTimeValue.boolValue)
248 return CompileTimeValue{.boolValue = true};
249
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 }
250
251 // Return 'false'
252 2 return CompileTimeValue{.boolValue = false};
253 }
254
255 7054 bool LogicalAndExprNode::hasCompileTimeValue() const {
256
2/4
✓ Branch 1 taken 7054 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7054 times.
✗ Branch 5 not taken.
14110 return std::ranges::all_of(operands(), [](const BitwiseOrExprNode *node) { return node->hasCompileTimeValue(); });
257 }
258
259 81 CompileTimeValue LogicalAndExprNode::getCompileTimeValue() const {
260
2/2
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 2 times.
81 if (children.size() == 1)
261 79 return children.front()->getCompileTimeValue();
262
263 // Check if all expressions evaluate to 'true'
264
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
4 for (const BitwiseOrExprNode *op : operands()) {
265
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 assert(op->hasCompileTimeValue());
266 // If one operand evaluates to 'false' the whole expression is 'false'
267
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue();
268
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (!opCompileTimeValue.boolValue)
269 2 return CompileTimeValue{.boolValue = false};
270
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 }
271
272 // Return 'false'
273 return CompileTimeValue{.boolValue = false};
274 }
275
276 7060 bool BitwiseOrExprNode::hasCompileTimeValue() const {
277
2/4
✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
14120 return std::ranges::all_of(operands(), [](const BitwiseXorExprNode *node) { return node->hasCompileTimeValue(); });
278 }
279
280 83 CompileTimeValue BitwiseOrExprNode::getCompileTimeValue() const {
281
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 if (children.size() == 1)
282
1/2
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
83 return children.front()->getCompileTimeValue();
283
284 const std::vector<BitwiseXorExprNode *> ops = operands();
285 CompileTimeValue result = ops.front()->getCompileTimeValue();
286 for (size_t i = 1; i < ops.size(); i++) {
287 assert(ops.at(i)->hasCompileTimeValue());
288 const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue();
289 result.longValue |= opCompileTimeValue.longValue;
290 }
291
292 return result;
293 }
294
295 7060 bool BitwiseXorExprNode::hasCompileTimeValue() const {
296
2/4
✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
14120 return std::ranges::all_of(operands(), [](const BitwiseAndExprNode *node) { return node->hasCompileTimeValue(); });
297 }
298
299 83 CompileTimeValue BitwiseXorExprNode::getCompileTimeValue() const {
300
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 if (children.size() == 1)
301
1/2
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
83 return children.front()->getCompileTimeValue();
302
303 const std::vector<BitwiseAndExprNode *> ops = operands();
304 CompileTimeValue result = ops.front()->getCompileTimeValue();
305 for (size_t i = 1; i < ops.size(); i++) {
306 assert(ops.at(i)->hasCompileTimeValue());
307 const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue();
308 result.longValue ^= opCompileTimeValue.longValue;
309 }
310
311 return result;
312 }
313
314 7060 bool BitwiseAndExprNode::hasCompileTimeValue() const {
315
2/4
✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
14120 return std::ranges::all_of(operands(), [](const EqualityExprNode *node) { return node->hasCompileTimeValue(); });
316 }
317
318 83 CompileTimeValue BitwiseAndExprNode::getCompileTimeValue() const {
319
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 if (children.size() == 1)
320
1/2
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
83 return children.front()->getCompileTimeValue();
321
322 const std::vector<EqualityExprNode *> ops = operands();
323 CompileTimeValue result = ops.front()->getCompileTimeValue();
324 for (size_t i = 1; i < ops.size(); i++) {
325 assert(ops.at(i)->hasCompileTimeValue());
326 const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue();
327 result.longValue &= opCompileTimeValue.longValue;
328 }
329
330 return result;
331 }
332
333 7060 bool EqualityExprNode::hasCompileTimeValue() const {
334
2/4
✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
14127 return std::ranges::all_of(operands(), [](const RelationalExprNode *node) { return node->hasCompileTimeValue(); });
335 }
336
337 83 CompileTimeValue EqualityExprNode::getCompileTimeValue() const {
338
2/2
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 7 times.
83 if (children.size() == 1)
339
1/2
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
76 return children.front()->getCompileTimeValue();
340
341
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 const std::vector<RelationalExprNode *> ops = operands();
342
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 const CompileTimeValue op0Value = ops.at(0)->getCompileTimeValue();
343
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 const CompileTimeValue op1Value = ops.at(1)->getCompileTimeValue();
344
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (op == OP_EQUAL)
345 2 return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue};
346
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (op == OP_NOT_EQUAL)
347 5 return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue};
348
349 throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()");
350 7 }
351
352 7067 bool RelationalExprNode::hasCompileTimeValue() const {
353
2/4
✓ Branch 1 taken 7067 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7067 times.
✗ Branch 5 not taken.
14135 return std::ranges::all_of(operands(), [](const ShiftExprNode *node) { return node->hasCompileTimeValue(); });
354 }
355
356 90 CompileTimeValue RelationalExprNode::getCompileTimeValue() const {
357
2/2
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 1 times.
90 if (children.size() == 1)
358
1/2
✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
89 return children.front()->getCompileTimeValue();
359
360
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const std::vector<ShiftExprNode *> ops = operands();
361
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 const CompileTimeValue op0Value = ops.at(0)->getCompileTimeValue();
362
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 const CompileTimeValue op1Value = ops.at(1)->getCompileTimeValue();
363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (op == OP_LESS)
364 return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue};
365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (op == OP_GREATER)
366 return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue};
367
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (op == OP_LESS_EQUAL)
368 1 return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue};
369 if (op == OP_GREATER_EQUAL)
370 return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue};
371
372 throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()");
373 1 }
374
375 7068 bool ShiftExprNode::hasCompileTimeValue() const {
376
2/4
✓ Branch 1 taken 7068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7068 times.
✗ Branch 5 not taken.
14136 return std::ranges::all_of(operands(), [](const AdditiveExprNode *node) { return node->hasCompileTimeValue(); });
377 }
378
379 91 CompileTimeValue ShiftExprNode::getCompileTimeValue() const {
380
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
381
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 return children.front()->getCompileTimeValue();
382
383 const std::vector<AdditiveExprNode *> ops = operands();
384 const CompileTimeValue op0Value = ops.at(0)->getCompileTimeValue();
385 const CompileTimeValue op1Value = ops.at(1)->getCompileTimeValue();
386 if (op == OP_SHIFT_LEFT)
387 return CompileTimeValue{.longValue = op0Value.longValue << op1Value.longValue};
388 if (op == OP_SHIFT_RIGHT)
389 return CompileTimeValue{.longValue = op0Value.longValue >> op1Value.longValue};
390
391 throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()");
392 }
393
394 7068 bool AdditiveExprNode::hasCompileTimeValue() const {
395
2/4
✓ Branch 1 taken 7068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7068 times.
✗ Branch 5 not taken.
14136 return std::ranges::all_of(operands(), [](const MultiplicativeExprNode *node) { return node->hasCompileTimeValue(); });
396 }
397
398 91 CompileTimeValue AdditiveExprNode::getCompileTimeValue() const {
399
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
400
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 return children.front()->getCompileTimeValue();
401
402 const std::vector<MultiplicativeExprNode *> ops = operands();
403 CompileTimeValue result = ops.front()->getCompileTimeValue();
404 OpQueue opQueueCopy = opQueue;
405 for (size_t i = 1; i < ops.size(); i++) {
406 assert(ops.at(i)->hasCompileTimeValue());
407 const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue();
408 const AdditiveOp op = opQueueCopy.front().first;
409 opQueueCopy.pop();
410 if (op == OP_PLUS)
411 result.longValue += opCompileTimeValue.longValue;
412 else if (op == OP_MINUS)
413 result.longValue -= opCompileTimeValue.longValue;
414 else
415 throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()");
416 }
417 return result;
418 }
419
420 7068 bool MultiplicativeExprNode::hasCompileTimeValue() const {
421
2/4
✓ Branch 1 taken 7068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7068 times.
✗ Branch 5 not taken.
14136 return std::ranges::all_of(operands(), [](const CastExprNode *node) { return node->hasCompileTimeValue(); });
422 }
423
424 91 CompileTimeValue MultiplicativeExprNode::getCompileTimeValue() const {
425
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
426
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 return children.front()->getCompileTimeValue();
427
428 const std::vector<CastExprNode *> ops = operands();
429 CompileTimeValue result = ops.front()->getCompileTimeValue();
430 OpQueue opQueueCopy = opQueue;
431 for (size_t i = 1; i < ops.size(); i++) {
432 assert(ops.at(i)->hasCompileTimeValue());
433 const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue();
434 const MultiplicativeOp op = opQueueCopy.front().first;
435 opQueueCopy.pop();
436 if (op == OP_MUL) {
437 result.longValue *= opCompileTimeValue.longValue;
438 } else if (op == OP_DIV) {
439 if (opCompileTimeValue.longValue == 0)
440 throw SemanticError(ops.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed.");
441 result.longValue /= opCompileTimeValue.longValue;
442 } else if (op == OP_REM) {
443 result.longValue %= opCompileTimeValue.longValue;
444 } else {
445 throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()");
446 }
447 }
448 return result;
449 }
450
451 7068 bool CastExprNode::hasCompileTimeValue() const { return prefixUnaryExpr()->hasCompileTimeValue(); }
452
453 91 CompileTimeValue CastExprNode::getCompileTimeValue() const {
454
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
455 91 return children.front()->getCompileTimeValue();
456
457 return prefixUnaryExpr()->getCompileTimeValue();
458 }
459
460 7317 bool PrefixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
461
2/2
✓ Branch 1 taken 7044 times.
✓ Branch 2 taken 273 times.
7317 if (postfixUnaryExpr())
462 7044 return postfixUnaryExpr()->hasCompileTimeValue();
463
464 273 const bool isOperatorSupported =
465
7/12
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 273 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 273 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✓ Branch 9 taken 249 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 24 times.
273 op == OP_NONE || op == OP_MINUS || op == OP_PLUS_PLUS || op == OP_MINUS_MINUS || op == OP_NOT || op == OP_BITWISE_NOT;
466
3/4
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 249 times.
273 return isOperatorSupported && prefixUnary()->hasCompileTimeValue();
467 }
468
469 91 CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
470
2/4
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
91 if (postfixUnaryExpr())
471
2/4
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
91 return postfixUnaryExpr()->getCompileTimeValue();
472
473 CompileTimeValue opValue = prefixUnary()->getCompileTimeValue();
474 if (op == OP_MINUS)
475 return CompileTimeValue{.longValue = -opValue.longValue};
476 if (op == OP_PLUS_PLUS)
477 return CompileTimeValue{.longValue = ++opValue.longValue};
478 if (op == OP_MINUS_MINUS)
479 return CompileTimeValue{.longValue = --opValue.longValue};
480 if (op == OP_NOT)
481 return CompileTimeValue{.boolValue = !opValue.boolValue};
482 if (op == OP_BITWISE_NOT)
483 return CompileTimeValue{.longValue = ~opValue.longValue};
484
485 throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()");
486 }
487
488 7044 bool PostfixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
489
2/2
✓ Branch 1 taken 5524 times.
✓ Branch 2 taken 1520 times.
7044 if (atomicExpr())
490 5524 return atomicExpr()->hasCompileTimeValue();
491
492
3/6
✓ Branch 0 taken 1520 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1520 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1520 times.
1520 const bool isOperatorSupported = op == OP_NONE || op == OP_PLUS_PLUS || op == OP_MINUS_MINUS;
493
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1520 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1520 return isOperatorSupported && postfixUnaryExpr()->hasCompileTimeValue();
494 }
495
496 91 CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
497
2/4
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
91 if (atomicExpr())
498
2/4
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
91 return atomicExpr()->getCompileTimeValue();
499
500 CompileTimeValue opValue = postfixUnaryExpr()->getCompileTimeValue();
501 if (op == OP_PLUS_PLUS)
502 return CompileTimeValue{.longValue = opValue.longValue++};
503 if (op == OP_MINUS_MINUS)
504 return CompileTimeValue{.longValue = opValue.longValue--};
505
506 throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()");
507 }
508
509 /**
510 * Check if right above the closest assign expression ancestor is a statement node
511 *
512 * @return Has return value receiver or not
513 */
514 6376 bool FctCallNode::hasReturnValueReceiver() const {
515 6376 const ASTNode *node = parent;
516
2/2
✓ Branch 1 taken 94813 times.
✓ Branch 2 taken 5117 times.
99930 while (!node->isAssignExpr()) {
517 // As soon as we have a node with more than one child, we know that the return value is used
518
2/2
✓ Branch 1 taken 1259 times.
✓ Branch 2 taken 93554 times.
94813 if (node->children.size() > 1)
519 1259 return true;
520 93554 node = node->parent;
521 }
522 // Also check the condition of the assign expression
523
3/4
✓ Branch 1 taken 5117 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4985 times.
✓ Branch 5 taken 132 times.
5117 return node->children.size() > 1 || !node->parent->isStmtLstNode();
524 }
525
526 9 bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
527 9 return body()->returnsOnAllControlPaths(overrideUnreachable);
528 }
529
530 38 bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
531 38 return body()->returnsOnAllControlPaths(overrideUnreachable);
532 }
533
534 1348 void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion)
535 // Set the current node to field type
536 1348 isFieldType = true;
537 // Do the same for all template nodes
538 1348 const BaseDataTypeNode *baseType = baseDataType();
539 1348 const CustomDataTypeNode *customType = baseType->customDataType();
540
6/6
✓ Branch 0 taken 539 times.
✓ Branch 1 taken 809 times.
✓ Branch 3 taken 116 times.
✓ Branch 4 taken 423 times.
✓ Branch 5 taken 116 times.
✓ Branch 6 taken 1232 times.
1348 if (customType != nullptr && customType->templateTypeLst())
541
4/6
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 116 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 154 times.
✓ Branch 12 taken 116 times.
270 for (DataTypeNode *templateNode : customType->templateTypeLst()->dataTypes())
542
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
270 templateNode->setFieldTypeRecursive();
543 1348 }
544
545 } // namespace spice::compiler
546