| 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 | 914 | std::string ASTNode::getErrorMessage() const { | |
| 16 | 914 | antlr4::CharStream *inputStream = codeLoc.sourceFile->antlrCtx.inputStream.get(); | |
| 17 | 914 | const antlr4::misc::Interval &sourceInterval = codeLoc.sourceInterval; | |
| 18 | 914 | antlr4::misc::Interval extSourceInterval(sourceInterval); | |
| 19 | |||
| 20 | // If we have a multi-line interval, only use the first line | ||
| 21 |
3/4✓ Branch 3 → 4 taken 914 times.
✗ Branch 3 → 77 not taken.
✓ Branch 6 → 7 taken 19 times.
✓ Branch 6 → 8 taken 895 times.
|
914 | 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 | 914 | size_t markerIndentation = 0; | |
| 25 |
2/2✓ Branch 20 → 9 taken 9943 times.
✓ Branch 20 → 21 taken 231 times.
|
10174 | for (; markerIndentation < ERROR_MESSAGE_CONTEXT; markerIndentation++) { |
| 26 | 9943 | extSourceInterval.a--; | |
| 27 |
9/12✓ Branch 9 → 10 taken 9929 times.
✓ Branch 9 → 13 taken 14 times.
✓ Branch 10 → 11 taken 9929 times.
✗ Branch 10 → 78 not taken.
✓ Branch 12 → 13 taken 669 times.
✓ Branch 12 → 14 taken 9260 times.
✓ Branch 15 → 16 taken 9929 times.
✓ Branch 15 → 17 taken 14 times.
✓ Branch 17 → 18 taken 683 times.
✓ Branch 17 → 19 taken 9260 times.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
|
9943 | if (extSourceInterval.a < 0 || inputStream->getText(extSourceInterval).find('\n') != std::string::npos) { |
| 28 | 683 | extSourceInterval.a++; | |
| 29 | 683 | break; | |
| 30 | } | ||
| 31 | } | ||
| 32 |
2/2✓ Branch 34 → 22 taken 2588 times.
✓ Branch 34 → 35 taken 8 times.
|
2596 | for (size_t suffixContext = 0; suffixContext < ERROR_MESSAGE_CONTEXT; suffixContext++) { |
| 33 | 2588 | extSourceInterval.b++; | |
| 34 |
4/6✓ Branch 22 → 23 taken 2588 times.
✗ Branch 22 → 82 not taken.
✓ Branch 23 → 24 taken 2588 times.
✗ Branch 23 → 27 not taken.
✓ Branch 26 → 27 taken 906 times.
✓ Branch 26 → 28 taken 1682 times.
|
5176 | if (static_cast<size_t>(extSourceInterval.b) > inputStream->size() || |
| 35 |
4/8✓ Branch 24 → 25 taken 2588 times.
✗ Branch 24 → 82 not taken.
✓ Branch 29 → 30 taken 2588 times.
✗ Branch 29 → 31 not taken.
✓ Branch 31 → 32 taken 906 times.
✓ Branch 31 → 33 taken 1682 times.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
|
5176 | inputStream->getText(extSourceInterval).find('\n') != std::string::npos) { |
| 36 | 906 | extSourceInterval.b--; | |
| 37 | 906 | break; | |
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | // Trim start | ||
| 42 |
3/4✓ Branch 37 → 38 taken 5262 times.
✗ Branch 37 → 86 not taken.
✓ Branch 40 → 36 taken 4348 times.
✓ Branch 40 → 41 taken 914 times.
|
5262 | while (inputStream->getText(extSourceInterval)[0] == ' ') { |
| 43 | 4348 | extSourceInterval.a++; | |
| 44 | 4348 | markerIndentation--; | |
| 45 | } | ||
| 46 | |||
| 47 | // Trim end | ||
| 48 |
3/4✓ Branch 41 → 42 taken 914 times.
✗ Branch 41 → 87 not taken.
✓ Branch 45 → 46 taken 19 times.
✓ Branch 45 → 47 taken 895 times.
|
914 | if (inputStream->getText(extSourceInterval)[extSourceInterval.length() - 1] == '\n') |
| 49 | 19 | extSourceInterval.b--; | |
| 50 | |||
| 51 | 914 | const std::string lineNumberStr = std::to_string(codeLoc.line); | |
| 52 | 914 | markerIndentation += lineNumberStr.length() + 2; | |
| 53 | |||
| 54 | // Build error message | ||
| 55 |
1/2✓ Branch 49 → 50 taken 914 times.
✗ Branch 49 → 107 not taken.
|
914 | std::stringstream ss; |
| 56 |
5/10✓ Branch 50 → 51 taken 914 times.
✗ Branch 50 → 105 not taken.
✓ Branch 51 → 52 taken 914 times.
✗ Branch 51 → 105 not taken.
✓ Branch 52 → 53 taken 914 times.
✗ Branch 52 → 90 not taken.
✓ Branch 53 → 54 taken 914 times.
✗ Branch 53 → 88 not taken.
✓ Branch 54 → 55 taken 914 times.
✗ Branch 54 → 88 not taken.
|
914 | ss << lineNumberStr << " " << inputStream->getText(extSourceInterval) << "\n"; |
| 57 |
2/4✓ Branch 58 → 59 taken 914 times.
✗ Branch 58 → 93 not taken.
✓ Branch 59 → 60 taken 914 times.
✗ Branch 59 → 91 not taken.
|
1828 | ss << std::string(markerIndentation, ' '); |
| 58 |
2/4✓ Branch 67 → 68 taken 914 times.
✗ Branch 67 → 99 not taken.
✓ Branch 68 → 69 taken 914 times.
✗ Branch 68 → 97 not taken.
|
914 | ss << std::string(std::min(sourceInterval.length(), extSourceInterval.length()), '^'); |
| 59 |
1/2✓ Branch 71 → 72 taken 914 times.
✗ Branch 71 → 105 not taken.
|
1828 | return ss.str(); |
| 60 | 914 | } | |
| 61 | |||
| 62 | 33326 | const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion) | |
| 63 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 33326 times.
|
33326 | assert(parent != nullptr); |
| 64 |
2/2✓ Branch 5 → 6 taken 19779 times.
✓ Branch 5 → 14 taken 13547 times.
|
53105 | return isStmtLst() ? spice_pointer_cast<const StmtLstNode *>(this) : parent->getNextOuterStmtLst(); |
| 65 | } | ||
| 66 | |||
| 67 | 381 | bool MainFctDefNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 68 | 381 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 69 | } | ||
| 70 | |||
| 71 | 11991 | bool FctDefBaseNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 72 | 11991 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 73 | } | ||
| 74 | |||
| 75 | 46 | CompileTimeValue GlobalVarDefNode::getCompileTimeValue() const { return constant->getCompileTimeValue(); } | |
| 76 | |||
| 77 | 1170 | bool ForLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 78 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
| 79 | // we can assume that the loop itself will always return | ||
| 80 |
3/4✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 7 taken 1169 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
|
1170 | const bool loopConditionAlwaysTrue = condAssign->hasCompileTimeValue() && condAssign->getCompileTimeValue().boolValue; |
| 81 |
1/4✗ Branch 8 → 9 not taken.
✓ Branch 8 → 12 taken 1170 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
1170 | return loopConditionAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
| 82 | } | ||
| 83 | |||
| 84 | 759 | bool WhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 85 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
| 86 | // we can assume that the loop itself will always return | ||
| 87 |
3/4✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 7 taken 753 times.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 7 not taken.
|
759 | const bool loopConditionAlwaysTrue = condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue; |
| 88 |
3/4✓ Branch 8 → 9 taken 6 times.
✓ Branch 8 → 12 taken 753 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 6 times.
|
759 | 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 | 3512 | bool IfStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion) | |
| 97 | // If the condition always evaluates to 'true' the then block must return | ||
| 98 |
6/6✓ Branch 3 → 4 taken 13 times.
✓ Branch 3 → 7 taken 3499 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 9 times.
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 11 taken 3508 times.
|
3512 | if (condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue) |
| 99 | 4 | return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 100 | |||
| 101 | // If the condition always evaluates to 'false' the else block must return | ||
| 102 |
5/6✓ Branch 12 → 13 taken 9 times.
✓ Branch 12 → 16 taken 3499 times.
✓ Branch 14 → 15 taken 9 times.
✗ Branch 14 → 16 not taken.
✓ Branch 17 → 18 taken 9 times.
✓ Branch 17 → 24 taken 3499 times.
|
3508 | if (condition->hasCompileTimeValue() && !condition->getCompileTimeValue().boolValue) |
| 103 |
3/4✓ Branch 18 → 19 taken 4 times.
✓ Branch 18 → 22 taken 5 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 4 times.
|
9 | return elseStmt != nullptr && elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
| 104 | |||
| 105 | // If the condition does not always evaluate to 'true' or 'false' we need to check both branches | ||
| 106 |
4/4✓ Branch 25 → 26 taken 2630 times.
✓ Branch 25 → 30 taken 869 times.
✓ Branch 26 → 27 taken 30 times.
✓ Branch 26 → 30 taken 2600 times.
|
3529 | return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable) && elseStmt != nullptr && |
| 107 |
1/2✓ Branch 28 → 29 taken 30 times.
✗ Branch 28 → 30 not taken.
|
3529 | elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
| 108 | } | ||
| 109 | |||
| 110 | 34 | bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion) | |
| 111 |
2/2✓ Branch 2 → 3 taken 11 times.
✓ Branch 2 → 5 taken 23 times.
|
34 | if (isElseIf) |
| 112 | 11 | return ifStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 113 | 23 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 114 | } | ||
| 115 | |||
| 116 | 12 | bool SwitchStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 117 | 42 | const auto pred = [=](const CaseBranchNode *node) { return node->returnsOnAllControlPaths(doSetPredecessorsUnreachable); }; | |
| 118 |
1/2✓ Branch 2 → 3 taken 12 times.
✗ Branch 2 → 15 not taken.
|
12 | const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches, pred); |
| 119 |
4/6✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 6 taken 6 times.
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 15 not taken.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 7 not taken.
|
12 | const bool defaultBranchReturns = !defaultBranch || defaultBranch->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
| 120 |
3/4✓ Branch 8 → 9 taken 9 times.
✓ Branch 8 → 11 taken 3 times.
✓ Branch 9 → 10 taken 9 times.
✗ Branch 9 → 11 not taken.
|
24 | return allCaseBranchesReturn && defaultBranchReturns; |
| 121 | } | ||
| 122 | |||
| 123 | 42 | bool CaseBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 124 | 42 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 125 | } | ||
| 126 | |||
| 127 | 6 | bool DefaultBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 128 | 6 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 129 | } | ||
| 130 | |||
| 131 | 18308 | bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 132 | // An empty statement list does not return at all | ||
| 133 |
2/2✓ Branch 3 → 4 taken 32 times.
✓ Branch 3 → 5 taken 18276 times.
|
18308 | if (statements.empty()) |
| 134 | 32 | return false; | |
| 135 | // A statement list returns on all control paths, if the one direct child statement returns on all control paths | ||
| 136 | 18276 | bool returnsOnAllControlPaths = false; | |
| 137 |
2/2✓ Branch 18 → 7 taken 34756 times.
✓ Branch 18 → 19 taken 18276 times.
|
53032 | for (StmtNode *child : statements) { |
| 138 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 34756 times.
|
34756 | assert(child != nullptr); |
| 139 | |||
| 140 | // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false | ||
| 141 |
4/4✓ Branch 10 → 11 taken 962 times.
✓ Branch 10 → 13 taken 33794 times.
✓ Branch 11 → 12 taken 5 times.
✓ Branch 11 → 13 taken 957 times.
|
34756 | if (returnsOnAllControlPaths && *doSetPredecessorsUnreachable) |
| 142 | 5 | child->unreachable = true; | |
| 143 | |||
| 144 |
3/4✓ Branch 13 → 14 taken 34756 times.
✗ Branch 13 → 21 not taken.
✓ Branch 14 → 15 taken 11316 times.
✓ Branch 14 → 16 taken 23440 times.
|
34756 | if (child->returnsOnAllControlPaths(doSetPredecessorsUnreachable)) |
| 145 | 11316 | returnsOnAllControlPaths = true; | |
| 146 | } | ||
| 147 | 18276 | return returnsOnAllControlPaths; | |
| 148 | } | ||
| 149 | |||
| 150 | 2577 | std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const { | |
| 151 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2577 times.
|
2577 | assert(ATTR_CONFIGS.contains(key)); |
| 152 | |||
| 153 | 2577 | std::vector<const CompileTimeValue *> attributeValues; | |
| 154 |
2/2✓ Branch 19 → 7 taken 3419 times.
✓ Branch 19 → 20 taken 2577 times.
|
5996 | for (const AttrNode *attrNode : attributes) { |
| 155 | // Skip attributes with different keys | ||
| 156 |
2/2✓ Branch 9 → 10 taken 2621 times.
✓ Branch 9 → 11 taken 798 times.
|
3419 | if (attrNode->key != key) |
| 157 | 2621 | continue; | |
| 158 | |||
| 159 | // Found a matching attribute | ||
| 160 | 798 | const CompileTimeValue *value = attrNode->getValue(); | |
| 161 |
2/2✓ Branch 12 → 13 taken 57 times.
✓ Branch 12 → 15 taken 741 times.
|
798 | if (!value) { |
| 162 | // If the attribute has no value, we use the default value | ||
| 163 |
1/2✓ Branch 13 → 14 taken 57 times.
✗ Branch 13 → 22 not taken.
|
57 | attributeValues.push_back(&DEFAULT_BOOL_COMPILE_VALUE); |
| 164 | } else { | ||
| 165 | // If the attribute has a value, we use the value | ||
| 166 |
1/2✓ Branch 15 → 16 taken 741 times.
✗ Branch 15 → 23 not taken.
|
741 | attributeValues.push_back(value); |
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | 2577 | return attributeValues; | |
| 171 | ✗ | } | |
| 172 | |||
| 173 | 1515 | const CompileTimeValue *AttrLstNode::getAttrValueByName(const std::string &key) const { | |
| 174 |
1/2✓ Branch 2 → 3 taken 1515 times.
✗ Branch 2 → 12 not taken.
|
1515 | const std::vector<const CompileTimeValue *> attrs = getAttrValuesByName(key); |
| 175 |
2/2✓ Branch 4 → 5 taken 964 times.
✓ Branch 4 → 6 taken 551 times.
|
3030 | return attrs.empty() ? nullptr : attrs.back(); |
| 176 | 1515 | } | |
| 177 | |||
| 178 | 1380 | bool AttrLstNode::hasAttr(const std::string &key) const { | |
| 179 | 3301 | return std::ranges::any_of(attributes, [&](const AttrNode *attr) { return attr->key == key; }); | |
| 180 | } | ||
| 181 | |||
| 182 |
2/2✓ Branch 2 → 3 taken 741 times.
✓ Branch 2 → 4 taken 57 times.
|
798 | const CompileTimeValue *AttrNode::getValue() const { return value ? &value->compileTimeValue : nullptr; } |
| 183 | |||
| 184 | 721 | bool AssertStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 185 | // If the expression, passed to the assert statement is always evaluated to false, the assert statement will never succeed | ||
| 186 |
4/4✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 7 taken 717 times.
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 1 time.
|
721 | return assignExpr->hasCompileTimeValue() && !assignExpr->getCompileTimeValue().boolValue; |
| 187 | } | ||
| 188 | |||
| 189 | 14165 | bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
| 190 | // If it's a ternary, do the default thing | ||
| 191 |
2/2✓ Branch 2 → 3 taken 8058 times.
✓ Branch 2 → 5 taken 6107 times.
|
14165 | if (op == AssignOp::OP_NONE) |
| 192 | 8058 | return ternaryExpr->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
| 193 | |||
| 194 | // If it's a modification on the result variable, we technically return from the function, but at the end of the function. | ||
| 195 |
2/2✓ Branch 5 → 6 taken 6099 times.
✓ Branch 5 → 7 taken 8 times.
|
6107 | const AtomicExprNode *atomicExpr = lhs->postfixUnaryExpr ? lhs->postfixUnaryExpr->atomicExpr : nullptr; |
| 196 |
6/6✓ Branch 8 → 9 taken 1367 times.
✓ Branch 8 → 12 taken 4740 times.
✓ Branch 10 → 11 taken 682 times.
✓ Branch 10 → 12 taken 685 times.
✓ Branch 13 → 14 taken 682 times.
✓ Branch 13 → 15 taken 5425 times.
|
6107 | 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 | 682 | *doSetPredecessorsUnreachable = false; | |
| 200 | 682 | return true; | |
| 201 | } | ||
| 202 | |||
| 203 | 5425 | return false; | |
| 204 | } | ||
| 205 | |||
| 206 | 10640 | bool TernaryExprNode::hasCompileTimeValue() const { | |
| 207 |
4/4✓ Branch 2 → 3 taken 7 times.
✓ Branch 2 → 5 taken 10633 times.
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 3 times.
|
10640 | const bool trueExprHasCompileTimeValue = !trueExpr || trueExpr->hasCompileTimeValue(); |
| 208 |
4/4✓ Branch 7 → 8 taken 7 times.
✓ Branch 7 → 10 taken 10633 times.
✓ Branch 9 → 10 taken 5 times.
✓ Branch 9 → 11 taken 2 times.
|
10640 | const bool falseExprHasCompileTimeValue = !falseExpr || falseExpr->hasCompileTimeValue(); |
| 209 |
4/6✓ Branch 13 → 14 taken 221 times.
✓ Branch 13 → 17 taken 10419 times.
✓ Branch 14 → 15 taken 221 times.
✗ Branch 14 → 17 not taken.
✓ Branch 15 → 16 taken 221 times.
✗ Branch 15 → 17 not taken.
|
10640 | return condition->hasCompileTimeValue() && trueExprHasCompileTimeValue && falseExprHasCompileTimeValue; |
| 210 | } | ||
| 211 | |||
| 212 | 84 | CompileTimeValue TernaryExprNode::getCompileTimeValue() const { | |
| 213 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 84 times.
|
84 | assert(condition != nullptr); |
| 214 |
2/4✓ Branch 4 → 5 taken 84 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 84 times.
✗ Branch 5 → 7 not taken.
|
84 | if (!trueExpr && !falseExpr) |
| 215 | 84 | return condition->getCompileTimeValue(); | |
| 216 | |||
| 217 | // If the condition has no compile time value, we do not need to evaluate the true and false values | ||
| 218 | ✗ | if (!condition->hasCompileTimeValue()) | |
| 219 | ✗ | return {}; | |
| 220 | |||
| 221 | // Check if the condition always evaluates to 'true' | ||
| 222 | ✗ | if (condition->getCompileTimeValue().boolValue) { | |
| 223 | ✗ | const LogicalOrExprNode *trueValue = isShortened ? condition : trueExpr; | |
| 224 | ✗ | assert(trueValue != nullptr); | |
| 225 | ✗ | return trueValue->getCompileTimeValue(); | |
| 226 | } | ||
| 227 | |||
| 228 | ✗ | assert(falseExpr != nullptr); | |
| 229 | ✗ | return falseExpr->getCompileTimeValue(); | |
| 230 | } | ||
| 231 | |||
| 232 | 11267 | bool LogicalOrExprNode::hasCompileTimeValue() const { | |
| 233 | 22536 | return std::ranges::all_of(operands, [](const LogicalAndExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 234 | } | ||
| 235 | |||
| 236 | 84 | CompileTimeValue LogicalOrExprNode::getCompileTimeValue() const { | |
| 237 |
2/2✓ Branch 3 → 4 taken 82 times.
✓ Branch 3 → 6 taken 2 times.
|
84 | if (operands.size() == 1) |
| 238 | 82 | return operands.front()->getCompileTimeValue(); | |
| 239 | |||
| 240 | // Check if one expression evaluates to 'true' | ||
| 241 |
2/2✓ Branch 17 → 8 taken 4 times.
✓ Branch 17 → 18 taken 2 times.
|
6 | for (const LogicalAndExprNode *op : operands) { |
| 242 |
2/4✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 21 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 4 times.
|
4 | assert(op->hasCompileTimeValue()); |
| 243 | // If one operand evaluates to 'true' the whole expression is 'true' | ||
| 244 |
2/4✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 20 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 4 times.
|
4 | if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); opCompileTimeValue.boolValue) |
| 245 | ✗ | return CompileTimeValue{.boolValue = true}; | |
| 246 | } | ||
| 247 | |||
| 248 | // Return 'false' | ||
| 249 | 2 | return CompileTimeValue{.boolValue = false}; | |
| 250 | } | ||
| 251 | |||
| 252 | 11273 | bool LogicalAndExprNode::hasCompileTimeValue() const { | |
| 253 | 22548 | return std::ranges::all_of(operands, [](const BitwiseOrExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 254 | } | ||
| 255 | |||
| 256 | 86 | CompileTimeValue LogicalAndExprNode::getCompileTimeValue() const { | |
| 257 |
2/2✓ Branch 3 → 4 taken 84 times.
✓ Branch 3 → 6 taken 2 times.
|
86 | if (operands.size() == 1) |
| 258 | 84 | return operands.front()->getCompileTimeValue(); | |
| 259 | |||
| 260 | // Check if all expressions evaluate to 'true' | ||
| 261 |
1/2✓ Branch 17 → 8 taken 4 times.
✗ Branch 17 → 18 not taken.
|
4 | for (const BitwiseOrExprNode *op : operands) { |
| 262 |
2/4✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 21 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 4 times.
|
4 | assert(op->hasCompileTimeValue()); |
| 263 | // If one operand evaluates to 'false' the whole expression is 'false' | ||
| 264 |
3/4✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 20 not taken.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 15 taken 2 times.
|
4 | if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); !opCompileTimeValue.boolValue) |
| 265 | 2 | return CompileTimeValue{.boolValue = false}; | |
| 266 | } | ||
| 267 | |||
| 268 | // Return 'false' | ||
| 269 | ✗ | return CompileTimeValue{.boolValue = false}; | |
| 270 | } | ||
| 271 | |||
| 272 | 11279 | bool BitwiseOrExprNode::hasCompileTimeValue() const { | |
| 273 | 22558 | return std::ranges::all_of(operands, [](const BitwiseXorExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 274 | } | ||
| 275 | |||
| 276 | 88 | CompileTimeValue BitwiseOrExprNode::getCompileTimeValue() const { | |
| 277 |
1/2✓ Branch 3 → 4 taken 88 times.
✗ Branch 3 → 7 not taken.
|
88 | if (operands.size() == 1) |
| 278 |
1/2✓ Branch 5 → 6 taken 88 times.
✗ Branch 5 → 23 not taken.
|
88 | return operands.front()->getCompileTimeValue(); |
| 279 | |||
| 280 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
| 281 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 282 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
| 283 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
| 284 | ✗ | result.longValue |= opCompileTimeValue.longValue; | |
| 285 | } | ||
| 286 | |||
| 287 | ✗ | return result; | |
| 288 | } | ||
| 289 | |||
| 290 | 11279 | bool BitwiseXorExprNode::hasCompileTimeValue() const { | |
| 291 | 22558 | return std::ranges::all_of(operands, [](const BitwiseAndExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 292 | } | ||
| 293 | |||
| 294 | 88 | CompileTimeValue BitwiseXorExprNode::getCompileTimeValue() const { | |
| 295 |
1/2✓ Branch 3 → 4 taken 88 times.
✗ Branch 3 → 7 not taken.
|
88 | if (operands.size() == 1) |
| 296 |
1/2✓ Branch 5 → 6 taken 88 times.
✗ Branch 5 → 23 not taken.
|
88 | return operands.front()->getCompileTimeValue(); |
| 297 | |||
| 298 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
| 299 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 300 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
| 301 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
| 302 | ✗ | result.longValue ^= opCompileTimeValue.longValue; | |
| 303 | } | ||
| 304 | |||
| 305 | ✗ | return result; | |
| 306 | } | ||
| 307 | |||
| 308 | 11279 | bool BitwiseAndExprNode::hasCompileTimeValue() const { | |
| 309 | 22558 | return std::ranges::all_of(operands, [](const EqualityExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 310 | } | ||
| 311 | |||
| 312 | 88 | CompileTimeValue BitwiseAndExprNode::getCompileTimeValue() const { | |
| 313 |
1/2✓ Branch 3 → 4 taken 88 times.
✗ Branch 3 → 7 not taken.
|
88 | if (operands.size() == 1) |
| 314 |
1/2✓ Branch 5 → 6 taken 88 times.
✗ Branch 5 → 23 not taken.
|
88 | return operands.front()->getCompileTimeValue(); |
| 315 | |||
| 316 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
| 317 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 318 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
| 319 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
| 320 | ✗ | result.longValue &= opCompileTimeValue.longValue; | |
| 321 | } | ||
| 322 | |||
| 323 | ✗ | return result; | |
| 324 | } | ||
| 325 | |||
| 326 | 11279 | bool EqualityExprNode::hasCompileTimeValue() const { | |
| 327 | 22568 | return std::ranges::all_of(operands, [](const RelationalExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 328 | } | ||
| 329 | |||
| 330 | 88 | CompileTimeValue EqualityExprNode::getCompileTimeValue() const { | |
| 331 |
2/2✓ Branch 3 → 4 taken 78 times.
✓ Branch 3 → 7 taken 10 times.
|
88 | if (operands.size() == 1) |
| 332 |
1/2✓ Branch 5 → 6 taken 78 times.
✗ Branch 5 → 34 not taken.
|
78 | return operands.front()->getCompileTimeValue(); |
| 333 | |||
| 334 |
2/4✓ Branch 7 → 8 taken 10 times.
✗ Branch 7 → 34 not taken.
✓ Branch 8 → 9 taken 10 times.
✗ Branch 8 → 34 not taken.
|
10 | const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue(); |
| 335 |
2/4✓ Branch 9 → 10 taken 10 times.
✗ Branch 9 → 34 not taken.
✓ Branch 10 → 11 taken 10 times.
✗ Branch 10 → 34 not taken.
|
10 | const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue(); |
| 336 |
2/2✓ Branch 11 → 12 taken 6 times.
✓ Branch 11 → 13 taken 4 times.
|
10 | if (op == EqualityOp::OP_EQUAL) |
| 337 | 6 | return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue}; | |
| 338 |
1/2✓ Branch 13 → 14 taken 4 times.
✗ Branch 13 → 15 not taken.
|
4 | if (op == EqualityOp::OP_NOT_EQUAL) |
| 339 | 4 | return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue}; | |
| 340 | |||
| 341 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()"); | |
| 342 | } | ||
| 343 | |||
| 344 | 11289 | bool RelationalExprNode::hasCompileTimeValue() const { | |
| 345 | 22579 | return std::ranges::all_of(operands, [](const ShiftExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 346 | } | ||
| 347 | |||
| 348 | 98 | CompileTimeValue RelationalExprNode::getCompileTimeValue() const { | |
| 349 |
2/2✓ Branch 3 → 4 taken 97 times.
✓ Branch 3 → 7 taken 1 time.
|
98 | if (operands.size() == 1) |
| 350 |
1/2✓ Branch 5 → 6 taken 97 times.
✗ Branch 5 → 38 not taken.
|
97 | return operands.front()->getCompileTimeValue(); |
| 351 | |||
| 352 |
2/4✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 38 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 38 not taken.
|
1 | const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue(); |
| 353 |
2/4✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 38 not taken.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 38 not taken.
|
1 | const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue(); |
| 354 |
1/2✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
|
1 | if (op == RelationalOp::OP_LESS) |
| 355 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue}; | |
| 356 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 1 time.
|
1 | if (op == RelationalOp::OP_GREATER) |
| 357 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue}; | |
| 358 |
1/2✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
|
1 | if (op == RelationalOp::OP_LESS_EQUAL) |
| 359 | 1 | return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue}; | |
| 360 | ✗ | if (op == RelationalOp::OP_GREATER_EQUAL) | |
| 361 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue}; | |
| 362 | |||
| 363 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()"); | |
| 364 | } | ||
| 365 | |||
| 366 | 11290 | bool ShiftExprNode::hasCompileTimeValue() const { | |
| 367 | 22580 | return std::ranges::all_of(operands, [](const AdditiveExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 368 | } | ||
| 369 | |||
| 370 | 99 | CompileTimeValue ShiftExprNode::getCompileTimeValue() const { | |
| 371 |
1/2✓ Branch 3 → 4 taken 99 times.
✗ Branch 3 → 7 not taken.
|
99 | if (operands.size() == 1) |
| 372 |
1/2✓ Branch 5 → 6 taken 99 times.
✗ Branch 5 → 49 not taken.
|
99 | return operands.front()->getCompileTimeValue(); |
| 373 | |||
| 374 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
| 375 | ✗ | OpQueue opQueueCopy = opQueue; | |
| 376 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 377 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
| 378 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
| 379 | ✗ | const ShiftOp op = opQueueCopy.front().first; | |
| 380 | ✗ | opQueueCopy.pop(); | |
| 381 | ✗ | if (op == ShiftOp::OP_SHIFT_LEFT) | |
| 382 | ✗ | result.longValue <<= opCompileTimeValue.longValue; | |
| 383 | ✗ | else if (op == ShiftOp::OP_SHIFT_RIGHT) | |
| 384 | ✗ | result.longValue >>= opCompileTimeValue.longValue; | |
| 385 | else | ||
| 386 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()"); | |
| 387 | } | ||
| 388 | ✗ | return result; | |
| 389 | ✗ | } | |
| 390 | |||
| 391 | 11290 | bool AdditiveExprNode::hasCompileTimeValue() const { | |
| 392 | 22580 | return std::ranges::all_of(operands, [](const MultiplicativeExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 393 | } | ||
| 394 | |||
| 395 | 99 | CompileTimeValue AdditiveExprNode::getCompileTimeValue() const { | |
| 396 |
1/2✓ Branch 3 → 4 taken 99 times.
✗ Branch 3 → 7 not taken.
|
99 | if (operands.size() == 1) |
| 397 |
1/2✓ Branch 5 → 6 taken 99 times.
✗ Branch 5 → 49 not taken.
|
99 | return operands.front()->getCompileTimeValue(); |
| 398 | |||
| 399 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
| 400 | ✗ | OpQueue opQueueCopy = opQueue; | |
| 401 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 402 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
| 403 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
| 404 | ✗ | const AdditiveOp op = opQueueCopy.front().first; | |
| 405 | ✗ | opQueueCopy.pop(); | |
| 406 | ✗ | if (op == AdditiveOp::OP_PLUS) | |
| 407 | ✗ | result.longValue += opCompileTimeValue.longValue; | |
| 408 | ✗ | else if (op == AdditiveOp::OP_MINUS) | |
| 409 | ✗ | result.longValue -= opCompileTimeValue.longValue; | |
| 410 | else | ||
| 411 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()"); | |
| 412 | } | ||
| 413 | ✗ | return result; | |
| 414 | ✗ | } | |
| 415 | |||
| 416 | 11290 | bool MultiplicativeExprNode::hasCompileTimeValue() const { | |
| 417 | 22580 | return std::ranges::all_of(operands, [](const CastExprNode *node) { return node->hasCompileTimeValue(); }); | |
| 418 | } | ||
| 419 | |||
| 420 | 99 | CompileTimeValue MultiplicativeExprNode::getCompileTimeValue() const { | |
| 421 |
1/2✓ Branch 3 → 4 taken 99 times.
✗ Branch 3 → 7 not taken.
|
99 | if (operands.size() == 1) |
| 422 |
1/2✓ Branch 5 → 6 taken 99 times.
✗ Branch 5 → 70 not taken.
|
99 | return operands.front()->getCompileTimeValue(); |
| 423 | |||
| 424 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
| 425 | ✗ | OpQueue opQueueCopy = opQueue; | |
| 426 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 427 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
| 428 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
| 429 | ✗ | const MultiplicativeOp op = opQueueCopy.front().first; | |
| 430 | ✗ | opQueueCopy.pop(); | |
| 431 | ✗ | if (op == MultiplicativeOp::OP_MUL) { | |
| 432 | ✗ | result.longValue *= opCompileTimeValue.longValue; | |
| 433 | ✗ | } else if (op == MultiplicativeOp::OP_DIV) { | |
| 434 | ✗ | if (opCompileTimeValue.longValue == 0) | |
| 435 | ✗ | throw SemanticError(operands.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed."); | |
| 436 | ✗ | result.longValue /= opCompileTimeValue.longValue; | |
| 437 | ✗ | } else if (op == MultiplicativeOp::OP_REM) { | |
| 438 | ✗ | result.longValue %= opCompileTimeValue.longValue; | |
| 439 | } else { | ||
| 440 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()"); | |
| 441 | } | ||
| 442 | } | ||
| 443 | ✗ | return result; | |
| 444 | ✗ | } | |
| 445 | |||
| 446 | 11290 | bool CastExprNode::hasCompileTimeValue() const { | |
| 447 |
2/2✓ Branch 2 → 3 taken 395 times.
✓ Branch 2 → 5 taken 10895 times.
|
11290 | return isCast ? assignExpr->hasCompileTimeValue() : prefixUnaryExpr->hasCompileTimeValue(); |
| 448 | } | ||
| 449 | |||
| 450 | 99 | CompileTimeValue CastExprNode::getCompileTimeValue() const { | |
| 451 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 99 times.
|
99 | return isCast ? assignExpr->getCompileTimeValue() : prefixUnaryExpr->getCompileTimeValue(); |
| 452 | } | ||
| 453 | |||
| 454 | 11259 | bool PrefixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion) | |
| 455 |
2/2✓ Branch 2 → 3 taken 10873 times.
✓ Branch 2 → 5 taken 386 times.
|
11259 | if (postfixUnaryExpr) |
| 456 | 10873 | return postfixUnaryExpr->hasCompileTimeValue(); | |
| 457 | |||
| 458 |
3/4✓ Branch 6 → 7 taken 378 times.
✓ Branch 6 → 11 taken 8 times.
✓ Branch 7 → 8 taken 378 times.
✗ Branch 7 → 11 not taken.
|
386 | const bool isSupported = op == PrefixUnaryOp::OP_NONE || op == PrefixUnaryOp::OP_MINUS || op == PrefixUnaryOp::OP_PLUS_PLUS || |
| 459 |
4/6✓ Branch 5 → 6 taken 386 times.
✗ Branch 5 → 11 not taken.
✓ Branch 8 → 9 taken 378 times.
✗ Branch 8 → 11 not taken.
✓ Branch 9 → 10 taken 22 times.
✓ Branch 9 → 11 taken 356 times.
|
794 | op == PrefixUnaryOp::OP_MINUS_MINUS || op == PrefixUnaryOp::OP_NOT || |
| 460 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 22 times.
|
22 | op == PrefixUnaryOp::OP_BITWISE_NOT; |
| 461 |
3/4✓ Branch 13 → 14 taken 364 times.
✓ Branch 13 → 17 taken 22 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 364 times.
|
386 | return isSupported && prefixUnaryExpr->hasCompileTimeValue(); |
| 462 | } | ||
| 463 | |||
| 464 | 99 | CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion) | |
| 465 |
1/2✓ Branch 2 → 3 taken 99 times.
✗ Branch 2 → 5 not taken.
|
99 | if (postfixUnaryExpr) |
| 466 |
1/2✓ Branch 3 → 4 taken 99 times.
✗ Branch 3 → 35 not taken.
|
99 | return postfixUnaryExpr->getCompileTimeValue(); |
| 467 | |||
| 468 | ✗ | CompileTimeValue opValue = prefixUnaryExpr->getCompileTimeValue(); | |
| 469 | ✗ | if (op == PrefixUnaryOp::OP_MINUS) | |
| 470 | ✗ | return CompileTimeValue{.longValue = -opValue.longValue}; | |
| 471 | ✗ | if (op == PrefixUnaryOp::OP_PLUS_PLUS) | |
| 472 | ✗ | return CompileTimeValue{.longValue = ++opValue.longValue}; | |
| 473 | ✗ | if (op == PrefixUnaryOp::OP_MINUS_MINUS) | |
| 474 | ✗ | return CompileTimeValue{.longValue = --opValue.longValue}; | |
| 475 | ✗ | if (op == PrefixUnaryOp::OP_NOT) | |
| 476 | ✗ | return CompileTimeValue{.boolValue = !opValue.boolValue}; | |
| 477 | ✗ | if (op == PrefixUnaryOp::OP_BITWISE_NOT) | |
| 478 | ✗ | return CompileTimeValue{.longValue = ~opValue.longValue}; | |
| 479 | |||
| 480 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()"); | |
| 481 | } | ||
| 482 | |||
| 483 | 10873 | bool PostfixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion) | |
| 484 |
2/2✓ Branch 2 → 3 taken 8459 times.
✓ Branch 2 → 5 taken 2414 times.
|
10873 | if (atomicExpr) |
| 485 | 8459 | return atomicExpr->hasCompileTimeValue(); | |
| 486 | |||
| 487 | 2414 | const bool isSupported = | |
| 488 |
3/6✓ Branch 5 → 6 taken 2414 times.
✗ Branch 5 → 8 not taken.
✓ Branch 6 → 7 taken 2414 times.
✗ Branch 6 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 2414 times.
|
2414 | op == PostfixUnaryOp::OP_NONE || op == PostfixUnaryOp::OP_PLUS_PLUS || op == PostfixUnaryOp::OP_MINUS_MINUS; |
| 489 |
1/4✗ Branch 10 → 11 not taken.
✓ Branch 10 → 14 taken 2414 times.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
|
2414 | return isSupported && postfixUnaryExpr->hasCompileTimeValue(); |
| 490 | } | ||
| 491 | |||
| 492 | 99 | CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion) | |
| 493 |
1/2✓ Branch 2 → 3 taken 99 times.
✗ Branch 2 → 5 not taken.
|
99 | if (atomicExpr) |
| 494 |
1/2✓ Branch 3 → 4 taken 99 times.
✗ Branch 3 → 29 not taken.
|
99 | return atomicExpr->getCompileTimeValue(); |
| 495 | |||
| 496 | ✗ | CompileTimeValue opValue = postfixUnaryExpr->getCompileTimeValue(); | |
| 497 | ✗ | if (op == PostfixUnaryOp::OP_PLUS_PLUS) | |
| 498 | ✗ | return CompileTimeValue{.longValue = opValue.longValue++}; | |
| 499 | ✗ | if (op == PostfixUnaryOp::OP_MINUS_MINUS) | |
| 500 | ✗ | return CompileTimeValue{.longValue = opValue.longValue--}; | |
| 501 | |||
| 502 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()"); | |
| 503 | } | ||
| 504 | |||
| 505 | /** | ||
| 506 | * Check if right above the closest assign expression ancestor is a statement node | ||
| 507 | * | ||
| 508 | * @return Has return value receiver or not | ||
| 509 | */ | ||
| 510 | 10241 | bool FctCallNode::hasReturnValueReceiver() const { | |
| 511 | 10241 | const ASTNode *node = parent; | |
| 512 |
2/2✓ Branch 10 → 3 taken 156052 times.
✓ Branch 10 → 11 taken 7810 times.
|
163862 | while (!node->isAssignExpr()) { |
| 513 | // As soon as we have a node with more than one child, we know that the return value is used | ||
| 514 |
3/4✓ Branch 3 → 4 taken 156052 times.
✗ Branch 3 → 23 not taken.
✓ Branch 6 → 7 taken 2431 times.
✓ Branch 6 → 8 taken 153621 times.
|
156052 | if (node->getChildren().size() > 1) |
| 515 | 2431 | return true; | |
| 516 | 153621 | node = node->parent; | |
| 517 | } | ||
| 518 | // Also check the condition of the assign expression | ||
| 519 |
6/12✓ Branch 11 → 12 taken 7810 times.
✗ Branch 11 → 24 not taken.
✓ Branch 13 → 14 taken 7810 times.
✗ Branch 13 → 16 not taken.
✓ Branch 14 → 15 taken 7810 times.
✗ Branch 14 → 24 not taken.
✓ Branch 15 → 16 taken 7578 times.
✓ Branch 15 → 17 taken 232 times.
✓ Branch 19 → 20 taken 7810 times.
✗ Branch 19 → 21 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 26 not taken.
|
7810 | return node->getChildren().size() > 1 || !node->parent->isExprStmt(); |
| 520 | } | ||
| 521 | |||
| 522 | 12 | bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable) const { | |
| 523 | 12 | return body->returnsOnAllControlPaths(overrideUnreachable); | |
| 524 | } | ||
| 525 | |||
| 526 | 38 | bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable) const { | |
| 527 | 38 | return body->returnsOnAllControlPaths(overrideUnreachable); | |
| 528 | } | ||
| 529 | |||
| 530 | 1790 | void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion) | |
| 531 | // Set the current node to field type | ||
| 532 | 1790 | isFieldType = true; | |
| 533 | // Do the same for all template nodes | ||
| 534 |
4/4✓ Branch 2 → 3 taken 819 times.
✓ Branch 2 → 12 taken 971 times.
✓ Branch 3 → 4 taken 185 times.
✓ Branch 3 → 12 taken 634 times.
|
1790 | if (const CustomDataTypeNode *customType = baseDataType->customDataType; customType != nullptr && customType->templateTypeLst) |
| 535 |
2/2✓ Branch 10 → 6 taken 256 times.
✓ Branch 10 → 11 taken 185 times.
|
441 | for (DataTypeNode *templateNode : customType->templateTypeLst->dataTypes) |
| 536 |
1/2✓ Branch 7 → 8 taken 256 times.
✗ Branch 7 → 13 not taken.
|
256 | templateNode->setFieldTypeRecursive(); |
| 537 | 1790 | } | |
| 538 | |||
| 539 | } // namespace spice::compiler | ||
| 540 |