GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 93.1% 364 / 0 / 391
Functions: 96.4% 27 / 0 / 28
Branches: 50.8% 647 / 0 / 1273

src/typechecker/TypeCheckerBuiltinFunctions.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "TypeChecker.h"
4
5 #include <SourceFile.h>
6 #include <ast/ASTNodes.h>
7 #include <driver/Driver.h>
8 #include <global/GlobalResourceManager.h>
9 #include <global/TypeRegistry.h>
10 #include <symboltablebuilder/QualType.h>
11 #include <symboltablebuilder/Scope.h>
12 #include <symboltablebuilder/SymbolTableBuilder.h>
13 #include <typechecker/Builtins.h>
14 #include <typechecker/FunctionManager.h>
15 #include <typechecker/MacroDefs.h>
16
17 #include <llvm/IR/DataLayout.h>
18 #include <llvm/IR/DerivedTypes.h>
19
20 namespace spice::compiler {
21
22 22753 std::any TypeChecker::visitBuiltinCall(FctCallNode *node) const {
23
2/4
✓ Branch 3 → 4 taken 22753 times.
✗ Branch 3 → 72 not taken.
✓ Branch 4 → 5 taken 22753 times.
✗ Branch 4 → 6 not taken.
22753 assert(BUILTIN_FUNCTIONS_MAP.contains(node->fqFunctionName) && "Builtin function not implemented!");
24
1/2
✓ Branch 8 → 9 taken 22753 times.
✗ Branch 8 → 73 not taken.
22753 const auto &info = BUILTIN_FUNCTIONS_MAP.find(node->fqFunctionName)->second;
25
1/2
✓ Branch 11 → 12 taken 22753 times.
✗ Branch 11 → 75 not taken.
22753 const auto &dispatch = BUILTIN_DISPATCH_MAP.find(node->fqFunctionName)->second;
26
27 52 const auto buildErrorMessage = [](unsigned int min, unsigned int max, unsigned int actual, const char *suffix) {
28 52 std::string expectedStr;
29
2/2
✓ Branch 3 → 4 taken 30 times.
✓ Branch 3 → 15 taken 22 times.
52 if (min == max)
30
5/8
✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 8 taken 22 times.
✓ Branch 7 → 9 taken 8 times.
✗ Branch 7 → 46 not taken.
✓ Branch 11 → 12 taken 8 times.
✓ Branch 11 → 14 taken 22 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 49 not taken.
46 expectedStr = min == 0 ? "no" : std::to_string(min);
31 else
32
5/10
✓ Branch 17 → 18 taken 22 times.
✗ Branch 17 → 60 not taken.
✓ Branch 18 → 19 taken 22 times.
✗ Branch 18 → 58 not taken.
✓ Branch 19 → 20 taken 22 times.
✗ Branch 19 → 56 not taken.
✓ Branch 20 → 21 taken 22 times.
✗ Branch 20 → 54 not taken.
✓ Branch 21 → 22 taken 22 times.
✗ Branch 21 → 52 not taken.
22 expectedStr = "between " + std::to_string(min) + " and " + std::to_string(max) + " " + suffix;
33
5/10
✓ Branch 32 → 33 taken 52 times.
✗ Branch 32 → 79 not taken.
✓ Branch 33 → 34 taken 52 times.
✗ Branch 33 → 77 not taken.
✓ Branch 34 → 35 taken 52 times.
✗ Branch 34 → 75 not taken.
✓ Branch 35 → 36 taken 52 times.
✗ Branch 35 → 73 not taken.
✓ Branch 36 → 37 taken 52 times.
✗ Branch 36 → 71 not taken.
156 return "This builtin expects " + expectedStr + " " + suffix + ", but got " + std::to_string(actual);
34 52 };
35
36 // Do basic checks of template types and args, based on the builtin function info
37
2/2
✓ Branch 13 → 14 taken 8459 times.
✓ Branch 13 → 15 taken 14294 times.
22753 const size_t numTemplateTypes = node->hasTemplateTypes ? node->templateTypeLst->dataTypes.size() : 0;
38
4/4
✓ Branch 16 → 17 taken 22745 times.
✓ Branch 16 → 18 taken 8 times.
✓ Branch 17 → 18 taken 16 times.
✓ Branch 17 → 25 taken 22729 times.
22753 if (numTemplateTypes < info.minTemplateTypes || numTemplateTypes > info.maxTemplateTypes) {
39
1/2
✓ Branch 18 → 19 taken 24 times.
✗ Branch 18 → 80 not taken.
24 const auto msg = buildErrorMessage(info.minTemplateTypes, info.maxTemplateTypes, numTemplateTypes, "template type(s)");
40
3/6
✓ Branch 19 → 20 taken 24 times.
✗ Branch 19 → 78 not taken.
✓ Branch 20 → 21 taken 24 times.
✗ Branch 20 → 77 not taken.
✓ Branch 21 → 22 taken 24 times.
✗ Branch 21 → 77 not taken.
24 SOFT_ERROR_ER(node, BUILTIN_TEMPLATE_TYPE_COUNT_MISMATCH, msg);
41 24 }
42
43
2/2
✓ Branch 25 → 26 taken 14461 times.
✓ Branch 25 → 27 taken 8268 times.
22729 const size_t numArgs = node->hasArgs ? node->argLst->args.size() : 0;
44
4/4
✓ Branch 28 → 29 taken 22721 times.
✓ Branch 28 → 30 taken 8 times.
✓ Branch 29 → 30 taken 20 times.
✓ Branch 29 → 37 taken 22701 times.
22729 if (numArgs < info.minArgTypes || numArgs > info.maxArgTypes) {
45
1/2
✓ Branch 30 → 31 taken 28 times.
✗ Branch 30 → 84 not taken.
28 const auto msg = buildErrorMessage(info.minArgTypes, info.maxArgTypes, numArgs, "argument(s)");
46
3/6
✓ Branch 31 → 32 taken 28 times.
✗ Branch 31 → 82 not taken.
✓ Branch 32 → 33 taken 28 times.
✗ Branch 32 → 81 not taken.
✓ Branch 33 → 34 taken 28 times.
✗ Branch 33 → 81 not taken.
28 SOFT_ERROR_ER(node, BUILTIN_ARG_COUNT_MISMATCH, msg);
47 28 }
48
49
2/2
✓ Branch 37 → 38 taken 4118 times.
✓ Branch 37 → 62 taken 18583 times.
22701 if (info.allTemplateTypesOrAllArgTypes) {
50
4/4
✓ Branch 38 → 39 taken 3973 times.
✓ Branch 38 → 50 taken 145 times.
✓ Branch 39 → 40 taken 8 times.
✓ Branch 39 → 50 taken 3965 times.
4118 if (numTemplateTypes > 0 && numArgs > 0)
51
4/8
✓ Branch 42 → 43 taken 8 times.
✗ Branch 42 → 87 not taken.
✓ Branch 43 → 44 taken 8 times.
✗ Branch 43 → 85 not taken.
✓ Branch 46 → 47 taken 8 times.
✗ Branch 46 → 91 not taken.
✓ Branch 47 → 48 taken 8 times.
✗ Branch 47 → 91 not taken.
32 SOFT_ERROR_ER(node, BUILTIN_SIGNATURE_MISMATCH, "This builtin expects either template types or arguments, but got both");
52
4/4
✓ Branch 50 → 51 taken 145 times.
✓ Branch 50 → 62 taken 3965 times.
✓ Branch 51 → 52 taken 8 times.
✓ Branch 51 → 62 taken 137 times.
4110 if (numTemplateTypes == 0 && numArgs == 0)
53
4/8
✓ Branch 54 → 55 taken 8 times.
✗ Branch 54 → 94 not taken.
✓ Branch 55 → 56 taken 8 times.
✗ Branch 55 → 92 not taken.
✓ Branch 58 → 59 taken 8 times.
✗ Branch 58 → 98 not taken.
✓ Branch 59 → 60 taken 8 times.
✗ Branch 59 → 98 not taken.
32 SOFT_ERROR_ER(node, BUILTIN_SIGNATURE_MISMATCH, "This builtin expects either template types or arguments, but got none");
54 }
55
56 // If specified, call to TypeChecker delegate to execute further checks
57
3/8
✓ Branch 62 → 63 taken 22685 times.
✗ Branch 62 → 67 not taken.
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 65 taken 22685 times.
✓ Branch 66 → 68 taken 22685 times.
✗ Branch 66 → 99 not taken.
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 99 not taken.
45370 return dispatch.typeCheckerVisitMethod != nullptr ? (this->*dispatch.typeCheckerVisitMethod)(node) : nullptr;
58 }
59
60 2846 std::any TypeChecker::visitBuiltinPrintfCall(FctCallNode *node) const {
61
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2846 times.
2846 assert(node->fqFunctionName == BUILTIN_FCT_NAME_PRINTF);
62
63 // Retrieve templated string
64
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2846 times.
2846 assert(node->hasArgs);
65 2846 const ExprNode *firstArg = node->argLst->args.front();
66
5/10
✓ Branch 9 → 10 taken 2846 times.
✗ Branch 9 → 285 not taken.
✓ Branch 10 → 11 taken 2846 times.
✗ Branch 10 → 285 not taken.
✓ Branch 11 → 12 taken 2846 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 2846 times.
✗ Branch 12 → 285 not taken.
✓ Branch 13 → 14 taken 2846 times.
✗ Branch 13 → 15 not taken.
2846 assert(firstArg->getEvaluatedSymbolType(manIdx).is(TY_STRING) && firstArg->hasCompileTimeValue(manIdx));
67
1/2
✓ Branch 16 → 17 taken 2846 times.
✗ Branch 16 → 285 not taken.
2846 const size_t stringOffset = firstArg->getCompileTimeValue(manIdx).stringValueOffset;
68
2/4
✓ Branch 17 → 18 taken 2846 times.
✗ Branch 17 → 285 not taken.
✓ Branch 18 → 19 taken 2846 times.
✗ Branch 18 → 285 not taken.
2846 const std::string templatedString = resourceManager.compileTimeStringValues.at(stringOffset);
69
70 // Check if assignment types match placeholder types
71 2846 size_t placeholderCount = 0;
72 2846 size_t index = templatedString.find_first_of('%');
73
5/6
✓ Branch 188 → 189 taken 2203 times.
✓ Branch 188 → 192 taken 2830 times.
✓ Branch 190 → 191 taken 2203 times.
✗ Branch 190 → 192 not taken.
✓ Branch 193 → 21 taken 2203 times.
✓ Branch 193 → 194 taken 2830 times.
5033 while (index != std::string::npos && index != templatedString.size() - 1) {
74 // Handle escaped percent signs (%%), which do not consume an argument
75
2/4
✓ Branch 21 → 22 taken 2203 times.
✗ Branch 21 → 273 not taken.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 25 taken 2203 times.
2203 if (templatedString.at(index + 1) == '%') {
76 ✗ index = templatedString.find_first_of('%', index + 2);
77 ✗ continue;
78 }
79
80 // Determine the position of the conversion specifier by skipping the optional
81 // flags, field width and precision (e.g. the "04" in "%04d"). These are forwarded
82 // verbatim to the underlying C printf, so we only need to skip over them here.
83 2203 size_t specifierIndex = index + 1;
84
10/10
✓ Branch 2 → 3 taken 2227 times.
✓ Branch 2 → 7 taken 2 times.
✓ Branch 3 → 4 taken 2225 times.
✓ Branch 3 → 7 taken 2 times.
✓ Branch 4 → 5 taken 2223 times.
✓ Branch 4 → 7 taken 2 times.
✓ Branch 5 → 6 taken 2221 times.
✓ Branch 5 → 7 taken 2 times.
✓ Branch 6 → 7 taken 18 times.
✓ Branch 6 → 8 taken 2203 times.
2229 auto isFlag = [](char c) { return c == '-' || c == '+' || c == ' ' || c == '#' || c == '0'; };
85
4/4
✓ Branch 2 → 3 taken 2237 times.
✓ Branch 2 → 5 taken 12 times.
✓ Branch 3 → 4 taken 34 times.
✓ Branch 3 → 5 taken 2203 times.
2249 auto isDigit = [](char c) { return c >= '0' && c <= '9'; };
86
6/8
✓ Branch 28 → 29 taken 2229 times.
✗ Branch 28 → 33 not taken.
✓ Branch 29 → 30 taken 2229 times.
✗ Branch 29 → 273 not taken.
✓ Branch 31 → 32 taken 26 times.
✓ Branch 31 → 33 taken 2203 times.
✓ Branch 34 → 26 taken 26 times.
✓ Branch 34 → 35 taken 2203 times.
2229 while (specifierIndex < templatedString.size() && isFlag(templatedString.at(specifierIndex)))
87 26 specifierIndex++; // Skip flags
88
6/8
✓ Branch 38 → 39 taken 2225 times.
✗ Branch 38 → 43 not taken.
✓ Branch 39 → 40 taken 2225 times.
✗ Branch 39 → 273 not taken.
✓ Branch 41 → 42 taken 22 times.
✓ Branch 41 → 43 taken 2203 times.
✓ Branch 44 → 36 taken 22 times.
✓ Branch 44 → 45 taken 2203 times.
2225 while (specifierIndex < templatedString.size() && isDigit(templatedString.at(specifierIndex)))
89 22 specifierIndex++; // Skip field width
90
6/8
✓ Branch 46 → 47 taken 2203 times.
✗ Branch 46 → 50 not taken.
✓ Branch 47 → 48 taken 2203 times.
✗ Branch 47 → 273 not taken.
✓ Branch 48 → 49 taken 12 times.
✓ Branch 48 → 50 taken 2191 times.
✓ Branch 51 → 52 taken 12 times.
✓ Branch 51 → 62 taken 2191 times.
2203 if (specifierIndex < templatedString.size() && templatedString.at(specifierIndex) == '.') {
91 12 specifierIndex++; // Skip precision dot
92
6/8
✓ Branch 55 → 56 taken 24 times.
✗ Branch 55 → 60 not taken.
✓ Branch 56 → 57 taken 24 times.
✗ Branch 56 → 273 not taken.
✓ Branch 58 → 59 taken 12 times.
✓ Branch 58 → 60 taken 12 times.
✓ Branch 61 → 53 taken 12 times.
✓ Branch 61 → 62 taken 12 times.
24 while (specifierIndex < templatedString.size() && isDigit(templatedString.at(specifierIndex)))
93 12 specifierIndex++; // Skip precision
94 }
95
1/2
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 74 taken 2203 times.
2203 if (specifierIndex >= templatedString.size())
96 ✗ SOFT_ERROR_ER(node, PRINTF_TYPE_ERROR, "The placeholder string contains an invalid placeholder")
97
98 // Check if there is another assignExpr
99
2/2
✓ Branch 75 → 76 taken 2 times.
✓ Branch 75 → 86 taken 2201 times.
2203 if (node->argLst->args.size() - 1 <= placeholderCount)
100
4/8
✓ Branch 78 → 79 taken 2 times.
✗ Branch 78 → 223 not taken.
✓ Branch 79 → 80 taken 2 times.
✗ Branch 79 → 221 not taken.
✓ Branch 82 → 83 taken 2 times.
✗ Branch 82 → 227 not taken.
✓ Branch 83 → 84 taken 2 times.
✗ Branch 83 → 227 not taken.
8 SOFT_ERROR_ER(node, PRINTF_ARG_COUNT_ERROR, "The placeholder string contains more placeholders than arguments")
101
102 // Get next assignment
103
1/2
✓ Branch 86 → 87 taken 2201 times.
✗ Branch 86 → 273 not taken.
2201 const ExprNode *assignment = node->argLst->args.at(placeholderCount + 1);
104 // Visit assignment
105
1/2
✓ Branch 87 → 88 taken 2201 times.
✗ Branch 87 → 273 not taken.
2201 QualType argType = assignment->getEvaluatedSymbolType(manIdx);
106
2/8
✓ Branch 88 → 89 taken 2201 times.
✗ Branch 88 → 273 not taken.
✗ Branch 89 → 90 not taken.
✓ Branch 89 → 94 taken 2201 times.
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 228 not taken.
✗ Branch 91 → 92 not taken.
✗ Branch 91 → 228 not taken.
2201 HANDLE_UNRESOLVED_TYPE_ER(argType)
107
1/2
✓ Branch 94 → 95 taken 2201 times.
✗ Branch 94 → 229 not taken.
2201 argType = argType.removeReferenceWrapper();
108
109
7/8
✓ Branch 95 → 96 taken 2201 times.
✗ Branch 95 → 273 not taken.
✓ Branch 96 → 97 taken 90 times.
✓ Branch 96 → 109 taken 1236 times.
✓ Branch 96 → 121 taken 222 times.
✓ Branch 96 → 133 taken 639 times.
✓ Branch 96 → 154 taken 12 times.
✓ Branch 96 → 173 taken 2 times.
2201 switch (templatedString.at(specifierIndex)) {
110 90 case 'c': {
111
3/4
✓ Branch 97 → 98 taken 90 times.
✗ Branch 97 → 273 not taken.
✓ Branch 98 → 99 taken 2 times.
✓ Branch 98 → 108 taken 88 times.
90 if (!argType.is(TY_CHAR))
112
5/10
✓ Branch 99 → 100 taken 2 times.
✗ Branch 99 → 234 not taken.
✓ Branch 100 → 101 taken 2 times.
✗ Branch 100 → 232 not taken.
✓ Branch 101 → 102 taken 2 times.
✗ Branch 101 → 230 not taken.
✓ Branch 104 → 105 taken 2 times.
✗ Branch 104 → 236 not taken.
✓ Branch 105 → 106 taken 2 times.
✗ Branch 105 → 236 not taken.
4 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR, "The placeholder string expects char, but got " + argType.getName(false))
113 88 placeholderCount++;
114 88 break;
115 }
116 1236 case 'd':
117 case 'i':
118 case 'l':
119 case 'o':
120 case 'u':
121 case 'x':
122 case 'X': {
123
3/4
✓ Branch 109 → 110 taken 1236 times.
✗ Branch 109 → 237 not taken.
✓ Branch 110 → 111 taken 4 times.
✓ Branch 110 → 120 taken 1232 times.
1236 if (!argType.isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_BOOL}))
124
5/10
✓ Branch 111 → 112 taken 4 times.
✗ Branch 111 → 242 not taken.
✓ Branch 112 → 113 taken 4 times.
✗ Branch 112 → 240 not taken.
✓ Branch 113 → 114 taken 4 times.
✗ Branch 113 → 238 not taken.
✓ Branch 116 → 117 taken 4 times.
✗ Branch 116 → 244 not taken.
✓ Branch 117 → 118 taken 4 times.
✗ Branch 117 → 244 not taken.
8 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR,
125 "The placeholder string expects int, short, long, byte or bool, but got " + argType.getName(false))
126 1232 placeholderCount++;
127 1232 break;
128 }
129 222 case 'a':
130 case 'A':
131 case 'f':
132 case 'F':
133 case 'e':
134 case 'E':
135 case 'g':
136 case 'G': {
137
3/4
✓ Branch 121 → 122 taken 222 times.
✗ Branch 121 → 273 not taken.
✓ Branch 122 → 123 taken 2 times.
✓ Branch 122 → 132 taken 220 times.
222 if (!argType.is(TY_DOUBLE))
138
5/10
✓ Branch 123 → 124 taken 2 times.
✗ Branch 123 → 249 not taken.
✓ Branch 124 → 125 taken 2 times.
✗ Branch 124 → 247 not taken.
✓ Branch 125 → 126 taken 2 times.
✗ Branch 125 → 245 not taken.
✓ Branch 128 → 129 taken 2 times.
✗ Branch 128 → 251 not taken.
✓ Branch 129 → 130 taken 2 times.
✗ Branch 129 → 251 not taken.
4 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR, "The placeholder string expects double, but got " + argType.getName(false))
139 220 placeholderCount++;
140 220 break;
141 }
142 639 case 's': {
143
13/18
✓ Branch 133 → 134 taken 639 times.
✗ Branch 133 → 273 not taken.
✓ Branch 134 → 135 taken 228 times.
✓ Branch 134 → 142 taken 411 times.
✓ Branch 135 → 136 taken 228 times.
✗ Branch 135 → 273 not taken.
✓ Branch 136 → 137 taken 4 times.
✓ Branch 136 → 142 taken 224 times.
✓ Branch 137 → 138 taken 4 times.
✗ Branch 137 → 273 not taken.
✓ Branch 138 → 139 taken 2 times.
✓ Branch 138 → 142 taken 2 times.
✓ Branch 139 → 140 taken 2 times.
✗ Branch 139 → 273 not taken.
✓ Branch 140 → 141 taken 2 times.
✗ Branch 140 → 142 not taken.
✓ Branch 143 → 144 taken 2 times.
✓ Branch 143 → 153 taken 637 times.
639 if (!argType.is(TY_STRING) && !argType.isStringObj() && !argType.isPtrTo(TY_CHAR) && !argType.isArrayOf(TY_CHAR))
144
5/10
✓ Branch 144 → 145 taken 2 times.
✗ Branch 144 → 256 not taken.
✓ Branch 145 → 146 taken 2 times.
✗ Branch 145 → 254 not taken.
✓ Branch 146 → 147 taken 2 times.
✗ Branch 146 → 252 not taken.
✓ Branch 149 → 150 taken 2 times.
✗ Branch 149 → 258 not taken.
✓ Branch 150 → 151 taken 2 times.
✗ Branch 150 → 258 not taken.
4 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR,
145 "The placeholder string expects string, String, char* or char[], but got " + argType.getName(false))
146 637 placeholderCount++;
147 637 break;
148 }
149 12 case 'p': {
150
9/14
✓ Branch 154 → 155 taken 12 times.
✗ Branch 154 → 273 not taken.
✓ Branch 155 → 156 taken 2 times.
✓ Branch 155 → 161 taken 10 times.
✓ Branch 156 → 157 taken 2 times.
✗ Branch 156 → 273 not taken.
✓ Branch 157 → 158 taken 2 times.
✗ Branch 157 → 161 not taken.
✓ Branch 158 → 159 taken 2 times.
✗ Branch 158 → 273 not taken.
✓ Branch 159 → 160 taken 2 times.
✗ Branch 159 → 161 not taken.
✓ Branch 162 → 163 taken 2 times.
✓ Branch 162 → 172 taken 10 times.
12 if (!argType.isPtr() && !argType.isArray() && !argType.is(TY_STRING))
151
5/10
✓ Branch 163 → 164 taken 2 times.
✗ Branch 163 → 263 not taken.
✓ Branch 164 → 165 taken 2 times.
✗ Branch 164 → 261 not taken.
✓ Branch 165 → 166 taken 2 times.
✗ Branch 165 → 259 not taken.
✓ Branch 168 → 169 taken 2 times.
✗ Branch 168 → 265 not taken.
✓ Branch 169 → 170 taken 2 times.
✗ Branch 169 → 265 not taken.
4 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR,
152 "The placeholder string expects pointer, array or string, but got " + argType.getName(false))
153 10 placeholderCount++;
154 10 break;
155 }
156 2 default:
157
4/8
✓ Branch 175 → 176 taken 2 times.
✗ Branch 175 → 268 not taken.
✓ Branch 176 → 177 taken 2 times.
✗ Branch 176 → 266 not taken.
✓ Branch 179 → 180 taken 2 times.
✗ Branch 179 → 272 not taken.
✓ Branch 180 → 181 taken 2 times.
✗ Branch 180 → 272 not taken.
8 SOFT_ERROR_ER(node, PRINTF_TYPE_ERROR, "The placeholder string contains an invalid placeholder")
158 }
159 2187 index = templatedString.find_first_of('%', specifierIndex + 1); // We can also skip the conversion specifier
160 }
161
162 // Check if the number of placeholders matches the number of args
163
2/2
✓ Branch 195 → 196 taken 2 times.
✓ Branch 195 → 206 taken 2828 times.
2830 if (placeholderCount < node->argLst->args.size() - 1)
164
4/8
✓ Branch 198 → 199 taken 2 times.
✗ Branch 198 → 276 not taken.
✓ Branch 199 → 200 taken 2 times.
✗ Branch 199 → 274 not taken.
✓ Branch 202 → 203 taken 2 times.
✗ Branch 202 → 280 not taken.
✓ Branch 203 → 204 taken 2 times.
✗ Branch 203 → 280 not taken.
8 SOFT_ERROR_ER(node, PRINTF_ARG_COUNT_ERROR, "The placeholder string contains less placeholders than arguments")
165
166
3/6
✓ Branch 206 → 207 taken 2828 times.
✗ Branch 206 → 281 not taken.
✓ Branch 207 → 208 taken 2828 times.
✗ Branch 207 → 281 not taken.
✓ Branch 208 → 209 taken 2828 times.
✗ Branch 208 → 281 not taken.
5656 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_INT), manIdx)};
167 2846 }
168
169 3856 std::any TypeChecker::visitBuiltinSizeOfCall(FctCallNode *node) const {
170
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3856 times.
3856 assert(node->fqFunctionName == BUILTIN_FCT_NAME_SIZEOF);
171
172 // Directly set compile time value here, so that compile time ifs can be evaluated.
173 3856 QualType qualType;
174
2/2
✓ Branch 6 → 7 taken 3747 times.
✓ Branch 6 → 10 taken 109 times.
3856 if (node->hasTemplateTypes) { // Align of type
175
1/2
✓ Branch 8 → 9 taken 3747 times.
✗ Branch 8 → 54 not taken.
3747 qualType = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
176 } else { // Align of value
177
1/2
✓ Branch 11 → 12 taken 109 times.
✗ Branch 11 → 54 not taken.
109 qualType = node->argLst->args.front()->getEvaluatedSymbolType(manIdx);
178 }
179
180
3/4
✓ Branch 13 → 14 taken 3856 times.
✗ Branch 13 → 40 not taken.
✓ Branch 14 → 15 taken 4 times.
✓ Branch 14 → 25 taken 3852 times.
3856 if (qualType.isOneOf({TY_UNRESOLVED, TY_DYN}))
181
4/8
✓ Branch 17 → 18 taken 4 times.
✗ Branch 17 → 43 not taken.
✓ Branch 18 → 19 taken 4 times.
✗ Branch 18 → 41 not taken.
✓ Branch 21 → 22 taken 4 times.
✗ Branch 21 → 47 not taken.
✓ Branch 22 → 23 taken 4 times.
✗ Branch 22 → 47 not taken.
16 SOFT_ERROR_ER(node, UNEXPECTED_DYN_TYPE, "Cannot use sizeof on a dyn or unresolved type");
182
183
1/2
✓ Branch 25 → 26 taken 3852 times.
✗ Branch 25 → 54 not taken.
3852 llvm::Type *type = qualType.toLLVMType(sourceFile);
184
3/6
✓ Branch 27 → 28 taken 3852 times.
✗ Branch 27 → 50 not taken.
✓ Branch 28 → 29 taken 3852 times.
✗ Branch 28 → 48 not taken.
✓ Branch 29 → 30 taken 3852 times.
✗ Branch 29 → 48 not taken.
3852 const int64_t typeSize = sourceFile->targetMachine->createDataLayout().getTypeAllocSize(type);
185
1/2
✓ Branch 31 → 32 taken 3852 times.
✗ Branch 31 → 54 not taken.
3852 node->data.at(manIdx).setCompileTimeValue({.longValue = typeSize});
186
187
3/6
✓ Branch 33 → 34 taken 3852 times.
✗ Branch 33 → 52 not taken.
✓ Branch 34 → 35 taken 3852 times.
✗ Branch 34 → 52 not taken.
✓ Branch 35 → 36 taken 3852 times.
✗ Branch 35 → 52 not taken.
7704 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
188 }
189
190 26 std::any TypeChecker::visitBuiltinAlignOfCall(FctCallNode *node) const {
191
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 26 times.
26 assert(node->fqFunctionName == BUILTIN_FCT_NAME_ALIGNOF);
192
193 // Directly set compile time value here, so that compile time ifs can be evaluated.
194 26 QualType qualType;
195
2/2
✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 10 taken 22 times.
26 if (node->hasTemplateTypes) { // Align of type
196
1/2
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 54 not taken.
4 qualType = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
197 } else { // Align of value
198
1/2
✓ Branch 11 → 12 taken 22 times.
✗ Branch 11 → 54 not taken.
22 qualType = node->argLst->args.front()->getEvaluatedSymbolType(manIdx);
199 }
200
201
3/4
✓ Branch 13 → 14 taken 26 times.
✗ Branch 13 → 40 not taken.
✓ Branch 14 → 15 taken 4 times.
✓ Branch 14 → 25 taken 22 times.
26 if (qualType.isOneOf({TY_UNRESOLVED, TY_DYN}))
202
4/8
✓ Branch 17 → 18 taken 4 times.
✗ Branch 17 → 43 not taken.
✓ Branch 18 → 19 taken 4 times.
✗ Branch 18 → 41 not taken.
✓ Branch 21 → 22 taken 4 times.
✗ Branch 21 → 47 not taken.
✓ Branch 22 → 23 taken 4 times.
✗ Branch 22 → 47 not taken.
16 SOFT_ERROR_ER(node, UNEXPECTED_DYN_TYPE, "Cannot use alignof on a dyn or unresolved type");
203
204
1/2
✓ Branch 25 → 26 taken 22 times.
✗ Branch 25 → 54 not taken.
22 llvm::Type *type = qualType.toLLVMType(sourceFile);
205
2/4
✓ Branch 27 → 28 taken 22 times.
✗ Branch 27 → 50 not taken.
✓ Branch 28 → 29 taken 22 times.
✗ Branch 28 → 48 not taken.
22 const int64_t typeAlignment = sourceFile->targetMachine->createDataLayout().getABITypeAlign(type).value();
206
1/2
✓ Branch 31 → 32 taken 22 times.
✗ Branch 31 → 54 not taken.
22 node->data.at(manIdx).setCompileTimeValue({.longValue = typeAlignment});
207
208
3/6
✓ Branch 33 → 34 taken 22 times.
✗ Branch 33 → 52 not taken.
✓ Branch 34 → 35 taken 22 times.
✗ Branch 34 → 52 not taken.
✓ Branch 35 → 36 taken 22 times.
✗ Branch 35 → 52 not taken.
44 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
209 }
210
211 20 std::any TypeChecker::visitBuiltinOffsetOfCall(FctCallNode *node) const {
212
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 20 times.
20 assert(node->fqFunctionName == BUILTIN_FCT_NAME_OFFSETOF);
213
2/4
✓ Branch 6 → 7 taken 20 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 20 times.
✗ Branch 8 → 10 not taken.
20 assert(node->hasArgs && node->argLst->args.size() == 2);
214
215 // The first argument denotes the struct to compute the offset within
216
1/2
✓ Branch 11 → 12 taken 20 times.
✗ Branch 11 → 225 not taken.
20 const ExprNode *structArg = node->argLst->args.at(0);
217
3/6
✓ Branch 12 → 13 taken 20 times.
✗ Branch 12 → 170 not taken.
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 170 not taken.
✓ Branch 14 → 15 taken 20 times.
✗ Branch 14 → 170 not taken.
20 const QualType structType = structArg->getEvaluatedSymbolType(manIdx).removeReferenceWrapper().autoDeReference();
218
3/4
✓ Branch 15 → 16 taken 20 times.
✗ Branch 15 → 225 not taken.
✓ Branch 16 → 17 taken 2 times.
✓ Branch 16 → 27 taken 18 times.
20 if (!structType.is(TY_STRUCT))
219
4/8
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 173 not taken.
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 171 not taken.
✓ Branch 23 → 24 taken 2 times.
✗ Branch 23 → 177 not taken.
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 177 not taken.
8 SOFT_ERROR_ER(structArg, EXPECTED_STRUCT_TYPE, "The offsetof builtin expects a struct as its first argument")
220
221 // The second argument must be a (possibly chained) member access, denoting the field to compute the offset of
222
1/2
✓ Branch 27 → 28 taken 18 times.
✗ Branch 27 → 225 not taken.
18 const ExprNode *memberArg = node->argLst->args.at(1);
223 18 const PostfixUnaryExprNode *leafAccess = nullptr;
224
2/2
✓ Branch 43 → 29 taken 18 times.
✓ Branch 43 → 44 taken 2 times.
20 for (const ASTNode *cur = memberArg; cur != nullptr;) {
225
3/4
✓ Branch 29 → 30 taken 18 times.
✗ Branch 29 → 31 not taken.
✓ Branch 32 → 33 taken 16 times.
✓ Branch 32 → 34 taken 2 times.
18 if (const auto *postfix = dynamic_cast<const PostfixUnaryExprNode *>(cur)) {
226 16 leafAccess = postfix;
227 16 break;
228 }
229
1/2
✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 178 not taken.
2 const std::vector<ASTNode *> children = cur->getChildren();
230
1/2
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 39 taken 2 times.
2 cur = children.size() == 1 ? children.front() : nullptr;
231 2 }
232
3/4
✓ Branch 44 → 45 taken 16 times.
✓ Branch 44 → 46 taken 2 times.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 56 taken 16 times.
18 if (leafAccess == nullptr || leafAccess->op != PostfixUnaryExprNode::PostfixUnaryOp::OP_MEMBER_ACCESS)
233
4/8
✓ Branch 48 → 49 taken 2 times.
✗ Branch 48 → 181 not taken.
✓ Branch 49 → 50 taken 2 times.
✗ Branch 49 → 179 not taken.
✓ Branch 52 → 53 taken 2 times.
✗ Branch 52 → 185 not taken.
✓ Branch 53 → 54 taken 2 times.
✗ Branch 53 → 185 not taken.
8 SOFT_ERROR_ER(memberArg, INVALID_MEMBER_ACCESS, "The offsetof builtin expects a struct member access as its second argument")
234
235 // Collect the chain of member accesses (from leaf to base). Only plain member accesses are supported.
236 16 std::vector<const PostfixUnaryExprNode *> accessChain;
237
2/2
✓ Branch 73 → 57 taken 20 times.
✓ Branch 73 → 74 taken 16 times.
36 for (const PostfixUnaryExprNode *access = leafAccess; access != nullptr;) {
238
1/2
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 68 taken 20 times.
20 if (access->op != PostfixUnaryExprNode::PostfixUnaryOp::OP_MEMBER_ACCESS)
239 ✗ SOFT_ERROR_ER(memberArg, INVALID_MEMBER_ACCESS, "The offsetof builtin only supports plain member accesses")
240
1/2
✓ Branch 68 → 69 taken 20 times.
✗ Branch 68 → 193 not taken.
20 accessChain.push_back(access);
241
1/2
✓ Branch 69 → 70 taken 20 times.
✗ Branch 69 → 71 not taken.
20 access = dynamic_cast<const PostfixUnaryExprNode *>(access->postfixUnaryExpr);
242 }
243
244 // Ensure the base of the member access chain is the struct that was passed as first argument
245 16 const QualType chainBaseType =
246
3/6
✓ Branch 75 → 76 taken 16 times.
✗ Branch 75 → 194 not taken.
✓ Branch 76 → 77 taken 16 times.
✗ Branch 76 → 194 not taken.
✓ Branch 77 → 78 taken 16 times.
✗ Branch 77 → 194 not taken.
16 accessChain.back()->postfixUnaryExpr->getEvaluatedSymbolType(manIdx).removeReferenceWrapper().autoDeReference();
247
2/4
✓ Branch 78 → 79 taken 16 times.
✗ Branch 78 → 223 not taken.
✗ Branch 79 → 80 not taken.
✓ Branch 79 → 90 taken 16 times.
16 if (!chainBaseType.matches(structType, false, true, false))
248 ✗ SOFT_ERROR_ER(memberArg, INVALID_MEMBER_ACCESS, "The member access must be rooted in the struct passed as first argument")
249
250 // Accumulate the byte offset by walking each access in the chain through its struct layout
251
1/2
✓ Branch 91 → 92 taken 16 times.
✗ Branch 91 → 223 not taken.
16 const llvm::DataLayout dataLayout = sourceFile->targetMachine->createDataLayout();
252 16 int64_t offset = 0;
253
2/2
✓ Branch 158 → 94 taken 20 times.
✓ Branch 158 → 159 taken 16 times.
52 for (const PostfixUnaryExprNode *access : accessChain) {
254 20 const QualType baseType =
255
3/6
✓ Branch 96 → 97 taken 20 times.
✗ Branch 96 → 202 not taken.
✓ Branch 97 → 98 taken 20 times.
✗ Branch 97 → 202 not taken.
✓ Branch 98 → 99 taken 20 times.
✗ Branch 98 → 202 not taken.
20 access->postfixUnaryExpr->getEvaluatedSymbolType(manIdx).removeReferenceWrapper().autoDeReference();
256
2/4
✓ Branch 99 → 100 taken 20 times.
✗ Branch 99 → 217 not taken.
✗ Branch 100 → 101 not taken.
✓ Branch 100 → 102 taken 20 times.
20 assert(baseType.is(TY_STRUCT));
257
258 // Resolve the struct body scope (substantiate the generic scope if required)
259
1/2
✓ Branch 102 → 103 taken 20 times.
✗ Branch 102 → 217 not taken.
20 Scope *structScope = baseType.getBodyScope();
260
1/2
✗ Branch 103 → 104 not taken.
✓ Branch 103 → 108 taken 20 times.
20 if (structScope->isGenericScope) {
261 ✗ const Struct *spiceStruct = baseType.getStruct(node);
262 ✗ assert(spiceStruct != nullptr);
263 ✗ structScope = spiceStruct->scope;
264 }
265
1/2
✗ Branch 108 → 109 not taken.
✓ Branch 108 → 110 taken 20 times.
20 assert(!structScope->isGenericScope);
266
267 // Look up the accessed field to retrieve its index path within the struct
268 20 std::vector<size_t> indexPath;
269
1/2
✓ Branch 110 → 111 taken 20 times.
✗ Branch 110 → 215 not taken.
20 const SymbolTableEntry *fieldEntry = structScope->symbolTable.lookupInComposedFields(access->identifier, indexPath);
270
1/2
✗ Branch 111 → 112 not taken.
✓ Branch 111 → 124 taken 20 times.
20 if (fieldEntry == nullptr)
271 ✗ SOFT_ERROR_ER(memberArg, REFERENCED_UNDEFINED_FIELD,
272 "Field '" + access->identifier + "' not found in struct " + baseType.getSubType())
273
274 // Walk the index path through the struct layout to accumulate the byte offset of the field
275
1/2
✓ Branch 124 → 125 taken 20 times.
✗ Branch 124 → 215 not taken.
20 llvm::Type *currentType = baseType.toLLVMType(sourceFile);
276
2/2
✓ Branch 143 → 127 taken 20 times.
✓ Branch 143 → 144 taken 20 times.
60 for (const size_t index : indexPath) {
277
1/2
✓ Branch 129 → 130 taken 20 times.
✗ Branch 129 → 214 not taken.
20 auto *structLLVMType = llvm::cast<llvm::StructType>(currentType);
278
3/6
✓ Branch 130 → 131 taken 20 times.
✗ Branch 130 → 213 not taken.
✓ Branch 131 → 132 taken 20 times.
✗ Branch 131 → 213 not taken.
✓ Branch 132 → 133 taken 20 times.
✗ Branch 132 → 213 not taken.
20 offset += static_cast<int64_t>(dataLayout.getStructLayout(structLLVMType)->getElementOffset(index));
279 20 currentType = structLLVMType->getElementType(index);
280 }
281
1/2
✓ Branch 146 → 147 taken 20 times.
✗ Branch 146 → 151 not taken.
20 }
282
1/2
✓ Branch 159 → 160 taken 16 times.
✗ Branch 159 → 221 not taken.
16 node->data.at(manIdx).setCompileTimeValue({.longValue = offset});
283
284
3/6
✓ Branch 161 → 162 taken 16 times.
✗ Branch 161 → 219 not taken.
✓ Branch 162 → 163 taken 16 times.
✗ Branch 162 → 219 not taken.
✓ Branch 163 → 164 taken 16 times.
✗ Branch 163 → 219 not taken.
32 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
285 16 }
286
287 56 std::any TypeChecker::visitBuiltinTypeIdCall(FctCallNode *node) const {
288
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 56 times.
56 assert(node->fqFunctionName == BUILTIN_FCT_NAME_TYPEID);
289
290 // Directly set compile time value here, so that compile time ifs can be evaluated.
291 56 QualType qualType;
292
2/2
✓ Branch 6 → 7 taken 54 times.
✓ Branch 6 → 10 taken 2 times.
56 if (node->hasTemplateTypes) { // typeid of type
293
1/2
✓ Branch 8 → 9 taken 54 times.
✗ Branch 8 → 26 not taken.
54 qualType = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
294 } else { // typeid of value
295
1/2
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 26 not taken.
2 qualType = node->argLst->args.front()->getEvaluatedSymbolType(manIdx);
296 }
297
1/2
✓ Branch 14 → 15 taken 56 times.
✗ Branch 14 → 26 not taken.
56 const uint64_t typeId = TypeRegistry::getTypeHash(*qualType.getType());
298
1/2
✓ Branch 15 → 16 taken 56 times.
✗ Branch 15 → 26 not taken.
56 node->data.at(manIdx).setCompileTimeValue({.longValue = std::bit_cast<int64_t>(typeId)});
299
300
3/6
✓ Branch 18 → 19 taken 56 times.
✗ Branch 18 → 24 not taken.
✓ Branch 19 → 20 taken 56 times.
✗ Branch 19 → 24 not taken.
✓ Branch 20 → 21 taken 56 times.
✗ Branch 20 → 24 not taken.
112 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
301 }
302
303 164 std::any TypeChecker::visitBuiltinTypeNameCall(FctCallNode *node) const {
304
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 164 times.
164 assert(node->fqFunctionName == BUILTIN_FCT_NAME_TYPENAME);
305
306 // Directly set compile time value here, so that compile time ifs can be evaluated.
307 164 QualType qualType;
308
2/2
✓ Branch 6 → 7 taken 160 times.
✓ Branch 6 → 10 taken 4 times.
164 if (node->hasTemplateTypes) { // typename of type
309
1/2
✓ Branch 8 → 9 taken 160 times.
✗ Branch 8 → 30 not taken.
160 qualType = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
310 } else { // typename of value
311
1/2
✓ Branch 11 → 12 taken 4 times.
✗ Branch 11 → 30 not taken.
4 qualType = node->argLst->args.front()->getEvaluatedSymbolType(manIdx);
312 }
313 164 const size_t stringValueOffset = resourceManager.compileTimeStringValues.size();
314
2/4
✓ Branch 14 → 15 taken 164 times.
✗ Branch 14 → 27 not taken.
✓ Branch 15 → 16 taken 164 times.
✗ Branch 15 → 25 not taken.
164 resourceManager.compileTimeStringValues.push_back(qualType.getName());
315
1/2
✓ Branch 17 → 18 taken 164 times.
✗ Branch 17 → 30 not taken.
164 node->data.at(manIdx).setCompileTimeValue({.stringValueOffset = stringValueOffset});
316
317
3/6
✓ Branch 19 → 20 taken 164 times.
✗ Branch 19 → 28 not taken.
✓ Branch 20 → 21 taken 164 times.
✗ Branch 20 → 28 not taken.
✓ Branch 21 → 22 taken 164 times.
✗ Branch 21 → 28 not taken.
328 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_STRING), manIdx)};
318 }
319
320 1144 std::any TypeChecker::visitBuiltinLenCall(FctCallNode *node) const {
321
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1144 times.
1144 assert(node->fqFunctionName == BUILTIN_FCT_NAME_LEN);
322
323 // Directly set compile time value here, so that compile time ifs can be evaluated.
324
1/2
✓ Branch 7 → 8 taken 1144 times.
✗ Branch 7 → 56 not taken.
1144 QualType argType = node->argLst->args.front()->getEvaluatedSymbolType(manIdx);
325
1/2
✓ Branch 8 → 9 taken 1144 times.
✗ Branch 8 → 45 not taken.
1144 argType = argType.removeReferenceWrapper();
326
327 // Check if arg is of type array
328
8/10
✓ Branch 9 → 10 taken 1144 times.
✗ Branch 9 → 56 not taken.
✓ Branch 10 → 11 taken 244 times.
✓ Branch 10 → 14 taken 900 times.
✓ Branch 11 → 12 taken 244 times.
✗ Branch 11 → 56 not taken.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 242 times.
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 27 taken 1142 times.
1144 if (!argType.isArray() && !argType.is(TY_STRING))
329
4/8
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 48 not taken.
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 46 not taken.
✓ Branch 23 → 24 taken 2 times.
✗ Branch 23 → 52 not taken.
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 52 not taken.
8 SOFT_ERROR_ER(node->argLst->args.front(), EXPECTED_ARRAY_TYPE, "The len builtin can only work on arrays or strings")
330
331
3/4
✓ Branch 27 → 28 taken 1142 times.
✗ Branch 27 → 56 not taken.
✓ Branch 28 → 29 taken 900 times.
✓ Branch 28 → 33 taken 242 times.
1142 if (argType.is(TY_ARRAY)) {
332
2/4
✓ Branch 29 → 30 taken 900 times.
✗ Branch 29 → 56 not taken.
✓ Branch 30 → 31 taken 900 times.
✗ Branch 30 → 53 not taken.
900 node->data.at(manIdx).setCompileTimeValue({.longValue = static_cast<int64_t>(argType.getArraySize())});
333 } else {
334 // If we want to use the len builtin on a string, we need to import the string runtime module
335
3/4
✓ Branch 33 → 34 taken 242 times.
✗ Branch 33 → 56 not taken.
✓ Branch 36 → 37 taken 240 times.
✓ Branch 36 → 38 taken 2 times.
484 if (!sourceFile->isStringRT())
336
1/2
✓ Branch 37 → 38 taken 240 times.
✗ Branch 37 → 56 not taken.
240 sourceFile->requestRuntimeModule(STRING_RT);
337 }
338
339
3/6
✓ Branch 38 → 39 taken 1142 times.
✗ Branch 38 → 54 not taken.
✓ Branch 39 → 40 taken 1142 times.
✗ Branch 39 → 54 not taken.
✓ Branch 40 → 41 taken 1142 times.
✗ Branch 40 → 54 not taken.
2284 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
340 }
341
342 7131 std::any TypeChecker::visitBuiltinPanicCall(FctCallNode *node) const {
343
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7131 times.
7131 assert(node->fqFunctionName == BUILTIN_FCT_NAME_PANIC);
344
345
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 7131 times.
7131 assert(node->hasArgs);
346 7131 const ExprNode *assignExpr = node->argLst->args.front();
347
1/2
✓ Branch 9 → 10 taken 7131 times.
✗ Branch 9 → 55 not taken.
7131 QualType argType = assignExpr->getEvaluatedSymbolType(manIdx);
348
2/8
✓ Branch 10 → 11 taken 7131 times.
✗ Branch 10 → 55 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 16 taken 7131 times.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 44 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 44 not taken.
7131 HANDLE_UNRESOLVED_TYPE_ER(argType)
349
1/2
✓ Branch 16 → 17 taken 7131 times.
✗ Branch 16 → 45 not taken.
7131 argType = argType.removeReferenceWrapper();
350
351 // Check if arg is of type array
352
3/4
✓ Branch 17 → 18 taken 7131 times.
✗ Branch 17 → 55 not taken.
✓ Branch 18 → 19 taken 2 times.
✓ Branch 18 → 29 taken 7129 times.
7131 if (!argType.isErrorObj())
353
4/8
✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 48 not taken.
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 46 not taken.
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 52 not taken.
✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 52 not taken.
8 SOFT_ERROR_ER(assignExpr, EXPECTED_ERROR_TYPE, "The panic builtin can only work with errors")
354
355 // The panic prints the stack trace, so the runtime that does that has to be loaded
356
2/8
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 34 taken 7129 times.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 55 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 7129 times.
7129 if (cliOptions.printsStackTraceOnAbort() && !sourceFile->isRT(STACK_TRACE_RT))
357 ✗ sourceFile->requestRuntimeModule(STACK_TRACE_RT);
358
359
3/6
✓ Branch 37 → 38 taken 7129 times.
✗ Branch 37 → 53 not taken.
✓ Branch 38 → 39 taken 7129 times.
✗ Branch 38 → 53 not taken.
✓ Branch 39 → 40 taken 7129 times.
✗ Branch 39 → 53 not taken.
14258 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_DYN), manIdx)};
360 }
361
362 8 std::any TypeChecker::visitBuiltinSyscallCall(FctCallNode *node) const {
363
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 8 times.
8 assert(node->fqFunctionName == BUILTIN_FCT_NAME_SYSCALL);
364
365 // Check if the syscall number if of type short
366 8 const ExprNode *sysCallNumberExpr = node->argLst->args.front();
367
1/2
✓ Branch 7 → 8 taken 8 times.
✗ Branch 7 → 57 not taken.
8 const QualType sysCallNumberType = sysCallNumberExpr->getEvaluatedSymbolType(manIdx);
368
3/4
✓ Branch 8 → 9 taken 8 times.
✗ Branch 8 → 57 not taken.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 20 taken 6 times.
8 if (!sysCallNumberType.is(TY_SHORT))
369
4/8
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 43 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 41 not taken.
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 47 not taken.
✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 47 not taken.
8 SOFT_ERROR_ER(sysCallNumberExpr, INVALID_SYSCALL_NUMBER_TYPE, "Syscall number must be of type short")
370
371 // Check if the syscall number is out of range
372 // According to https://www.chromium.org/chromium-os/developer-library/reference/linux-constants/syscalls/
373
2/4
✓ Branch 20 → 21 taken 6 times.
✗ Branch 20 → 57 not taken.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 34 taken 6 times.
6 if (node->hasCompileTimeValue(manIdx)) {
374 ✗ const unsigned short sysCallNumber = node->getCompileTimeValue(manIdx).shortValue;
375 ✗ if (sysCallNumber < 0 || sysCallNumber > 439)
376 ✗ SOFT_ERROR_ER(node, SYSCALL_NUMBER_OUT_OF_RANGE, "Only syscall numbers between 0 and 439 are supported")
377 }
378
379
3/6
✓ Branch 34 → 35 taken 6 times.
✗ Branch 34 → 55 not taken.
✓ Branch 35 → 36 taken 6 times.
✗ Branch 35 → 55 not taken.
✓ Branch 36 → 37 taken 6 times.
✗ Branch 36 → 55 not taken.
12 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
380 }
381
382 12 std::any TypeChecker::visitBuiltinIsSameCall(FctCallNode *node) const {
383
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 12 times.
12 assert(node->fqFunctionName == BUILTIN_FCT_NAME_IS_SAME);
384
385 // Directly set compile time value here, so that compile time ifs can be evaluated.
386
1/2
✓ Branch 6 → 7 taken 12 times.
✗ Branch 6 → 26 not taken.
12 node->setCompileTimeValue({.boolValue = true}, manIdx);
387 12 const std::vector<DataTypeNode *> &dataTypeNodes = node->templateTypeLst->dataTypes;
388
1/2
✓ Branch 8 → 9 taken 12 times.
✗ Branch 8 → 31 not taken.
12 const QualType firstType = dataTypeNodes.front()->getEvaluatedSymbolType(manIdx);
389
2/2
✓ Branch 19 → 10 taken 12 times.
✓ Branch 19 → 20 taken 4 times.
16 for (size_t i = 1; i < dataTypeNodes.size(); i++) {
390
2/4
✓ Branch 10 → 11 taken 12 times.
✗ Branch 10 → 28 not taken.
✓ Branch 11 → 12 taken 12 times.
✗ Branch 11 → 28 not taken.
12 const QualType qualType = dataTypeNodes.at(i)->getEvaluatedSymbolType(manIdx);
391
3/4
✓ Branch 12 → 13 taken 12 times.
✗ Branch 12 → 28 not taken.
✓ Branch 13 → 14 taken 8 times.
✓ Branch 13 → 16 taken 4 times.
12 if (!qualType.matches(firstType, false, true, false)) {
392
1/2
✓ Branch 14 → 15 taken 8 times.
✗ Branch 14 → 27 not taken.
8 node->setCompileTimeValue({.boolValue = false}, manIdx);
393 8 break;
394 }
395 }
396
397
3/6
✓ Branch 20 → 21 taken 12 times.
✗ Branch 20 → 29 not taken.
✓ Branch 21 → 22 taken 12 times.
✗ Branch 21 → 29 not taken.
✓ Branch 22 → 23 taken 12 times.
✗ Branch 22 → 29 not taken.
24 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BOOL), manIdx)};
398 }
399
400 2 std::any TypeChecker::visitBuiltinImplementsInterfaceCall(FctCallNode *node) const {
401
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
2 assert(node->fqFunctionName == BUILTIN_FCT_NAME_IMPLEMENTS_INTERFACE);
402
403
1/2
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 28 not taken.
2 const QualType interfaceType = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
404
1/2
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 28 not taken.
2 const QualType structType = node->templateTypeLst->dataTypes.back()->getEvaluatedSymbolType(manIdx);
405
6/12
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 28 not taken.
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 17 not taken.
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 28 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 17 not taken.
✓ Branch 14 → 15 taken 2 times.
✗ Branch 14 → 28 not taken.
✓ Branch 15 → 16 taken 2 times.
✗ Branch 15 → 17 not taken.
2 const bool value = interfaceType.is(TY_INTERFACE) && structType.is(TY_STRUCT) && structType.doesImplement(interfaceType, node);
406
1/2
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 25 not taken.
2 node->setCompileTimeValue({.boolValue = value}, manIdx);
407
408
3/6
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 26 not taken.
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 26 not taken.
✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 26 not taken.
4 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BOOL), manIdx)};
409 }
410
411 148 std::any TypeChecker::visitBuiltinGetBuildVarCall(FctCallNode *node) const {
412
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 148 times.
148 assert(node->fqFunctionName == BUILTIN_FCT_NAME_GET_BUILD_VAR);
413
414 148 const DataTypeNode *requestedTypeNode = node->templateTypeLst->dataTypes.front();
415
1/2
✓ Branch 7 → 8 taken 148 times.
✗ Branch 7 → 210 not taken.
148 const QualType requestedType = requestedTypeNode->getEvaluatedSymbolType(manIdx);
416
3/4
✓ Branch 8 → 9 taken 148 times.
✗ Branch 8 → 120 not taken.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 20 taken 146 times.
148 if (!requestedType.isOneOf({TY_STRING, TY_INT, TY_BOOL}))
417
4/8
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 123 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 121 not taken.
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 127 not taken.
✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 127 not taken.
8 SOFT_ERROR_ER(requestedTypeNode, BUILTIN_SIGNATURE_MISMATCH, "Build var type must be string, int or bool")
418
419
1/2
✓ Branch 20 → 21 taken 146 times.
✗ Branch 20 → 210 not taken.
146 const ExprNode *varNameNode = node->argLst->args.at(0);
420
1/2
✓ Branch 21 → 22 taken 146 times.
✗ Branch 21 → 210 not taken.
146 const QualType varNameType = varNameNode->getEvaluatedSymbolType(manIdx);
421
3/4
✓ Branch 22 → 23 taken 146 times.
✗ Branch 22 → 210 not taken.
✓ Branch 23 → 24 taken 2 times.
✓ Branch 23 → 34 taken 144 times.
146 if (!varNameType.is(TY_STRING))
422
4/8
✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 130 not taken.
✓ Branch 27 → 28 taken 2 times.
✗ Branch 27 → 128 not taken.
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 134 not taken.
✓ Branch 31 → 32 taken 2 times.
✗ Branch 31 → 134 not taken.
8 SOFT_ERROR_ER(varNameNode, BUILTIN_ARG_TYPE_MISMATCH, "Build var name must be a string")
423
3/4
✓ Branch 34 → 35 taken 144 times.
✗ Branch 34 → 210 not taken.
✓ Branch 35 → 36 taken 2 times.
✓ Branch 35 → 46 taken 142 times.
144 if (!varNameNode->hasCompileTimeValue(manIdx))
424
4/8
✓ Branch 38 → 39 taken 2 times.
✗ Branch 38 → 137 not taken.
✓ Branch 39 → 40 taken 2 times.
✗ Branch 39 → 135 not taken.
✓ Branch 42 → 43 taken 2 times.
✗ Branch 42 → 141 not taken.
✓ Branch 43 → 44 taken 2 times.
✗ Branch 43 → 141 not taken.
8 SOFT_ERROR_ER(varNameNode, EXPECTED_COMPILE_TIME_VALUE, "Var name must be known at compile time")
425
426 142 const bool hasDefaultValue = node->argLst->args.size() == 2;
427 142 CompileTimeValue defaultValue;
428
2/2
✓ Branch 47 → 48 taken 100 times.
✓ Branch 47 → 77 taken 42 times.
142 if (hasDefaultValue) {
429
1/2
✓ Branch 48 → 49 taken 100 times.
✗ Branch 48 → 156 not taken.
100 const ExprNode *defaultValueNode = node->argLst->args.at(1);
430
1/2
✓ Branch 49 → 50 taken 100 times.
✗ Branch 49 → 156 not taken.
100 const QualType defaultValueType = defaultValueNode->getEvaluatedSymbolType(manIdx);
431
3/4
✓ Branch 50 → 51 taken 100 times.
✗ Branch 50 → 156 not taken.
✓ Branch 51 → 52 taken 2 times.
✓ Branch 51 → 62 taken 98 times.
100 if (!defaultValueType.matches(requestedType, false, true, true))
432
4/8
✓ Branch 54 → 55 taken 2 times.
✗ Branch 54 → 144 not taken.
✓ Branch 55 → 56 taken 2 times.
✗ Branch 55 → 142 not taken.
✓ Branch 58 → 59 taken 2 times.
✗ Branch 58 → 148 not taken.
✓ Branch 59 → 60 taken 2 times.
✗ Branch 59 → 148 not taken.
8 SOFT_ERROR_ER(defaultValueNode, BUILTIN_ARG_TYPE_MISMATCH, "Default value type must be the same as the requested type")
433
3/4
✓ Branch 62 → 63 taken 98 times.
✗ Branch 62 → 156 not taken.
✓ Branch 63 → 64 taken 2 times.
✓ Branch 63 → 74 taken 96 times.
98 if (!defaultValueNode->hasCompileTimeValue(manIdx))
434
4/8
✓ Branch 66 → 67 taken 2 times.
✗ Branch 66 → 151 not taken.
✓ Branch 67 → 68 taken 2 times.
✗ Branch 67 → 149 not taken.
✓ Branch 70 → 71 taken 2 times.
✗ Branch 70 → 155 not taken.
✓ Branch 71 → 72 taken 2 times.
✗ Branch 71 → 155 not taken.
8 SOFT_ERROR_ER(defaultValueNode, EXPECTED_COMPILE_TIME_VALUE, "Default value must be known at compile time")
435
1/2
✓ Branch 74 → 75 taken 96 times.
✗ Branch 74 → 156 not taken.
96 defaultValue = defaultValueNode->getCompileTimeValue(manIdx);
436 }
437
438
1/2
✓ Branch 77 → 78 taken 138 times.
✗ Branch 77 → 210 not taken.
138 const size_t stringValueOffset = varNameNode->getCompileTimeValue(manIdx).stringValueOffset;
439
1/2
✓ Branch 78 → 79 taken 138 times.
✗ Branch 78 → 210 not taken.
138 const std::string &varName = resourceManager.compileTimeStringValues.at(stringValueOffset);
440
1/2
✓ Branch 79 → 80 taken 138 times.
✗ Branch 79 → 210 not taken.
138 const auto it = cliOptions.buildVars.find(varName);
441
2/2
✓ Branch 82 → 83 taken 54 times.
✓ Branch 82 → 102 taken 84 times.
138 if (it != cliOptions.buildVars.end()) {
442 try {
443
3/4
✓ Branch 83 → 84 taken 54 times.
✗ Branch 83 → 160 not taken.
✓ Branch 84 → 85 taken 16 times.
✓ Branch 84 → 90 taken 38 times.
54 if (requestedType.is(TY_STRING)) {
444 16 const size_t value = resourceManager.compileTimeStringValues.size();
445
1/2
✓ Branch 87 → 88 taken 16 times.
✗ Branch 87 → 160 not taken.
16 resourceManager.compileTimeStringValues.push_back(it->second);
446
1/2
✓ Branch 88 → 89 taken 16 times.
✗ Branch 88 → 157 not taken.
16 node->setCompileTimeValue({.stringValueOffset = value}, manIdx);
447
3/4
✓ Branch 90 → 91 taken 38 times.
✗ Branch 90 → 160 not taken.
✓ Branch 91 → 92 taken 6 times.
✓ Branch 91 → 96 taken 32 times.
38 } else if (requestedType.is(TY_INT)) {
448
2/2
✓ Branch 93 → 94 taken 2 times.
✓ Branch 93 → 160 taken 4 times.
6 const int value = std::stoi(it->second);
449
1/2
✓ Branch 94 → 95 taken 2 times.
✗ Branch 94 → 158 not taken.
2 node->setCompileTimeValue({.intValue = value}, manIdx);
450
2/4
✓ Branch 96 → 97 taken 32 times.
✗ Branch 96 → 160 not taken.
✓ Branch 97 → 98 taken 32 times.
✗ Branch 97 → 114 not taken.
32 } else if (requestedType.is(TY_BOOL)) {
451
1/2
✓ Branch 99 → 100 taken 32 times.
✗ Branch 99 → 160 not taken.
32 const bool value = it->second == "true";
452
1/2
✓ Branch 100 → 101 taken 32 times.
✗ Branch 100 → 159 not taken.
32 node->setCompileTimeValue({.boolValue = value}, manIdx);
453 }
454
1/3
✗ Branch 160 → 161 not taken.
✓ Branch 160 → 162 taken 4 times.
✗ Branch 160 → 173 not taken.
4 } catch (const std::invalid_argument &) {
455
4/8
✓ Branch 165 → 166 taken 4 times.
✗ Branch 165 → 186 not taken.
✓ Branch 166 → 167 taken 4 times.
✗ Branch 166 → 184 not taken.
✓ Branch 169 → 170 taken 4 times.
✗ Branch 169 → 190 not taken.
✓ Branch 170 → 171 taken 4 times.
✗ Branch 170 → 190 not taken.
12 SOFT_ERROR_ER(node, BUILTIN_ARG_TYPE_MISMATCH, "Error while parsing the provided value to the requested type")
456 4 } catch (const std::out_of_range &) {
457 ✗ SOFT_ERROR_ER(node, BUILTIN_ARG_TYPE_MISMATCH, "Error while parsing the provided value to the requested type")
458 ✗ }
459 } else {
460
2/2
✓ Branch 102 → 103 taken 2 times.
✓ Branch 102 → 113 taken 82 times.
84 if (!hasDefaultValue)
461
4/8
✓ Branch 105 → 106 taken 2 times.
✗ Branch 105 → 204 not taken.
✓ Branch 106 → 107 taken 2 times.
✗ Branch 106 → 202 not taken.
✓ Branch 109 → 110 taken 2 times.
✗ Branch 109 → 208 not taken.
✓ Branch 110 → 111 taken 2 times.
✗ Branch 110 → 208 not taken.
8 SOFT_ERROR_ER(varNameNode, BUILTIN_ARG_TYPE_MISMATCH, "Build var with this name was not provided");
462
1/2
✓ Branch 113 → 114 taken 82 times.
✗ Branch 113 → 210 not taken.
82 node->setCompileTimeValue(defaultValue, manIdx);
463 }
464
465
2/4
✓ Branch 114 → 115 taken 132 times.
✗ Branch 114 → 209 not taken.
✓ Branch 115 → 116 taken 132 times.
✗ Branch 115 → 209 not taken.
264 return ExprResult{node->setEvaluatedSymbolType(requestedType, manIdx)};
466 }
467
468 8 std::any TypeChecker::visitBuiltinIsTriviallyConstructible(FctCallNode *node) const {
469
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 8 times.
8 assert(node->fqFunctionName == BUILTIN_FCT_NAME_IS_TRIVIALLY_CONSTRUCTIBLE);
470
471
1/2
✓ Branch 7 → 8 taken 8 times.
✗ Branch 7 → 19 not taken.
8 const QualType type = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
472
1/2
✓ Branch 8 → 9 taken 8 times.
✗ Branch 8 → 19 not taken.
8 const bool value = type.isTriviallyConstructible(node);
473
1/2
✓ Branch 9 → 10 taken 8 times.
✗ Branch 9 → 16 not taken.
8 node->setCompileTimeValue({.boolValue = value}, manIdx);
474
475
3/6
✓ Branch 10 → 11 taken 8 times.
✗ Branch 10 → 17 not taken.
✓ Branch 11 → 12 taken 8 times.
✗ Branch 11 → 17 not taken.
✓ Branch 12 → 13 taken 8 times.
✗ Branch 12 → 17 not taken.
16 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BOOL), manIdx)};
476 }
477
478 22 std::any TypeChecker::visitBuiltinIsTriviallyCopyable(FctCallNode *node) const {
479
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 22 times.
22 assert(node->fqFunctionName == BUILTIN_FCT_NAME_IS_TRIVIALLY_COPYABLE);
480
481
1/2
✓ Branch 7 → 8 taken 22 times.
✗ Branch 7 → 19 not taken.
22 const QualType type = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
482
1/2
✓ Branch 8 → 9 taken 22 times.
✗ Branch 8 → 19 not taken.
22 const bool value = type.isTriviallyCopyable(node);
483
1/2
✓ Branch 9 → 10 taken 22 times.
✗ Branch 9 → 16 not taken.
22 node->setCompileTimeValue({.boolValue = value}, manIdx);
484
485
3/6
✓ Branch 10 → 11 taken 22 times.
✗ Branch 10 → 17 not taken.
✓ Branch 11 → 12 taken 22 times.
✗ Branch 11 → 17 not taken.
✓ Branch 12 → 13 taken 22 times.
✗ Branch 12 → 17 not taken.
44 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BOOL), manIdx)};
486 }
487
488 1226 std::any TypeChecker::visitBuiltinIsTriviallyDestructible(FctCallNode *node) const {
489
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1226 times.
1226 assert(node->fqFunctionName == BUILTIN_FCT_NAME_IS_TRIVIALLY_DESTRUCTIBLE);
490
491
1/2
✓ Branch 7 → 8 taken 1226 times.
✗ Branch 7 → 19 not taken.
1226 const QualType type = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
492
1/2
✓ Branch 8 → 9 taken 1226 times.
✗ Branch 8 → 19 not taken.
1226 const bool value = type.isTriviallyDestructible(node);
493
1/2
✓ Branch 9 → 10 taken 1226 times.
✗ Branch 9 → 16 not taken.
1226 node->setCompileTimeValue({.boolValue = value}, manIdx);
494
495
3/6
✓ Branch 10 → 11 taken 1226 times.
✗ Branch 10 → 17 not taken.
✓ Branch 11 → 12 taken 1226 times.
✗ Branch 11 → 17 not taken.
✓ Branch 12 → 13 taken 1226 times.
✗ Branch 12 → 17 not taken.
2452 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BOOL), manIdx)};
496 }
497
498 8 std::any TypeChecker::visitBuiltinIsHeap(FctCallNode *node) const {
499
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 8 times.
8 assert(node->fqFunctionName == BUILTIN_FCT_NAME_IS_HEAP);
500
501
1/2
✓ Branch 7 → 8 taken 8 times.
✗ Branch 7 → 19 not taken.
8 const QualType type = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
502
1/2
✓ Branch 8 → 9 taken 8 times.
✗ Branch 8 → 19 not taken.
8 const bool value = type.isHeap();
503
1/2
✓ Branch 9 → 10 taken 8 times.
✗ Branch 9 → 16 not taken.
8 node->setCompileTimeValue({.boolValue = value}, manIdx);
504
505
3/6
✓ Branch 10 → 11 taken 8 times.
✗ Branch 10 → 17 not taken.
✓ Branch 11 → 12 taken 8 times.
✗ Branch 11 → 17 not taken.
✓ Branch 12 → 13 taken 8 times.
✗ Branch 12 → 17 not taken.
16 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BOOL), manIdx)};
506 }
507
508 509 std::any TypeChecker::visitBuiltinNewCall(FctCallNode *node) const {
509
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 509 times.
509 assert(node->fqFunctionName == BUILTIN_FCT_NAME_NEW);
510
511
1/2
✓ Branch 6 → 7 taken 509 times.
✗ Branch 6 → 160 not taken.
509 FctCallNode::FctCallData &data = node->data.at(manIdx);
512
1/2
✓ Branch 8 → 9 taken 509 times.
✗ Branch 8 → 160 not taken.
509 const QualType templateType = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
513
514
3/4
✓ Branch 9 → 10 taken 509 times.
✗ Branch 9 → 160 not taken.
✓ Branch 10 → 11 taken 498 times.
✓ Branch 10 → 57 taken 11 times.
509 if (templateType.is(TY_STRUCT)) {
515
1/2
✓ Branch 11 → 12 taken 498 times.
✗ Branch 11 → 160 not taken.
498 Scope *bodyScope = templateType.getBodyScope();
516
2/4
✓ Branch 15 → 16 taken 498 times.
✗ Branch 15 → 104 not taken.
✓ Branch 16 → 17 taken 498 times.
✗ Branch 16 → 102 not taken.
1494 Function *ctor = FunctionManager::match(bodyScope, CTOR_FUNCTION_NAME, templateType, data.args, {}, false, node);
517
2/2
✓ Branch 20 → 21 taken 2 times.
✓ Branch 20 → 56 taken 496 times.
498 if (ctor == nullptr) {
518
1/2
✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 160 not taken.
2 const bool copyCtorCall = isCopyCtorCall(node, templateType);
519
4/8
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 26 not taken.
✓ Branch 23 → 24 taken 2 times.
✗ Branch 23 → 160 not taken.
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 26 not taken.
✓ Branch 27 → 28 taken 2 times.
✗ Branch 27 → 39 not taken.
2 if (!copyCtorCall && !templateType.isTriviallyConstructible(node))
520
6/12
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 117 not taken.
✓ Branch 29 → 30 taken 2 times.
✗ Branch 29 → 115 not taken.
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 113 not taken.
✓ Branch 31 → 32 taken 2 times.
✗ Branch 31 → 111 not taken.
✓ Branch 35 → 36 taken 2 times.
✗ Branch 35 → 120 not taken.
✓ Branch 36 → 37 taken 2 times.
✗ Branch 36 → 120 not taken.
4 SOFT_ERROR_ER(node, NO_MATCHING_CTOR_FOUND,
521 "No matching constructor found for type '" + templateType.getName(false) + "'")
522 ✗ if (copyCtorCall && !templateType.isTriviallyCopyable(node))
523 ✗ SOFT_ERROR_ER(node, NO_MATCHING_CTOR_FOUND,
524 "No matching copy constructor found for type '" + templateType.getName(false) + "'")
525 }
526 496 data.callee = ctor;
527
2/2
✓ Branch 58 → 59 taken 2 times.
✓ Branch 58 → 69 taken 9 times.
11 } else if (data.args.size() > 1) {
528
2/4
✓ Branch 60 → 61 taken 2 times.
✗ Branch 60 → 133 not taken.
✓ Branch 61 → 62 taken 2 times.
✗ Branch 61 → 131 not taken.
2 const auto msg = "Expected no or 1 argument for __new on primitive type, got " + std::to_string(data.args.size());
529
3/6
✓ Branch 63 → 64 taken 2 times.
✗ Branch 63 → 135 not taken.
✓ Branch 64 → 65 taken 2 times.
✗ Branch 64 → 134 not taken.
✓ Branch 65 → 66 taken 2 times.
✗ Branch 65 → 134 not taken.
2 SOFT_ERROR_ER(node, BUILTIN_ARG_TYPE_MISMATCH, msg)
530
2/2
✓ Branch 70 → 71 taken 6 times.
✓ Branch 70 → 94 taken 3 times.
11 } else if (data.args.size() == 1) {
531
2/4
✓ Branch 72 → 73 taken 6 times.
✗ Branch 72 → 138 not taken.
✓ Branch 73 → 74 taken 6 times.
✗ Branch 73 → 138 not taken.
6 const QualType argType = data.args.front().first.removeReferenceWrapper().toNonConst();
532
2/4
✓ Branch 74 → 75 taken 6 times.
✗ Branch 74 → 158 not taken.
✗ Branch 75 → 76 not taken.
✓ Branch 75 → 93 taken 6 times.
6 if (!templateType.matches(argType, false, false, true)) {
533 ✗ const auto msg = "Argument type '" + argType.getName() + "' does not match template type '" + templateType.getName() + "'";
534 ✗ SOFT_ERROR_ER(node, BUILTIN_ARG_TYPE_MISMATCH, msg)
535 ✗ }
536 }
537
538
1/2
✓ Branch 94 → 95 taken 505 times.
✗ Branch 94 → 160 not taken.
505 QualType returnType = templateType.toPtr(node);
539
1/2
✓ Branch 95 → 96 taken 505 times.
✗ Branch 95 → 160 not taken.
505 returnType.makeHeap();
540
2/4
✓ Branch 96 → 97 taken 505 times.
✗ Branch 96 → 159 not taken.
✓ Branch 97 → 98 taken 505 times.
✗ Branch 97 → 159 not taken.
1010 return ExprResult{node->setEvaluatedSymbolType(returnType, manIdx)};
541 }
542
543 2521 std::any TypeChecker::visitBuiltinPlacementNewCall(FctCallNode *node) const {
544
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2521 times.
2521 assert(node->fqFunctionName == BUILTIN_FCT_NAME_PLACEMENT_NEW);
545
546
1/2
✓ Branch 6 → 7 taken 2521 times.
✗ Branch 6 → 212 not taken.
2521 FctCallNode::FctCallData &data = node->data.at(manIdx);
547
1/2
✓ Branch 8 → 9 taken 2521 times.
✗ Branch 8 → 212 not taken.
2521 const QualType templateType = node->templateTypeLst->dataTypes.front()->getEvaluatedSymbolType(manIdx);
548
549 // Validate first arg is a byte pointer or a heap pointer to the template type
550
1/2
✓ Branch 10 → 11 taken 2521 times.
✗ Branch 10 → 212 not taken.
2521 const QualType ptrArgType = data.args.front().first.removeReferenceWrapper();
551
1/2
✓ Branch 11 → 12 taken 2521 times.
✗ Branch 11 → 212 not taken.
2521 const bool isBytePtr = ptrArgType.isPtrTo(TY_BYTE);
552
6/10
✓ Branch 12 → 13 taken 2521 times.
✗ Branch 12 → 138 not taken.
✓ Branch 13 → 14 taken 2521 times.
✗ Branch 13 → 18 not taken.
✓ Branch 14 → 15 taken 2521 times.
✗ Branch 14 → 138 not taken.
✓ Branch 15 → 16 taken 2521 times.
✗ Branch 15 → 138 not taken.
✓ Branch 16 → 17 taken 2519 times.
✓ Branch 16 → 18 taken 2 times.
2521 const bool isStructPtr = ptrArgType.isPtr() && ptrArgType.getContained() == templateType;
553
3/4
✓ Branch 19 → 20 taken 2521 times.
✗ Branch 19 → 32 not taken.
✓ Branch 20 → 21 taken 2 times.
✓ Branch 20 → 32 taken 2519 times.
2521 if (!isBytePtr && !isStructPtr)
554
4/8
✓ Branch 23 → 24 taken 2 times.
✗ Branch 23 → 141 not taken.
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 139 not taken.
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 145 not taken.
✓ Branch 29 → 30 taken 2 times.
✗ Branch 29 → 145 not taken.
8 SOFT_ERROR_ER(node->argLst->args.front(), BUILTIN_ARG_TYPE_MISMATCH,
555 "__placement_new expects a 'byte*' or 'T*' as its first argument")
556
557
3/4
✓ Branch 32 → 33 taken 2519 times.
✗ Branch 32 → 212 not taken.
✓ Branch 33 → 34 taken 1591 times.
✓ Branch 33 → 94 taken 928 times.
2519 if (templateType.is(TY_STRUCT)) {
558
1/2
✓ Branch 34 → 35 taken 1591 times.
✗ Branch 34 → 181 not taken.
1591 Scope *bodyScope = templateType.getBodyScope();
559
1/2
✓ Branch 42 → 43 taken 1591 times.
✗ Branch 42 → 146 not taken.
4773 const ArgList ctorArgs(data.args.begin() + 1, data.args.end());
560
2/4
✓ Branch 47 → 48 taken 1591 times.
✗ Branch 47 → 152 not taken.
✓ Branch 48 → 49 taken 1591 times.
✗ Branch 48 → 150 not taken.
4773 Function *ctor = FunctionManager::match(bodyScope, CTOR_FUNCTION_NAME, templateType, ctorArgs, {}, false, node);
561
2/2
✓ Branch 52 → 53 taken 130 times.
✓ Branch 52 → 88 taken 1461 times.
1591 if (ctor == nullptr) {
562
1/2
✓ Branch 53 → 54 taken 130 times.
✗ Branch 53 → 179 not taken.
130 const bool copyCtorCall = isCopyCtorCall(node, templateType);
563
6/8
✓ Branch 54 → 55 taken 2 times.
✓ Branch 54 → 58 taken 128 times.
✓ Branch 55 → 56 taken 2 times.
✗ Branch 55 → 179 not taken.
✓ Branch 56 → 57 taken 2 times.
✗ Branch 56 → 58 not taken.
✓ Branch 59 → 60 taken 2 times.
✓ Branch 59 → 71 taken 128 times.
130 if (!copyCtorCall && !templateType.isTriviallyConstructible(node))
564
6/12
✓ Branch 60 → 61 taken 2 times.
✗ Branch 60 → 165 not taken.
✓ Branch 61 → 62 taken 2 times.
✗ Branch 61 → 163 not taken.
✓ Branch 62 → 63 taken 2 times.
✗ Branch 62 → 161 not taken.
✓ Branch 63 → 64 taken 2 times.
✗ Branch 63 → 159 not taken.
✓ Branch 67 → 68 taken 2 times.
✗ Branch 67 → 168 not taken.
✓ Branch 68 → 69 taken 2 times.
✗ Branch 68 → 168 not taken.
4 SOFT_ERROR_ER(node, NO_MATCHING_CTOR_FOUND,
565 "No matching constructor found for type '" + templateType.getName(false) + "'")
566
4/8
✓ Branch 71 → 72 taken 128 times.
✗ Branch 71 → 75 not taken.
✓ Branch 72 → 73 taken 128 times.
✗ Branch 72 → 179 not taken.
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 128 times.
✗ Branch 76 → 77 not taken.
✓ Branch 76 → 88 taken 128 times.
128 if (copyCtorCall && !templateType.isTriviallyCopyable(node))
567 ✗ SOFT_ERROR_ER(node, NO_MATCHING_CTOR_FOUND,
568 "No matching copy constructor found for type '" + templateType.getName(false) + "'")
569 }
570 1589 data.callee = ctor;
571
4/4
✓ Branch 90 → 91 taken 1589 times.
✓ Branch 90 → 93 taken 2 times.
✓ Branch 95 → 96 taken 2 times.
✓ Branch 95 → 106 taken 926 times.
2519 } else if (data.args.size() > 2) {
572
2/4
✓ Branch 97 → 98 taken 2 times.
✗ Branch 97 → 184 not taken.
✓ Branch 98 → 99 taken 2 times.
✗ Branch 98 → 182 not taken.
2 const auto msg = "Expected 1 or 2 arguments for __placement_new, got " + std::to_string(data.args.size());
573
3/6
✓ Branch 100 → 101 taken 2 times.
✗ Branch 100 → 186 not taken.
✓ Branch 101 → 102 taken 2 times.
✗ Branch 101 → 185 not taken.
✓ Branch 102 → 103 taken 2 times.
✗ Branch 102 → 185 not taken.
2 SOFT_ERROR_ER(node, BUILTIN_ARG_TYPE_MISMATCH, msg)
574
1/2
✓ Branch 107 → 108 taken 926 times.
✗ Branch 107 → 131 not taken.
928 } else if (data.args.size() == 2) {
575
2/4
✓ Branch 109 → 110 taken 926 times.
✗ Branch 109 → 189 not taken.
✓ Branch 110 → 111 taken 926 times.
✗ Branch 110 → 189 not taken.
926 const QualType argType = data.args.back().first.removeReferenceWrapper().toNonConst();
576
2/4
✓ Branch 111 → 112 taken 926 times.
✗ Branch 111 → 209 not taken.
✗ Branch 112 → 113 not taken.
✓ Branch 112 → 130 taken 926 times.
926 if (!templateType.matches(argType, false, false, true)) {
577 ✗ const auto msg = "Argument type '" + argType.getName() + "' does not match template type '" + templateType.getName() + "'";
578 ✗ SOFT_ERROR_ER(node, BUILTIN_ARG_TYPE_MISMATCH, msg)
579 ✗ }
580 }
581
582
3/6
✓ Branch 131 → 132 taken 2515 times.
✗ Branch 131 → 210 not taken.
✓ Branch 132 → 133 taken 2515 times.
✗ Branch 132 → 210 not taken.
✓ Branch 133 → 134 taken 2515 times.
✗ Branch 133 → 210 not taken.
5030 return ExprResult{node->setEvaluatedSymbolType(templateType.toPtr(node), manIdx)};
583 }
584
585 2 std::any TypeChecker::visitBuiltinSourceFileCall(FctCallNode *node) const {
586
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
2 assert(node->fqFunctionName == BUILTIN_FCT_NAME_SOURCE_FILE);
587
588 2 const size_t stringValueOffset = resourceManager.compileTimeStringValues.size();
589
2/4
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 20 not taken.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 18 not taken.
2 resourceManager.compileTimeStringValues.push_back(node->codeLoc.toPrettyFilePath());
590 2 node->data.at(manIdx).setCompileTimeValue({.stringValueOffset = stringValueOffset});
591
592
3/6
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 21 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 21 not taken.
✓ Branch 14 → 15 taken 2 times.
✗ Branch 14 → 21 not taken.
4 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_STRING), manIdx)};
593 }
594
595 4 std::any TypeChecker::visitBuiltinSourceLineCall(FctCallNode *node) const {
596
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 4 times.
4 assert(node->fqFunctionName == BUILTIN_FCT_NAME_SOURCE_LINE);
597
598 4 node->data.at(manIdx).setCompileTimeValue({.longValue = static_cast<int64_t>(node->codeLoc.line)});
599
600
3/6
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 14 not taken.
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 14 not taken.
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 14 not taken.
8 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
601 }
602
603 4 std::any TypeChecker::visitBuiltinSourceColumnCall(FctCallNode *node) const {
604
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 4 times.
4 assert(node->fqFunctionName == BUILTIN_FCT_NAME_SOURCE_COLUMN);
605
606 4 node->data.at(manIdx).setCompileTimeValue({.longValue = static_cast<int64_t>(node->codeLoc.col)});
607
608
3/6
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 14 not taken.
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 14 not taken.
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 14 not taken.
8 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
609 }
610
611 /**
612 * Resolves to a reference to the calling thread's ErrorTraceBuffer (std/runtime/error_trace_rt.spice). Only ever
613 * called from within that same file, where the struct is always in scope by name.
614 */
615 1461 std::any TypeChecker::visitBuiltinErrTraceBufferCall(FctCallNode *node) const {
616
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1461 times.
1461 assert(node->fqFunctionName == BUILTIN_FCT_NAME_ERR_TRACE_BUFFER);
617
618
1/2
✓ Branch 8 → 9 taken 1461 times.
✗ Branch 8 → 25 not taken.
4383 const SymbolTableEntry *structEntry = rootScope->lookupStrict("ErrorTraceBuffer");
619
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1461 times.
1461 assert(structEntry != nullptr);
620
2/4
✓ Branch 16 → 17 taken 1461 times.
✗ Branch 16 → 30 not taken.
✓ Branch 17 → 18 taken 1461 times.
✗ Branch 17 → 30 not taken.
1461 const QualType bufferType = structEntry->getQualType().toRef(node);
621
622
2/4
✓ Branch 18 → 19 taken 1461 times.
✗ Branch 18 → 29 not taken.
✓ Branch 19 → 20 taken 1461 times.
✗ Branch 19 → 29 not taken.
2922 return ExprResult{node->setEvaluatedSymbolType(bufferType, manIdx)};
623 }
624
625 /**
626 * Resolves to a pointer to the process's stderr stream. Spice source has no syntax for declaring an external
627 * *variable* (only functions/procedures via 'ext'), so this exists as a builtin that reaches the real libc
628 * symbol directly in IR generation, the same way panic()'s own codegen already did before this builtin existed.
629 */
630 1507 std::any TypeChecker::visitBuiltinStdErrCall(FctCallNode *node) const {
631
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1507 times.
1507 assert(node->fqFunctionName == BUILTIN_FCT_NAME_STDERR);
632
633
4/8
✓ Branch 6 → 7 taken 1507 times.
✗ Branch 6 → 13 not taken.
✓ Branch 7 → 8 taken 1507 times.
✗ Branch 7 → 13 not taken.
✓ Branch 8 → 9 taken 1507 times.
✗ Branch 8 → 13 not taken.
✓ Branch 9 → 10 taken 1507 times.
✗ Branch 9 → 13 not taken.
3014 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BYTE).toPtr(node), manIdx)};
634 }
635
636 /**
637 * Resolves to the frame address (saved frame-pointer slot) of the calling function's own stack frame, i.e. the
638 * same value as C's `__builtin_frame_address(0)`. IRGenerator keeps frame pointers for every function it emits, so
639 * the value is always a real frame address - but see the IR generator side of this builtin for why that alone does
640 * not make the surrounding frame chain walkable on every target.
641 */
642 ✗ std::any TypeChecker::visitBuiltinFrameAddressCall(FctCallNode *node) const {
643 ✗ assert(node->fqFunctionName == BUILTIN_FCT_NAME_FRAME_ADDRESS);
644
645 ✗ return ExprResult{node->setEvaluatedSymbolType(QualType(TY_BYTE).toPtr(node), manIdx)};
646 }
647
648 } // namespace spice::compiler
649