GCC Code Coverage Report


Directory: ../
File: src/ast/ASTNodes.cpp
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 221 318 69.5%
Functions: 64 64 100.0%
Branches: 237 518 45.8%

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 763 std::string ASTNode::getErrorMessage() const {
16 763 antlr4::CharStream *inputStream = codeLoc.sourceFile->antlrCtx.inputStream.get();
17 763 const antlr4::misc::Interval &sourceInterval = codeLoc.sourceInterval;
18 763 antlr4::misc::Interval extSourceInterval(sourceInterval);
19
20 // If we have a multi-line interval, only use the first line
21
3/4
✓ Branch 0 (3→4) taken 763 times.
✗ Branch 1 (3→77) not taken.
✓ Branch 2 (6→7) taken 19 times.
✓ Branch 3 (6→8) taken 744 times.
763 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 763 size_t markerIndentation = 0;
25
2/2
✓ Branch 0 (20→9) taken 8176 times.
✓ Branch 1 (20→21) taken 185 times.
8361 for (; markerIndentation < ERROR_MESSAGE_CONTEXT; markerIndentation++) {
26 8176 extSourceInterval.a--;
27
9/12
✓ Branch 0 (9→10) taken 8161 times.
✓ Branch 1 (9→13) taken 15 times.
✓ Branch 2 (10→11) taken 8161 times.
✗ Branch 3 (10→78) not taken.
✓ Branch 4 (12→13) taken 563 times.
✓ Branch 5 (12→14) taken 7598 times.
✓ Branch 6 (15→16) taken 8161 times.
✓ Branch 7 (15→17) taken 15 times.
✓ Branch 8 (17→18) taken 578 times.
✓ Branch 9 (17→19) taken 7598 times.
✗ Branch 10 (78→79) not taken.
✗ Branch 11 (78→80) not taken.
8176 if (extSourceInterval.a < 0 || inputStream->getText(extSourceInterval).find('\n') != std::string::npos) {
28 578 extSourceInterval.a++;
29 578 break;
30 }
31 }
32
2/2
✓ Branch 0 (34→22) taken 2206 times.
✓ Branch 1 (34→35) taken 8 times.
2214 for (size_t suffixContext = 0; suffixContext < ERROR_MESSAGE_CONTEXT; suffixContext++) {
33 2206 extSourceInterval.b++;
34
4/6
✓ Branch 0 (22→23) taken 2206 times.
✗ Branch 1 (22→82) not taken.
✓ Branch 2 (23→24) taken 2206 times.
✗ Branch 3 (23→27) not taken.
✓ Branch 4 (26→27) taken 755 times.
✓ Branch 5 (26→28) taken 1451 times.
4412 if (static_cast<size_t>(extSourceInterval.b) > inputStream->size() ||
35
4/8
✓ Branch 0 (24→25) taken 2206 times.
✗ Branch 1 (24→82) not taken.
✓ Branch 2 (29→30) taken 2206 times.
✗ Branch 3 (29→31) not taken.
✓ Branch 4 (31→32) taken 755 times.
✓ Branch 5 (31→33) taken 1451 times.
✗ Branch 6 (82→83) not taken.
✗ Branch 7 (82→84) not taken.
4412 inputStream->getText(extSourceInterval).find('\n') != std::string::npos) {
36 755 extSourceInterval.b--;
37 755 break;
38 }
39 }
40
41 // Trim start
42
3/4
✓ Branch 0 (37→38) taken 4335 times.
✗ Branch 1 (37→86) not taken.
✓ Branch 2 (40→36) taken 3572 times.
✓ Branch 3 (40→41) taken 763 times.
4335 while (inputStream->getText(extSourceInterval)[0] == ' ') {
43 3572 extSourceInterval.a++;
44 3572 markerIndentation--;
45 }
46
47 // Trim end
48
3/4
✓ Branch 0 (41→42) taken 763 times.
✗ Branch 1 (41→87) not taken.
✓ Branch 2 (45→46) taken 19 times.
✓ Branch 3 (45→47) taken 744 times.
763 if (inputStream->getText(extSourceInterval)[extSourceInterval.length() - 1] == '\n')
49 19 extSourceInterval.b--;
50
51 763 const std::string lineNumberStr = std::to_string(codeLoc.line);
52 763 markerIndentation += lineNumberStr.length() + 2;
53
54 // Build error message
55
1/2
✓ Branch 0 (49→50) taken 763 times.
✗ Branch 1 (49→107) not taken.
763 std::stringstream ss;
56
5/10
✓ Branch 0 (50→51) taken 763 times.
✗ Branch 1 (50→105) not taken.
✓ Branch 2 (51→52) taken 763 times.
✗ Branch 3 (51→105) not taken.
✓ Branch 4 (52→53) taken 763 times.
✗ Branch 5 (52→90) not taken.
✓ Branch 6 (53→54) taken 763 times.
✗ Branch 7 (53→88) not taken.
✓ Branch 8 (54→55) taken 763 times.
✗ Branch 9 (54→88) not taken.
763 ss << lineNumberStr << " " << inputStream->getText(extSourceInterval) << "\n";
57
2/4
✓ Branch 0 (58→59) taken 763 times.
✗ Branch 1 (58→93) not taken.
✓ Branch 2 (59→60) taken 763 times.
✗ Branch 3 (59→91) not taken.
1526 ss << std::string(markerIndentation, ' ');
58
2/4
✓ Branch 0 (67→68) taken 763 times.
✗ Branch 1 (67→99) not taken.
✓ Branch 2 (68→69) taken 763 times.
✗ Branch 3 (68→97) not taken.
763 ss << std::string(std::min(sourceInterval.length(), extSourceInterval.length()), '^');
59
1/2
✓ Branch 0 (71→72) taken 763 times.
✗ Branch 1 (71→105) not taken.
1526 return ss.str();
60 763 }
61
62 26790 const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion)
63
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 26790 times.
26790 assert(parent != nullptr && "Could not find next outer statement list");
64
2/2
✓ Branch 0 (5→6) taken 16093 times.
✓ Branch 1 (5→14) taken 10697 times.
42883 return isStmtLst() ? spice_pointer_cast<const StmtLstNode *>(this) : parent->getNextOuterStmtLst();
65 }
66
67 354 bool MainFctDefNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
68 354 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
69 }
70
71 8954 bool FctDefBaseNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
72 8954 return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
73 }
74
75 46 CompileTimeValue GlobalVarDefNode::getCompileTimeValue() const { return constant->getCompileTimeValue(); }
76
77 850 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 0 (2→3) taken 850 times.
✗ Branch 1 (2→15) not taken.
✓ Branch 2 (3→4) taken 1 times.
✓ Branch 3 (3→7) taken 849 times.
✓ Branch 4 (4→5) taken 1 times.
✗ Branch 5 (4→15) not taken.
✗ Branch 6 (5→6) not taken.
✓ Branch 7 (5→7) taken 1 times.
850 const bool loopConditionAlwaysTrue = condAssign->hasCompileTimeValue() && condAssign->getCompileTimeValue().boolValue;
81
1/4
✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→12) taken 850 times.
✗ Branch 2 (10→11) not taken.
✗ Branch 3 (10→12) not taken.
850 return loopConditionAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
82 }
83
84 559 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 0 (2→3) taken 559 times.
✗ Branch 1 (2→15) not taken.
✓ Branch 2 (3→4) taken 4 times.
✓ Branch 3 (3→7) taken 555 times.
✓ Branch 4 (4→5) taken 4 times.
✗ Branch 5 (4→15) not taken.
✓ Branch 6 (5→6) taken 3 times.
✓ Branch 7 (5→7) taken 1 times.
559 const bool loopConditionAlwaysTrue = condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue;
88
3/4
✓ Branch 0 (8→9) taken 3 times.
✓ Branch 1 (8→12) taken 556 times.
✗ Branch 2 (10→11) not taken.
✓ Branch 3 (10→12) taken 3 times.
559 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 2796 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 0 (2→3) taken 2796 times.
✗ Branch 1 (2→33) not taken.
✓ Branch 2 (3→4) taken 12 times.
✓ Branch 3 (3→7) taken 2784 times.
✓ Branch 4 (4→5) taken 12 times.
✗ Branch 5 (4→33) not taken.
✓ Branch 6 (5→6) taken 4 times.
✓ Branch 7 (5→7) taken 8 times.
✓ Branch 8 (8→9) taken 4 times.
✓ Branch 9 (8→11) taken 2792 times.
2796 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 0 (11→12) taken 2792 times.
✗ Branch 1 (11→34) not taken.
✓ Branch 2 (12→13) taken 8 times.
✓ Branch 3 (12→16) taken 2784 times.
✓ Branch 4 (13→14) taken 8 times.
✗ Branch 5 (13→34) not taken.
✓ Branch 6 (14→15) taken 8 times.
✗ Branch 7 (14→16) not taken.
✓ Branch 8 (17→18) taken 8 times.
✓ Branch 9 (17→24) taken 2784 times.
2792 if (condition->hasCompileTimeValue() && !condition->getCompileTimeValue().boolValue)
103
3/4
✓ Branch 0 (18→19) taken 2 times.
✓ Branch 1 (18→22) taken 6 times.
✗ Branch 2 (20→21) not taken.
✓ Branch 3 (20→22) 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 0 (25→26) taken 2085 times.
✓ Branch 1 (25→30) taken 699 times.
✓ Branch 2 (26→27) taken 30 times.
✓ Branch 3 (26→30) taken 2055 times.
2814 return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable) && elseStmt != nullptr &&
107
1/2
✓ Branch 0 (28→29) taken 30 times.
✗ Branch 1 (28→30) not taken.
2814 elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
108 }
109
110 32 bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion)
111
2/2
✓ Branch 0 (2→3) taken 10 times.
✓ Branch 1 (2→5) taken 22 times.
32 if (isElseIf)
112 10 return ifStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
113 22 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 0 (2→3) taken 12 times.
✗ Branch 1 (2→15) not taken.
12 const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches, pred);
119
4/6
✓ Branch 0 (3→4) taken 6 times.
✓ Branch 1 (3→6) taken 6 times.
✓ Branch 2 (4→5) taken 6 times.
✗ Branch 3 (4→15) not taken.
✓ Branch 4 (5→6) taken 6 times.
✗ Branch 5 (5→7) not taken.
12 const bool defaultBranchReturns = !defaultBranch || defaultBranch->returnsOnAllControlPaths(doSetPredecessorsUnreachable);
120
3/4
✓ Branch 0 (8→9) taken 9 times.
✓ Branch 1 (8→11) taken 3 times.
✓ Branch 2 (9→10) taken 9 times.
✗ Branch 3 (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 14052 bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
132 // An empty statement list does not return at all
133
2/2
✓ Branch 0 (3→4) taken 29 times.
✓ Branch 1 (3→5) taken 14023 times.
14052 if (statements.empty())
134 29 return false;
135 // A statement list returns on all control paths, if the one direct child statement returns on all control paths
136 14023 bool returnsOnAllControlPaths = false;
137
2/2
✓ Branch 0 (18→7) taken 27202 times.
✓ Branch 1 (18→19) taken 14023 times.
41225 for (StmtNode *child : statements) {
138
1/2
✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→10) taken 27202 times.
27202 assert(child != nullptr);
139
140 // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false
141
4/4
✓ Branch 0 (10→11) taken 621 times.
✓ Branch 1 (10→13) taken 26581 times.
✓ Branch 2 (11→12) taken 7 times.
✓ Branch 3 (11→13) taken 614 times.
27202 if (returnsOnAllControlPaths && *doSetPredecessorsUnreachable)
142 7 child->unreachable = true;
143
144
3/4
✓ Branch 0 (13→14) taken 27202 times.
✗ Branch 1 (13→21) not taken.
✓ Branch 2 (14→15) taken 8650 times.
✓ Branch 3 (14→16) taken 18552 times.
27202 if (child->returnsOnAllControlPaths(doSetPredecessorsUnreachable))
145 8650 returnsOnAllControlPaths = true;
146 }
147 14023 return returnsOnAllControlPaths;
148 }
149
150 2314 std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const {
151
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 2314 times.
2314 assert(ATTR_CONFIGS.contains(key));
152
153 2314 std::vector<const CompileTimeValue *> attributeValues;
154
2/2
✓ Branch 0 (19→7) taken 3648 times.
✓ Branch 1 (19→20) taken 2314 times.
5962 for (const AttrNode *attrNode : attributes) {
155 // Skip attributes with different keys
156
2/2
✓ Branch 0 (9→10) taken 2754 times.
✓ Branch 1 (9→11) taken 894 times.
3648 if (attrNode->key != key)
157 2754 continue;
158
159 // Found a matching attribute
160 894 const CompileTimeValue *value = attrNode->getValue();
161
2/2
✓ Branch 0 (12→13) taken 57 times.
✓ Branch 1 (12→15) taken 837 times.
894 if (!value) {
162 // If the attribute has no value, we use the default value
163
1/2
✓ Branch 0 (13→14) taken 57 times.
✗ Branch 1 (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 0 (15→16) taken 837 times.
✗ Branch 1 (15→23) not taken.
837 attributeValues.push_back(value);
167 }
168 }
169
170 2314 return attributeValues;
171 }
172
173 1435 const CompileTimeValue *AttrLstNode::getAttrValueByName(const std::string &key) const {
174
1/2
✓ Branch 0 (2→3) taken 1435 times.
✗ Branch 1 (2→12) not taken.
1435 const std::vector<const CompileTimeValue *> attrs = getAttrValuesByName(key);
175
2/2
✓ Branch 0 (4→5) taken 970 times.
✓ Branch 1 (4→6) taken 465 times.
2870 return attrs.empty() ? nullptr : attrs.back();
176 1435 }
177
178 1207 bool AttrLstNode::hasAttr(const std::string &key) const {
179 3283 return std::ranges::any_of(attributes, [&](const AttrNode *attr) { return attr->key == key; });
180 }
181
182
2/2
✓ Branch 0 (2→3) taken 837 times.
✓ Branch 1 (2→4) taken 57 times.
894 const CompileTimeValue *AttrNode::getValue() const { return value ? &value->compileTimeValue : nullptr; }
183
184 633 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 0 (2→3) taken 633 times.
✗ Branch 1 (2→11) not taken.
✓ Branch 2 (3→4) taken 4 times.
✓ Branch 3 (3→7) taken 629 times.
✓ Branch 4 (4→5) taken 4 times.
✗ Branch 5 (4→11) not taken.
✓ Branch 6 (5→6) taken 3 times.
✓ Branch 7 (5→7) taken 1 times.
633 return assignExpr->hasCompileTimeValue() && !assignExpr->getCompileTimeValue().boolValue;
187 }
188
189 10912 bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const {
190 // If it's a ternary, do the default thing
191
2/2
✓ Branch 0 (2→3) taken 6245 times.
✓ Branch 1 (2→5) taken 4667 times.
10912 if (op == AssignOp::OP_NONE)
192 6245 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 0 (5→6) taken 4662 times.
✓ Branch 1 (5→7) taken 5 times.
4667 const AtomicExprNode* atomicExpr = lhs->postfixUnaryExpr ? lhs->postfixUnaryExpr->atomicExpr : nullptr;
196
6/6
✓ Branch 0 (8→9) taken 893 times.
✓ Branch 1 (8→12) taken 3774 times.
✓ Branch 2 (10→11) taken 377 times.
✓ Branch 3 (10→12) taken 516 times.
✓ Branch 4 (13→14) taken 377 times.
✓ Branch 5 (13→15) taken 4290 times.
4667 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 377 *doSetPredecessorsUnreachable = false;
200 377 return true;
201 }
202
203 4290 return false;
204 }
205
206 8494 bool TernaryExprNode::hasCompileTimeValue() const {
207
4/4
✓ Branch 0 (2→3) taken 7 times.
✓ Branch 1 (2→5) taken 8487 times.
✓ Branch 2 (4→5) taken 4 times.
✓ Branch 3 (4→6) taken 3 times.
8494 const bool trueExprHasCompileTimeValue = !trueExpr || trueExpr->hasCompileTimeValue();
208
4/4
✓ Branch 0 (7→8) taken 7 times.
✓ Branch 1 (7→10) taken 8487 times.
✓ Branch 2 (9→10) taken 5 times.
✓ Branch 3 (9→11) taken 2 times.
8494 const bool falseExprHasCompileTimeValue = !falseExpr || falseExpr->hasCompileTimeValue();
209
4/6
✓ Branch 0 (13→14) taken 310 times.
✓ Branch 1 (13→17) taken 8184 times.
✓ Branch 2 (14→15) taken 310 times.
✗ Branch 3 (14→17) not taken.
✓ Branch 4 (15→16) taken 310 times.
✗ Branch 5 (15→17) not taken.
8494 return condition->hasCompileTimeValue() && trueExprHasCompileTimeValue && falseExprHasCompileTimeValue;
210 }
211
212 80 CompileTimeValue TernaryExprNode::getCompileTimeValue() const {
213
2/4
✓ Branch 0 (2→3) taken 80 times.
✗ Branch 1 (2→5) not taken.
✓ Branch 2 (3→4) taken 80 times.
✗ Branch 3 (3→5) not taken.
80 if (!trueExpr && !falseExpr)
214 80 return condition->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 }
225 return falseExpr->getCompileTimeValue();
226 }
227
228 8842 bool LogicalOrExprNode::hasCompileTimeValue() const {
229 17686 return std::ranges::all_of(operands, [](const LogicalAndExprNode *node) { return node->hasCompileTimeValue(); });
230 }
231
232 80 CompileTimeValue LogicalOrExprNode::getCompileTimeValue() const {
233
2/2
✓ Branch 0 (3→4) taken 78 times.
✓ Branch 1 (3→6) taken 2 times.
80 if (operands.size() == 1)
234 78 return operands.front()->getCompileTimeValue();
235
236 // Check if one expression evaluates to 'true'
237
2/2
✓ Branch 0 (17→8) taken 4 times.
✓ Branch 1 (17→18) taken 2 times.
6 for (const LogicalAndExprNode *op : operands) {
238
2/4
✓ Branch 0 (9→10) taken 4 times.
✗ Branch 1 (9→21) not taken.
✗ Branch 2 (10→11) not taken.
✓ Branch 3 (10→12) taken 4 times.
4 assert(op->hasCompileTimeValue());
239 // If one operand evaluates to 'true' the whole expression is 'true'
240
2/4
✓ Branch 0 (12→13) taken 4 times.
✗ Branch 1 (12→20) not taken.
✗ Branch 2 (13→14) not taken.
✓ Branch 3 (13→15) taken 4 times.
4 if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); opCompileTimeValue.boolValue)
241 return CompileTimeValue{.boolValue = true};
242 }
243
244 // Return 'false'
245 2 return CompileTimeValue{.boolValue = false};
246 }
247
248 8848 bool LogicalAndExprNode::hasCompileTimeValue() const {
249 17698 return std::ranges::all_of(operands, [](const BitwiseOrExprNode *node) { return node->hasCompileTimeValue(); });
250 }
251
252 82 CompileTimeValue LogicalAndExprNode::getCompileTimeValue() const {
253
2/2
✓ Branch 0 (3→4) taken 80 times.
✓ Branch 1 (3→6) taken 2 times.
82 if (operands.size() == 1)
254 80 return operands.front()->getCompileTimeValue();
255
256 // Check if all expressions evaluate to 'true'
257
1/2
✓ Branch 0 (17→8) taken 4 times.
✗ Branch 1 (17→18) not taken.
4 for (const BitwiseOrExprNode *op : operands) {
258
2/4
✓ Branch 0 (9→10) taken 4 times.
✗ Branch 1 (9→21) not taken.
✗ Branch 2 (10→11) not taken.
✓ Branch 3 (10→12) taken 4 times.
4 assert(op->hasCompileTimeValue());
259 // If one operand evaluates to 'false' the whole expression is 'false'
260
3/4
✓ Branch 0 (12→13) taken 4 times.
✗ Branch 1 (12→20) not taken.
✓ Branch 2 (13→14) taken 2 times.
✓ Branch 3 (13→15) taken 2 times.
4 if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); !opCompileTimeValue.boolValue)
261 2 return CompileTimeValue{.boolValue = false};
262 }
263
264 // Return 'false'
265 return CompileTimeValue{.boolValue = false};
266 }
267
268 8854 bool BitwiseOrExprNode::hasCompileTimeValue() const {
269 17708 return std::ranges::all_of(operands, [](const BitwiseXorExprNode *node) { return node->hasCompileTimeValue(); });
270 }
271
272 84 CompileTimeValue BitwiseOrExprNode::getCompileTimeValue() const {
273
1/2
✓ Branch 0 (3→4) taken 84 times.
✗ Branch 1 (3→7) not taken.
84 if (operands.size() == 1)
274
1/2
✓ Branch 0 (5→6) taken 84 times.
✗ Branch 1 (5→23) not taken.
84 return operands.front()->getCompileTimeValue();
275
276 CompileTimeValue result = operands.front()->getCompileTimeValue();
277 for (size_t i = 1; i < operands.size(); i++) {
278 assert(operands.at(i)->hasCompileTimeValue());
279 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
280 result.longValue |= opCompileTimeValue.longValue;
281 }
282
283 return result;
284 }
285
286 8854 bool BitwiseXorExprNode::hasCompileTimeValue() const {
287 17708 return std::ranges::all_of(operands, [](const BitwiseAndExprNode *node) { return node->hasCompileTimeValue(); });
288 }
289
290 84 CompileTimeValue BitwiseXorExprNode::getCompileTimeValue() const {
291
1/2
✓ Branch 0 (3→4) taken 84 times.
✗ Branch 1 (3→7) not taken.
84 if (operands.size() == 1)
292
1/2
✓ Branch 0 (5→6) taken 84 times.
✗ Branch 1 (5→23) not taken.
84 return operands.front()->getCompileTimeValue();
293
294 CompileTimeValue result = operands.front()->getCompileTimeValue();
295 for (size_t i = 1; i < operands.size(); i++) {
296 assert(operands.at(i)->hasCompileTimeValue());
297 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
298 result.longValue ^= opCompileTimeValue.longValue;
299 }
300
301 return result;
302 }
303
304 8854 bool BitwiseAndExprNode::hasCompileTimeValue() const {
305 17708 return std::ranges::all_of(operands, [](const EqualityExprNode *node) { return node->hasCompileTimeValue(); });
306 }
307
308 84 CompileTimeValue BitwiseAndExprNode::getCompileTimeValue() const {
309
1/2
✓ Branch 0 (3→4) taken 84 times.
✗ Branch 1 (3→7) not taken.
84 if (operands.size() == 1)
310
1/2
✓ Branch 0 (5→6) taken 84 times.
✗ Branch 1 (5→23) not taken.
84 return operands.front()->getCompileTimeValue();
311
312 CompileTimeValue result = operands.front()->getCompileTimeValue();
313 for (size_t i = 1; i < operands.size(); i++) {
314 assert(operands.at(i)->hasCompileTimeValue());
315 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
316 result.longValue &= opCompileTimeValue.longValue;
317 }
318
319 return result;
320 }
321
322 8854 bool EqualityExprNode::hasCompileTimeValue() const {
323 17715 return std::ranges::all_of(operands, [](const RelationalExprNode *node) { return node->hasCompileTimeValue(); });
324 }
325
326 84 CompileTimeValue EqualityExprNode::getCompileTimeValue() const {
327
2/2
✓ Branch 0 (3→4) taken 77 times.
✓ Branch 1 (3→7) taken 7 times.
84 if (operands.size() == 1)
328
1/2
✓ Branch 0 (5→6) taken 77 times.
✗ Branch 1 (5→34) not taken.
77 return operands.front()->getCompileTimeValue();
329
330
2/4
✓ Branch 0 (7→8) taken 7 times.
✗ Branch 1 (7→34) not taken.
✓ Branch 2 (8→9) taken 7 times.
✗ Branch 3 (8→34) not taken.
7 const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue();
331
2/4
✓ Branch 0 (9→10) taken 7 times.
✗ Branch 1 (9→34) not taken.
✓ Branch 2 (10→11) taken 7 times.
✗ Branch 3 (10→34) not taken.
7 const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue();
332
2/2
✓ Branch 0 (11→12) taken 2 times.
✓ Branch 1 (11→13) taken 5 times.
7 if (op == EqualityOp::OP_EQUAL)
333 2 return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue};
334
1/2
✓ Branch 0 (13→14) taken 5 times.
✗ Branch 1 (13→15) not taken.
5 if (op == EqualityOp::OP_NOT_EQUAL)
335 5 return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue};
336
337 throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()");
338 }
339
340 8861 bool RelationalExprNode::hasCompileTimeValue() const {
341 17723 return std::ranges::all_of(operands, [](const ShiftExprNode *node) { return node->hasCompileTimeValue(); });
342 }
343
344 91 CompileTimeValue RelationalExprNode::getCompileTimeValue() const {
345
2/2
✓ Branch 0 (3→4) taken 90 times.
✓ Branch 1 (3→7) taken 1 times.
91 if (operands.size() == 1)
346
1/2
✓ Branch 0 (5→6) taken 90 times.
✗ Branch 1 (5→38) not taken.
90 return operands.front()->getCompileTimeValue();
347
348
2/4
✓ Branch 0 (7→8) taken 1 times.
✗ Branch 1 (7→38) not taken.
✓ Branch 2 (8→9) taken 1 times.
✗ Branch 3 (8→38) not taken.
1 const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue();
349
2/4
✓ Branch 0 (9→10) taken 1 times.
✗ Branch 1 (9→38) not taken.
✓ Branch 2 (10→11) taken 1 times.
✗ Branch 3 (10→38) not taken.
1 const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue();
350
1/2
✗ Branch 0 (11→12) not taken.
✓ Branch 1 (11→13) taken 1 times.
1 if (op == RelationalOp::OP_LESS)
351 return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue};
352
1/2
✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→15) taken 1 times.
1 if (op == RelationalOp::OP_GREATER)
353 return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue};
354
1/2
✓ Branch 0 (15→16) taken 1 times.
✗ Branch 1 (15→17) not taken.
1 if (op == RelationalOp::OP_LESS_EQUAL)
355 1 return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue};
356 if (op == RelationalOp::OP_GREATER_EQUAL)
357 return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue};
358
359 throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()");
360 }
361
362 8862 bool ShiftExprNode::hasCompileTimeValue() const {
363 17724 return std::ranges::all_of(operands, [](const AdditiveExprNode *node) { return node->hasCompileTimeValue(); });
364 }
365
366 92 CompileTimeValue ShiftExprNode::getCompileTimeValue() const {
367
1/2
✓ Branch 0 (3→4) taken 92 times.
✗ Branch 1 (3→7) not taken.
92 if (operands.size() == 1)
368
1/2
✓ Branch 0 (5→6) taken 92 times.
✗ Branch 1 (5→49) not taken.
92 return operands.front()->getCompileTimeValue();
369
370 CompileTimeValue result = operands.front()->getCompileTimeValue();
371 OpQueue opQueueCopy = opQueue;
372 for (size_t i = 1; i < operands.size(); i++) {
373 assert(operands.at(i)->hasCompileTimeValue());
374 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
375 const ShiftOp op = opQueueCopy.front().first;
376 opQueueCopy.pop();
377 if (op == ShiftOp::OP_SHIFT_LEFT)
378 result.longValue <<= opCompileTimeValue.longValue;
379 else if (op == ShiftOp::OP_SHIFT_RIGHT)
380 result.longValue >>= opCompileTimeValue.longValue;
381 else
382 throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()");
383 }
384 return result;
385 }
386
387 8862 bool AdditiveExprNode::hasCompileTimeValue() const {
388 17724 return std::ranges::all_of(operands, [](const MultiplicativeExprNode *node) { return node->hasCompileTimeValue(); });
389 }
390
391 92 CompileTimeValue AdditiveExprNode::getCompileTimeValue() const {
392
1/2
✓ Branch 0 (3→4) taken 92 times.
✗ Branch 1 (3→7) not taken.
92 if (operands.size() == 1)
393
1/2
✓ Branch 0 (5→6) taken 92 times.
✗ Branch 1 (5→49) not taken.
92 return operands.front()->getCompileTimeValue();
394
395 CompileTimeValue result = operands.front()->getCompileTimeValue();
396 OpQueue opQueueCopy = opQueue;
397 for (size_t i = 1; i < operands.size(); i++) {
398 assert(operands.at(i)->hasCompileTimeValue());
399 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
400 const AdditiveOp op = opQueueCopy.front().first;
401 opQueueCopy.pop();
402 if (op == AdditiveOp::OP_PLUS)
403 result.longValue += opCompileTimeValue.longValue;
404 else if (op == AdditiveOp::OP_MINUS)
405 result.longValue -= opCompileTimeValue.longValue;
406 else
407 throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()");
408 }
409 return result;
410 }
411
412 8862 bool MultiplicativeExprNode::hasCompileTimeValue() const {
413 17724 return std::ranges::all_of(operands, [](const CastExprNode *node) { return node->hasCompileTimeValue(); });
414 }
415
416 92 CompileTimeValue MultiplicativeExprNode::getCompileTimeValue() const {
417
1/2
✓ Branch 0 (3→4) taken 92 times.
✗ Branch 1 (3→7) not taken.
92 if (operands.size() == 1)
418
1/2
✓ Branch 0 (5→6) taken 92 times.
✗ Branch 1 (5→70) not taken.
92 return operands.front()->getCompileTimeValue();
419
420 CompileTimeValue result = operands.front()->getCompileTimeValue();
421 OpQueue opQueueCopy = opQueue;
422 for (size_t i = 1; i < operands.size(); i++) {
423 assert(operands.at(i)->hasCompileTimeValue());
424 const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue();
425 const MultiplicativeOp op = opQueueCopy.front().first;
426 opQueueCopy.pop();
427 if (op == MultiplicativeOp::OP_MUL) {
428 result.longValue *= opCompileTimeValue.longValue;
429 } else if (op == MultiplicativeOp::OP_DIV) {
430 if (opCompileTimeValue.longValue == 0)
431 throw SemanticError(operands.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed.");
432 result.longValue /= opCompileTimeValue.longValue;
433 } else if (op == MultiplicativeOp::OP_REM) {
434 result.longValue %= opCompileTimeValue.longValue;
435 } else {
436 throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()");
437 }
438 }
439 return result;
440 }
441
442 8862 bool CastExprNode::hasCompileTimeValue() const { return prefixUnaryExpr->hasCompileTimeValue(); }
443
444 92 CompileTimeValue CastExprNode::getCompileTimeValue() const { return prefixUnaryExpr->getCompileTimeValue(); }
445
446 9134 bool PrefixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
447
2/2
✓ Branch 0 (2→3) taken 8838 times.
✓ Branch 1 (2→5) taken 296 times.
9134 if (postfixUnaryExpr)
448 8838 return postfixUnaryExpr->hasCompileTimeValue();
449
450
3/4
✓ Branch 0 (6→7) taken 288 times.
✓ Branch 1 (6→11) taken 8 times.
✓ Branch 2 (7→8) taken 288 times.
✗ Branch 3 (7→11) not taken.
296 const bool isSupported = op == PrefixUnaryOp::OP_NONE || op == PrefixUnaryOp::OP_MINUS || op == PrefixUnaryOp::OP_PLUS_PLUS ||
451
4/6
✓ Branch 0 (5→6) taken 296 times.
✗ Branch 1 (5→11) not taken.
✓ Branch 2 (8→9) taken 288 times.
✗ Branch 3 (8→11) not taken.
✓ Branch 4 (9→10) taken 24 times.
✓ Branch 5 (9→11) taken 264 times.
616 op == PrefixUnaryOp::OP_MINUS_MINUS || op == PrefixUnaryOp::OP_NOT ||
452
1/2
✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→12) taken 24 times.
24 op == PrefixUnaryOp::OP_BITWISE_NOT;
453
3/4
✓ Branch 0 (13→14) taken 272 times.
✓ Branch 1 (13→17) taken 24 times.
✗ Branch 2 (15→16) not taken.
✓ Branch 3 (15→17) taken 272 times.
296 return isSupported && prefixUnaryExpr->hasCompileTimeValue();
454 }
455
456 92 CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
457
1/2
✓ Branch 0 (2→3) taken 92 times.
✗ Branch 1 (2→5) not taken.
92 if (postfixUnaryExpr)
458
1/2
✓ Branch 0 (3→4) taken 92 times.
✗ Branch 1 (3→35) not taken.
92 return postfixUnaryExpr->getCompileTimeValue();
459
460 CompileTimeValue opValue = prefixUnaryExpr->getCompileTimeValue();
461 if (op == PrefixUnaryOp::OP_MINUS)
462 return CompileTimeValue{.longValue = -opValue.longValue};
463 if (op == PrefixUnaryOp::OP_PLUS_PLUS)
464 return CompileTimeValue{.longValue = ++opValue.longValue};
465 if (op == PrefixUnaryOp::OP_MINUS_MINUS)
466 return CompileTimeValue{.longValue = --opValue.longValue};
467 if (op == PrefixUnaryOp::OP_NOT)
468 return CompileTimeValue{.boolValue = !opValue.boolValue};
469 if (op == PrefixUnaryOp::OP_BITWISE_NOT)
470 return CompileTimeValue{.longValue = ~opValue.longValue};
471
472 throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()");
473 }
474
475 8838 bool PostfixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion)
476
2/2
✓ Branch 0 (2→3) taken 6914 times.
✓ Branch 1 (2→5) taken 1924 times.
8838 if (atomicExpr)
477 6914 return atomicExpr->hasCompileTimeValue();
478
479 1924 const bool isSupported =
480
3/6
✓ Branch 0 (5→6) taken 1924 times.
✗ Branch 1 (5→8) not taken.
✓ Branch 2 (6→7) taken 1924 times.
✗ Branch 3 (6→8) not taken.
✗ Branch 4 (7→8) not taken.
✓ Branch 5 (7→9) taken 1924 times.
1924 op == PostfixUnaryOp::OP_NONE || op == PostfixUnaryOp::OP_PLUS_PLUS || op == PostfixUnaryOp::OP_MINUS_MINUS;
481
1/4
✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→14) taken 1924 times.
✗ Branch 2 (12→13) not taken.
✗ Branch 3 (12→14) not taken.
1924 return isSupported && postfixUnaryExpr->hasCompileTimeValue();
482 }
483
484 92 CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion)
485
1/2
✓ Branch 0 (2→3) taken 92 times.
✗ Branch 1 (2→5) not taken.
92 if (atomicExpr)
486
1/2
✓ Branch 0 (3→4) taken 92 times.
✗ Branch 1 (3→29) not taken.
92 return atomicExpr->getCompileTimeValue();
487
488 CompileTimeValue opValue = postfixUnaryExpr->getCompileTimeValue();
489 if (op == PostfixUnaryOp::OP_PLUS_PLUS)
490 return CompileTimeValue{.longValue = opValue.longValue++};
491 if (op == PostfixUnaryOp::OP_MINUS_MINUS)
492 return CompileTimeValue{.longValue = opValue.longValue--};
493
494 throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()");
495 }
496
497 /**
498 * Check if right above the closest assign expression ancestor is a statement node
499 *
500 * @return Has return value receiver or not
501 */
502 8481 bool FctCallNode::hasReturnValueReceiver() const {
503 8481 const ASTNode *node = parent;
504
2/2
✓ Branch 0 (10→3) taken 126928 times.
✓ Branch 1 (10→11) taken 6231 times.
133159 while (!node->isAssignExpr()) {
505 // As soon as we have a node with more than one child, we know that the return value is used
506
3/4
✓ Branch 0 (3→4) taken 126928 times.
✗ Branch 1 (3→23) not taken.
✓ Branch 2 (6→7) taken 2250 times.
✓ Branch 3 (6→8) taken 124678 times.
126928 if (node->getChildren().size() > 1)
507 2250 return true;
508 124678 node = node->parent;
509 }
510 // Also check the condition of the assign expression
511
6/12
✓ Branch 0 (11→12) taken 6231 times.
✗ Branch 1 (11→24) not taken.
✓ Branch 2 (13→14) taken 6231 times.
✗ Branch 3 (13→16) not taken.
✓ Branch 4 (14→15) taken 6231 times.
✗ Branch 5 (14→24) not taken.
✓ Branch 6 (15→16) taken 6090 times.
✓ Branch 7 (15→17) taken 141 times.
✓ Branch 8 (19→20) taken 6231 times.
✗ Branch 9 (19→21) not taken.
✗ Branch 10 (24→25) not taken.
✗ Branch 11 (24→26) not taken.
6231 return node->getChildren().size() > 1 || !node->parent->isExprStmt();
512 }
513
514 12 bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
515 12 return body->returnsOnAllControlPaths(overrideUnreachable);
516 }
517
518 38 bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable) const {
519 38 return body->returnsOnAllControlPaths(overrideUnreachable);
520 }
521
522 1429 void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion)
523 // Set the current node to field type
524 1429 isFieldType = true;
525 // Do the same for all template nodes
526
4/4
✓ Branch 0 (2→3) taken 591 times.
✓ Branch 1 (2→12) taken 838 times.
✓ Branch 2 (3→4) taken 119 times.
✓ Branch 3 (3→12) taken 472 times.
1429 if (const CustomDataTypeNode *customType = baseDataType->customDataType; customType != nullptr && customType->templateTypeLst)
527
2/2
✓ Branch 0 (10→6) taken 157 times.
✓ Branch 1 (10→11) taken 119 times.
276 for (DataTypeNode *templateNode : customType->templateTypeLst->dataTypes)
528
1/2
✓ Branch 0 (7→8) taken 157 times.
✗ Branch 1 (7→13) not taken.
157 templateNode->setFieldTypeRecursive();
529 1429 }
530
531 } // namespace spice::compiler
532