GCC Code Coverage Report


Directory: ../
File: src/ast/ASTNodes.cpp
Date: 2024-12-24 01:17:15
Exec Total Coverage
Lines: 224 315 71.1%
Functions: 64 64 100.0%
Branches: 230 506 45.5%

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 19084 const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion)
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19084 times.
19084 assert(parent != nullptr && "Could not find next outer statement list");
64
2/2
✓ Branch 1 taken 12472 times.
✓ Branch 2 taken 6612 times.
31556 return isStmtLst() ? 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 32 CompileTimeValue GlobalVarDefNode::getCompileTimeValue() const { return constant->getCompileTimeValue(); }
76
77 806 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
5/8
✓ Branch 1 taken 806 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 805 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
806 const bool loopConditionAlwaysTrue = condAssign->hasCompileTimeValue() && condAssign->getCompileTimeValue().boolValue;
81
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 806 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
806 return loopConditionAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
82 }
83
84 381 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
6/8
✓ Branch 1 taken 381 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 377 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 1 times.
381 const bool loopConditionAlwaysTrue = condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue;
88
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 378 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
381 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 2339 bool IfStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion)
97 // If the condition always evaluates to 'true' the then block must return
98
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 (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
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 (condition->hasCompileTimeValue() && !condition->getCompileTimeValue().boolValue)
103
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
8 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 1 taken 1665 times.
✓ Branch 2 taken 662 times.
✓ Branch 3 taken 29 times.
✓ Branch 4 taken 1636 times.
2356 return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable) && elseStmt != nullptr &&
107
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
2356 elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
108 }
109
110 31 bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion)
111
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 21 times.
31 if (isElseIf)
112 10 return ifStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
113 21 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
114 }
115
116 8 bool SwitchStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
117 23 const auto pred = [=](const CaseBranchNode *node) { return node->returnsOnAllControlPaths(doSetPredecessorsUnreachable); };
118
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches, pred);
119
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
8 const bool defaultBranchReturns = !defaultBranch || defaultBranch->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
120
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;
121 }
122
123 23 bool CaseBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
124 23 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
125 }
126
127 3 bool DefaultBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
128 3 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
129 }
130
131 11282 bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
132 // An empty statement list does not return at all
133
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 11254 times.
11282 if (children.empty())
134 28 return false;
135 // A statement list returns on all control paths, if the one direct child statement returns on all control paths
136 11254 bool returnsOnAllControlPaths = false;
137
2/2
✓ Branch 5 taken 22809 times.
✓ Branch 6 taken 11254 times.
34063 for (ASTNode *child : children) {
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22809 times.
22809 assert(child != nullptr);
139
140 // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false
141
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)
142 5 child->unreachable = true;
143
144
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))
145 6336 returnsOnAllControlPaths = true;
146 }
147 11254 return returnsOnAllControlPaths;
148 }
149
150 1304 std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const {
151
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1304 times.
1304 assert(ATTR_CONFIGS.contains(key));
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 : attributes) {
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 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 1304 return attributeValues;
171 }
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 1998 return std::ranges::any_of(attributes, [&](const AttrNode *attr) { return attr->key == key; });
180 }
181
182
2/2
✓ Branch 0 taken 597 times.
✓ Branch 1 taken 54 times.
651 const CompileTimeValue *AttrNode::getValue() const { return value ? &value->compileTimeValue : nullptr; }
183
184 607 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
6/8
✓ Branch 1 taken 607 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 604 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 1 times.
607 return assignExpr->hasCompileTimeValue() && !assignExpr->getCompileTimeValue().boolValue;
187 }
188
189 9852 bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
190 // If it's a ternary, do the default thing
191
2/2
✓ Branch 0 taken 5530 times.
✓ Branch 1 taken 4322 times.
9852 if (op == OP_NONE)
192 5530 return children.front()->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
4/4
✓ Branch 0 taken 4317 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 843 times.
✓ Branch 3 taken 3474 times.
4322 const bool hasAtomicExpr = lhs->postfixUnaryExpr && lhs->postfixUnaryExpr->atomicExpr;
196
6/6
✓ Branch 0 taken 843 times.
✓ Branch 1 taken 3479 times.
✓ Branch 3 taken 358 times.
✓ Branch 4 taken 485 times.
✓ Branch 5 taken 358 times.
✓ Branch 6 taken 3964 times.
4322 if (hasAtomicExpr && lhs->postfixUnaryExpr->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 358 *doSetPredecessorsUnreachable = false;
200 358 return true;
201 }
202
203 3964 return false;
204 }
205
206 7048 bool TernaryExprNode::hasCompileTimeValue() const {
207
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7048 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7048 const bool trueExprHasCompileTimeValue = !trueExpr || trueExpr->hasCompileTimeValue();
208
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7048 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7048 const bool falseExprHasCompileTimeValue = !falseExpr || falseExpr->hasCompileTimeValue();
209
4/6
✓ Branch 1 taken 237 times.
✓ Branch 2 taken 6811 times.
✓ Branch 3 taken 237 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 237 times.
✗ Branch 6 not taken.
7048 return condition->hasCompileTimeValue() && trueExprHasCompileTimeValue && falseExprHasCompileTimeValue;
210 }
211
212 79 CompileTimeValue TernaryExprNode::getCompileTimeValue() const {
213
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 if (children.size() == 1)
214 79 return children.front()->getCompileTimeValue();
215
216 // If the condition has no compile time value, we do not need to evaluate the true and false values
217 if (!condition->hasCompileTimeValue())
218 return {};
219
220 // Check if condition always evaluates to 'true'
221 if (condition->getCompileTimeValue().boolValue) {
222 const LogicalOrExprNode *trueValue = isShortened ? condition : trueExpr;
223 return trueValue->getCompileTimeValue();
224 } else {
225 return falseExpr->getCompileTimeValue();
226 }
227 }
228
229 7048 bool LogicalOrExprNode::hasCompileTimeValue() const {
230 14098 return std::ranges::all_of(operands, [](const LogicalAndExprNode *node) { return node->hasCompileTimeValue(); });
231 }
232
233 79 CompileTimeValue LogicalOrExprNode::getCompileTimeValue() const {
234
2/2
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 2 times.
79 if (children.size() == 1)
235 77 return children.front()->getCompileTimeValue();
236
237 // Check if one expression evaluates to 'true'
238
2/2
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
6 for (const LogicalAndExprNode *op : operands) {
239
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 assert(op->hasCompileTimeValue());
240 // If one operand evaluates to 'true' the whole expression is 'true'
241
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue();
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (opCompileTimeValue.boolValue)
243 return CompileTimeValue{.boolValue = true};
244 }
245
246 // Return 'false'
247 2 return CompileTimeValue{.boolValue = false};
248 }
249
250 7054 bool LogicalAndExprNode::hasCompileTimeValue() const {
251 14110 return std::ranges::all_of(operands, [](const BitwiseOrExprNode *node) { return node->hasCompileTimeValue(); });
252 }
253
254 81 CompileTimeValue LogicalAndExprNode::getCompileTimeValue() const {
255
2/2
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 2 times.
81 if (children.size() == 1)
256 79 return children.front()->getCompileTimeValue();
257
258 // Check if all expressions evaluate to 'true'
259
1/2
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 for (const BitwiseOrExprNode *op : operands) {
260
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 assert(op->hasCompileTimeValue());
261 // If one operand evaluates to 'false' the whole expression is 'false'
262
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue();
263
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (!opCompileTimeValue.boolValue)
264 2 return CompileTimeValue{.boolValue = false};
265 }
266
267 // Return 'false'
268 return CompileTimeValue{.boolValue = false};
269 }
270
271 7060 bool BitwiseOrExprNode::hasCompileTimeValue() const {
272 14120 return std::ranges::all_of(operands, [](const BitwiseXorExprNode *node) { return node->hasCompileTimeValue(); });
273 }
274
275 83 CompileTimeValue BitwiseOrExprNode::getCompileTimeValue() const {
276
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 if (children.size() == 1)
277
1/2
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
83 return children.front()->getCompileTimeValue();
278
279 CompileTimeValue result = operands.front()->getCompileTimeValue();
280 for (size_t i = 1; i < operands.size(); i++) {
281 assert(operands.at(i)->hasCompileTimeValue());
282 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
283 result.longValue |= opCompileTimeValue.longValue;
284 }
285
286 return result;
287 }
288
289 7060 bool BitwiseXorExprNode::hasCompileTimeValue() const {
290 14120 return std::ranges::all_of(operands, [](const BitwiseAndExprNode *node) { return node->hasCompileTimeValue(); });
291 }
292
293 83 CompileTimeValue BitwiseXorExprNode::getCompileTimeValue() const {
294
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 if (children.size() == 1)
295
1/2
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
83 return children.front()->getCompileTimeValue();
296
297 CompileTimeValue result = operands.front()->getCompileTimeValue();
298 for (size_t i = 1; i < operands.size(); i++) {
299 assert(operands.at(i)->hasCompileTimeValue());
300 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
301 result.longValue ^= opCompileTimeValue.longValue;
302 }
303
304 return result;
305 }
306
307 7060 bool BitwiseAndExprNode::hasCompileTimeValue() const {
308 14120 return std::ranges::all_of(operands, [](const EqualityExprNode *node) { return node->hasCompileTimeValue(); });
309 }
310
311 83 CompileTimeValue BitwiseAndExprNode::getCompileTimeValue() const {
312
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 if (children.size() == 1)
313
1/2
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
83 return children.front()->getCompileTimeValue();
314
315 CompileTimeValue result = operands.front()->getCompileTimeValue();
316 for (size_t i = 1; i < operands.size(); i++) {
317 assert(operands.at(i)->hasCompileTimeValue());
318 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
319 result.longValue &= opCompileTimeValue.longValue;
320 }
321
322 return result;
323 }
324
325 7060 bool EqualityExprNode::hasCompileTimeValue() const {
326 14127 return std::ranges::all_of(operands, [](const RelationalExprNode *node) { return node->hasCompileTimeValue(); });
327 }
328
329 83 CompileTimeValue EqualityExprNode::getCompileTimeValue() const {
330
2/2
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 7 times.
83 if (children.size() == 1)
331
1/2
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
76 return children.front()->getCompileTimeValue();
332
333
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue();
334
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue();
335
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (op == OP_EQUAL)
336 2 return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue};
337
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (op == OP_NOT_EQUAL)
338 5 return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue};
339
340 throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()");
341 }
342
343 7067 bool RelationalExprNode::hasCompileTimeValue() const {
344 14135 return std::ranges::all_of(operands, [](const ShiftExprNode *node) { return node->hasCompileTimeValue(); });
345 }
346
347 90 CompileTimeValue RelationalExprNode::getCompileTimeValue() const {
348
2/2
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 1 times.
90 if (children.size() == 1)
349
1/2
✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
89 return children.front()->getCompileTimeValue();
350
351
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue();
352
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue();
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (op == OP_LESS)
354 return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue};
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (op == OP_GREATER)
356 return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue};
357
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (op == OP_LESS_EQUAL)
358 1 return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue};
359 if (op == OP_GREATER_EQUAL)
360 return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue};
361
362 throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()");
363 }
364
365 7068 bool ShiftExprNode::hasCompileTimeValue() const {
366 14136 return std::ranges::all_of(operands, [](const AdditiveExprNode *node) { return node->hasCompileTimeValue(); });
367 }
368
369 91 CompileTimeValue ShiftExprNode::getCompileTimeValue() const {
370
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
371
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 return children.front()->getCompileTimeValue();
372
373 const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue();
374 const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue();
375 if (op == OP_SHIFT_LEFT)
376 return CompileTimeValue{.longValue = op0Value.longValue << op1Value.longValue};
377 if (op == OP_SHIFT_RIGHT)
378 return CompileTimeValue{.longValue = op0Value.longValue >> op1Value.longValue};
379
380 throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()");
381 }
382
383 7068 bool AdditiveExprNode::hasCompileTimeValue() const {
384 14136 return std::ranges::all_of(operands, [](const MultiplicativeExprNode *node) { return node->hasCompileTimeValue(); });
385 }
386
387 91 CompileTimeValue AdditiveExprNode::getCompileTimeValue() const {
388
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
389
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 return children.front()->getCompileTimeValue();
390
391 CompileTimeValue result = operands.front()->getCompileTimeValue();
392 OpQueue opQueueCopy = opQueue;
393 for (size_t i = 1; i < operands.size(); i++) {
394 assert(operands.at(i)->hasCompileTimeValue());
395 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
396 const AdditiveOp op = opQueueCopy.front().first;
397 opQueueCopy.pop();
398 if (op == OP_PLUS)
399 result.longValue += opCompileTimeValue.longValue;
400 else if (op == OP_MINUS)
401 result.longValue -= opCompileTimeValue.longValue;
402 else
403 throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()");
404 }
405 return result;
406 }
407
408 7068 bool MultiplicativeExprNode::hasCompileTimeValue() const {
409 14136 return std::ranges::all_of(operands, [](const CastExprNode *node) { return node->hasCompileTimeValue(); });
410 }
411
412 91 CompileTimeValue MultiplicativeExprNode::getCompileTimeValue() const {
413
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
414
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 return children.front()->getCompileTimeValue();
415
416 CompileTimeValue result = operands.front()->getCompileTimeValue();
417 OpQueue opQueueCopy = opQueue;
418 for (size_t i = 1; i < operands.size(); i++) {
419 assert(operands.at(i)->hasCompileTimeValue());
420 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
421 const MultiplicativeOp op = opQueueCopy.front().first;
422 opQueueCopy.pop();
423 if (op == OP_MUL) {
424 result.longValue *= opCompileTimeValue.longValue;
425 } else if (op == OP_DIV) {
426 if (opCompileTimeValue.longValue == 0)
427 throw SemanticError(operands.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed.");
428 result.longValue /= opCompileTimeValue.longValue;
429 } else if (op == OP_REM) {
430 result.longValue %= opCompileTimeValue.longValue;
431 } else {
432 throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()");
433 }
434 }
435 return result;
436 }
437
438 7068 bool CastExprNode::hasCompileTimeValue() const { return prefixUnaryExpr->hasCompileTimeValue(); }
439
440 91 CompileTimeValue CastExprNode::getCompileTimeValue() const {
441
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (children.size() == 1)
442 91 return children.front()->getCompileTimeValue();
443 return prefixUnaryExpr->getCompileTimeValue();
444 }
445
446 7317 bool PrefixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
447
2/2
✓ Branch 0 taken 7044 times.
✓ Branch 1 taken 273 times.
7317 if (postfixUnaryExpr)
448 7044 return postfixUnaryExpr->hasCompileTimeValue();
449
450 273 const bool isOperatorSupported =
451
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;
452
3/4
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 249 times.
273 return isOperatorSupported && prefixUnaryExpr->hasCompileTimeValue();
453 }
454
455 91 CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
456
1/2
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
91 if (postfixUnaryExpr)
457
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 return postfixUnaryExpr->getCompileTimeValue();
458
459 CompileTimeValue opValue = prefixUnaryExpr->getCompileTimeValue();
460 if (op == OP_MINUS)
461 return CompileTimeValue{.longValue = -opValue.longValue};
462 if (op == OP_PLUS_PLUS)
463 return CompileTimeValue{.longValue = ++opValue.longValue};
464 if (op == OP_MINUS_MINUS)
465 return CompileTimeValue{.longValue = --opValue.longValue};
466 if (op == OP_NOT)
467 return CompileTimeValue{.boolValue = !opValue.boolValue};
468 if (op == OP_BITWISE_NOT)
469 return CompileTimeValue{.longValue = ~opValue.longValue};
470
471 throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()");
472 }
473
474 7044 bool PostfixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
475
2/2
✓ Branch 0 taken 5524 times.
✓ Branch 1 taken 1520 times.
7044 if (atomicExpr)
476 5524 return atomicExpr->hasCompileTimeValue();
477
478
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;
479
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1520 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1520 return isOperatorSupported && postfixUnaryExpr->hasCompileTimeValue();
480 }
481
482 91 CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
483
1/2
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
91 if (atomicExpr)
484
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 return atomicExpr->getCompileTimeValue();
485
486 CompileTimeValue opValue = postfixUnaryExpr->getCompileTimeValue();
487 if (op == OP_PLUS_PLUS)
488 return CompileTimeValue{.longValue = opValue.longValue++};
489 if (op == OP_MINUS_MINUS)
490 return CompileTimeValue{.longValue = opValue.longValue--};
491
492 throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()");
493 }
494
495 /**
496 * Check if right above the closest assign expression ancestor is a statement node
497 *
498 * @return Has return value receiver or not
499 */
500 6376 bool FctCallNode::hasReturnValueReceiver() const {
501 6376 const ASTNode *node = parent;
502
2/2
✓ Branch 1 taken 94813 times.
✓ Branch 2 taken 5117 times.
99930 while (!node->isAssignExpr()) {
503 // As soon as we have a node with more than one child, we know that the return value is used
504
2/2
✓ Branch 1 taken 1259 times.
✓ Branch 2 taken 93554 times.
94813 if (node->children.size() > 1)
505 1259 return true;
506 93554 node = node->parent;
507 }
508 // Also check the condition of the assign expression
509
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->isExprStmt();
510 }
511
512 9 bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
513 9 return body->returnsOnAllControlPaths(overrideUnreachable);
514 }
515
516 38 bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
517 38 return body->returnsOnAllControlPaths(overrideUnreachable);
518 }
519
520 1348 void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion)
521 // Set the current node to field type
522 1348 isFieldType = true;
523 // Do the same for all template nodes
524 1348 const CustomDataTypeNode *customType = baseDataType->customDataType;
525
4/4
✓ Branch 0 taken 539 times.
✓ Branch 1 taken 809 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 423 times.
1348 if (customType != nullptr && customType->templateTypeLst)
526
2/2
✓ Branch 5 taken 154 times.
✓ Branch 6 taken 116 times.
270 for (DataTypeNode *templateNode : customType->templateTypeLst->dataTypes)
527
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 templateNode->setFieldTypeRecursive();
528 1348 }
529
530 } // namespace spice::compiler
531