GCC Code Coverage Report


Directory: ../
File: src/typechecker/TypeCheckBuiltinFunctions.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 86 94 91.5%
Functions: 7 7 100.0%
Branches: 169 330 51.2%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "TypeChecker.h"
4
5 #include <SourceFile.h>
6 #include <ast/ASTNodes.h>
7 #include <global/GlobalResourceManager.h>
8 #include <typechecker/MacroDefs.h>
9
10 namespace spice::compiler {
11
12 1580 std::any TypeChecker::visitBuiltinCall(BuiltinCallNode *node) {
13
2/2
✓ Branch 0 (2→3) taken 781 times.
✓ Branch 1 (2→4) taken 799 times.
1580 if (node->printfCall)
14 781 return visitPrintfCall(node->printfCall);
15
2/2
✓ Branch 0 (4→5) taken 127 times.
✓ Branch 1 (4→6) taken 672 times.
799 if (node->sizeofCall)
16 127 return visitSizeofCall(node->sizeofCall);
17
2/2
✓ Branch 0 (6→7) taken 11 times.
✓ Branch 1 (6→8) taken 661 times.
672 if (node->alignofCall)
18 11 return visitAlignofCall(node->alignofCall);
19
2/2
✓ Branch 0 (8→9) taken 50 times.
✓ Branch 1 (8→10) taken 611 times.
661 if (node->lenCall)
20 50 return visitLenCall(node->lenCall);
21
2/2
✓ Branch 0 (10→11) taken 610 times.
✓ Branch 1 (10→12) taken 1 times.
611 if (node->panicCall)
22 610 return visitPanicCall(node->panicCall);
23
1/2
✓ Branch 0 (12→13) taken 1 times.
✗ Branch 1 (12→14) not taken.
1 if (node->sysCall)
24 1 return visitSysCall(node->sysCall);
25 assert_fail("Unknown builtin call"); // LCOV_EXCL_LINE
26 return nullptr; // LCOV_EXCL_LINE
27 }
28
29 781 std::any TypeChecker::visitPrintfCall(PrintfCallNode *node) {
30 // Check if assignment types match placeholder types
31 781 size_t placeholderCount = 0;
32 781 size_t index = node->templatedString.find_first_of('%');
33
5/6
✓ Branch 0 (118→119) taken 662 times.
✓ Branch 1 (118→122) taken 759 times.
✓ Branch 2 (120→121) taken 662 times.
✗ Branch 3 (120→122) not taken.
✓ Branch 4 (123→3) taken 662 times.
✓ Branch 5 (123→124) taken 759 times.
1421 while (index != std::string::npos && index != node->templatedString.size() - 1) {
34 // Check if there is another assignExpr
35
2/2
✓ Branch 0 (4→5) taken 1 times.
✓ Branch 1 (4→15) taken 661 times.
662 if (node->args.size() <= placeholderCount)
36
4/8
✓ Branch 0 (7→8) taken 1 times.
✗ Branch 1 (7→144) not taken.
✓ Branch 2 (8→9) taken 1 times.
✗ Branch 3 (8→142) not taken.
✓ Branch 4 (11→12) taken 1 times.
✗ Branch 5 (11→148) not taken.
✓ Branch 6 (12→13) taken 1 times.
✗ Branch 7 (12→148) not taken.
3 SOFT_ERROR_ER(node, PRINTF_ARG_COUNT_ERROR, "The placeholder string contains more placeholders than arguments")
37
38 // Get next assignment
39
1/2
✓ Branch 0 (15→16) taken 661 times.
✗ Branch 1 (15→198) not taken.
661 AssignExprNode *assignment = node->args.at(placeholderCount);
40 // Visit assignment
41
2/4
✓ Branch 0 (16→17) taken 661 times.
✗ Branch 1 (16→151) not taken.
✓ Branch 2 (17→18) taken 661 times.
✗ Branch 3 (17→149) not taken.
661 QualType argType = std::any_cast<ExprResult>(visit(assignment)).type;
42
5/8
✓ Branch 0 (19→20) taken 661 times.
✗ Branch 1 (19→198) not taken.
✓ Branch 2 (20→21) taken 15 times.
✓ Branch 3 (20→25) taken 646 times.
✓ Branch 4 (21→22) taken 15 times.
✗ Branch 5 (21→153) not taken.
✓ Branch 6 (22→23) taken 15 times.
✗ Branch 7 (22→153) not taken.
661 HANDLE_UNRESOLVED_TYPE_ER(argType)
43
1/2
✓ Branch 0 (25→26) taken 646 times.
✗ Branch 1 (25→154) not taken.
646 argType = argType.removeReferenceWrapper();
44
45
6/8
✓ Branch 0 (26→27) taken 646 times.
✗ Branch 1 (26→198) not taken.
✓ Branch 2 (27→28) taken 17 times.
✓ Branch 3 (27→40) taken 335 times.
✓ Branch 4 (27→52) taken 54 times.
✓ Branch 5 (27→64) taken 235 times.
✓ Branch 6 (27→85) taken 5 times.
✗ Branch 7 (27→104) not taken.
646 switch (node->templatedString.at(index + 1)) {
46 17 case 'c': {
47
3/4
✓ Branch 0 (28→29) taken 17 times.
✗ Branch 1 (28→198) not taken.
✓ Branch 2 (29→30) taken 1 times.
✓ Branch 3 (29→39) taken 16 times.
17 if (!argType.is(TY_CHAR))
48
5/10
✓ Branch 0 (30→31) taken 1 times.
✗ Branch 1 (30→159) not taken.
✓ Branch 2 (31→32) taken 1 times.
✗ Branch 3 (31→157) not taken.
✓ Branch 4 (32→33) taken 1 times.
✗ Branch 5 (32→155) not taken.
✓ Branch 6 (35→36) taken 1 times.
✗ Branch 7 (35→161) not taken.
✓ Branch 8 (36→37) taken 1 times.
✗ Branch 9 (36→161) not taken.
1 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR, "The placeholder string expects char, but got " + argType.getName(false))
49 16 placeholderCount++;
50 16 break;
51 }
52 335 case 'd':
53 case 'i':
54 case 'l':
55 case 'o':
56 case 'u':
57 case 'x':
58 case 'X': {
59
3/4
✓ Branch 0 (40→41) taken 335 times.
✗ Branch 1 (40→162) not taken.
✓ Branch 2 (41→42) taken 2 times.
✓ Branch 3 (41→51) taken 333 times.
335 if (!argType.isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_BOOL}))
60
5/10
✓ Branch 0 (42→43) taken 2 times.
✗ Branch 1 (42→167) not taken.
✓ Branch 2 (43→44) taken 2 times.
✗ Branch 3 (43→165) not taken.
✓ Branch 4 (44→45) taken 2 times.
✗ Branch 5 (44→163) not taken.
✓ Branch 6 (47→48) taken 2 times.
✗ Branch 7 (47→169) not taken.
✓ Branch 8 (48→49) taken 2 times.
✗ Branch 9 (48→169) not taken.
2 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR,
61 "The placeholder string expects int, short, long, byte or bool, but got " + argType.getName(false))
62 333 placeholderCount++;
63 333 break;
64 }
65 54 case 'a':
66 case 'A':
67 case 'f':
68 case 'F':
69 case 'e':
70 case 'E':
71 case 'g':
72 case 'G': {
73
3/4
✓ Branch 0 (52→53) taken 54 times.
✗ Branch 1 (52→198) not taken.
✓ Branch 2 (53→54) taken 1 times.
✓ Branch 3 (53→63) taken 53 times.
54 if (!argType.is(TY_DOUBLE))
74
5/10
✓ Branch 0 (54→55) taken 1 times.
✗ Branch 1 (54→174) not taken.
✓ Branch 2 (55→56) taken 1 times.
✗ Branch 3 (55→172) not taken.
✓ Branch 4 (56→57) taken 1 times.
✗ Branch 5 (56→170) not taken.
✓ Branch 6 (59→60) taken 1 times.
✗ Branch 7 (59→176) not taken.
✓ Branch 8 (60→61) taken 1 times.
✗ Branch 9 (60→176) not taken.
1 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR, "The placeholder string expects double, but got " + argType.getName(false))
75 53 placeholderCount++;
76 53 break;
77 }
78 235 case 's': {
79
13/18
✓ Branch 0 (64→65) taken 235 times.
✗ Branch 1 (64→198) not taken.
✓ Branch 2 (65→66) taken 60 times.
✓ Branch 3 (65→73) taken 175 times.
✓ Branch 4 (66→67) taken 60 times.
✗ Branch 5 (66→198) not taken.
✓ Branch 6 (67→68) taken 2 times.
✓ Branch 7 (67→73) taken 58 times.
✓ Branch 8 (68→69) taken 2 times.
✗ Branch 9 (68→198) not taken.
✓ Branch 10 (69→70) taken 1 times.
✓ Branch 11 (69→73) taken 1 times.
✓ Branch 12 (70→71) taken 1 times.
✗ Branch 13 (70→198) not taken.
✓ Branch 14 (71→72) taken 1 times.
✗ Branch 15 (71→73) not taken.
✓ Branch 16 (74→75) taken 1 times.
✓ Branch 17 (74→84) taken 234 times.
235 if (!argType.is(TY_STRING) && !argType.isStringObj() && !argType.isPtrTo(TY_CHAR) && !argType.isArrayOf(TY_CHAR))
80
5/10
✓ Branch 0 (75→76) taken 1 times.
✗ Branch 1 (75→181) not taken.
✓ Branch 2 (76→77) taken 1 times.
✗ Branch 3 (76→179) not taken.
✓ Branch 4 (77→78) taken 1 times.
✗ Branch 5 (77→177) not taken.
✓ Branch 6 (80→81) taken 1 times.
✗ Branch 7 (80→183) not taken.
✓ Branch 8 (81→82) taken 1 times.
✗ Branch 9 (81→183) not taken.
1 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR,
81 "The placeholder string expects string, String, char* or char[], but got " + argType.getName(false))
82 234 placeholderCount++;
83 234 break;
84 }
85 5 case 'p': {
86
9/14
✓ Branch 0 (85→86) taken 5 times.
✗ Branch 1 (85→198) not taken.
✓ Branch 2 (86→87) taken 1 times.
✓ Branch 3 (86→92) taken 4 times.
✓ Branch 4 (87→88) taken 1 times.
✗ Branch 5 (87→198) not taken.
✓ Branch 6 (88→89) taken 1 times.
✗ Branch 7 (88→92) not taken.
✓ Branch 8 (89→90) taken 1 times.
✗ Branch 9 (89→198) not taken.
✓ Branch 10 (90→91) taken 1 times.
✗ Branch 11 (90→92) not taken.
✓ Branch 12 (93→94) taken 1 times.
✓ Branch 13 (93→103) taken 4 times.
5 if (!argType.isPtr() && !argType.isArray() && !argType.is(TY_STRING))
87
5/10
✓ Branch 0 (94→95) taken 1 times.
✗ Branch 1 (94→188) not taken.
✓ Branch 2 (95→96) taken 1 times.
✗ Branch 3 (95→186) not taken.
✓ Branch 4 (96→97) taken 1 times.
✗ Branch 5 (96→184) not taken.
✓ Branch 6 (99→100) taken 1 times.
✗ Branch 7 (99→190) not taken.
✓ Branch 8 (100→101) taken 1 times.
✗ Branch 9 (100→190) not taken.
1 SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR,
88 "The placeholder string expects pointer, array or string, but got " + argType.getName(false))
89 4 placeholderCount++;
90 4 break;
91 }
92 default:
93 SOFT_ERROR_ER(node, PRINTF_TYPE_ERROR, "The placeholder string contains an invalid placeholder")
94 }
95 640 index = node->templatedString.find_first_of('%', index + 2); // We can also skip the following char
96 }
97
98 // Check if the number of placeholders matches the number of args
99
2/2
✓ Branch 0 (125→126) taken 1 times.
✓ Branch 1 (125→136) taken 758 times.
759 if (placeholderCount < node->args.size())
100
4/8
✓ Branch 0 (128→129) taken 1 times.
✗ Branch 1 (128→201) not taken.
✓ Branch 2 (129→130) taken 1 times.
✗ Branch 3 (129→199) not taken.
✓ Branch 4 (132→133) taken 1 times.
✗ Branch 5 (132→205) not taken.
✓ Branch 6 (133→134) taken 1 times.
✗ Branch 7 (133→205) not taken.
3 SOFT_ERROR_ER(node, PRINTF_ARG_COUNT_ERROR, "The placeholder string contains less placeholders than arguments")
101
102
3/6
✓ Branch 0 (136→137) taken 758 times.
✗ Branch 1 (136→206) not taken.
✓ Branch 2 (137→138) taken 758 times.
✗ Branch 3 (137→206) not taken.
✓ Branch 4 (138→139) taken 758 times.
✗ Branch 5 (138→206) not taken.
758 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_INT), manIdx)};
103 }
104
105 127 std::any TypeChecker::visitSizeofCall(SizeofCallNode *node) {
106
2/2
✓ Branch 0 (2→3) taken 111 times.
✓ Branch 1 (2→6) taken 16 times.
127 if (node->isType) { // Size of type
107
1/2
✓ Branch 0 (3→4) taken 111 times.
✗ Branch 1 (3→15) not taken.
111 visit(node->dataType);
108 } else { // Size of value
109
1/2
✓ Branch 0 (6→7) taken 16 times.
✗ Branch 1 (6→16) not taken.
16 visit(node->assignExpr);
110 }
111
112
3/6
✓ Branch 0 (9→10) taken 127 times.
✗ Branch 1 (9→17) not taken.
✓ Branch 2 (10→11) taken 127 times.
✗ Branch 3 (10→17) not taken.
✓ Branch 4 (11→12) taken 127 times.
✗ Branch 5 (11→17) not taken.
127 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
113 }
114
115 11 std::any TypeChecker::visitAlignofCall(AlignofCallNode *node) {
116
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→6) taken 10 times.
11 if (node->isType) { // Align of type
117
1/2
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→15) not taken.
1 visit(node->dataType);
118 } else { // Align of value
119
1/2
✓ Branch 0 (6→7) taken 10 times.
✗ Branch 1 (6→16) not taken.
10 visit(node->assignExpr);
120 }
121
122
3/6
✓ Branch 0 (9→10) taken 11 times.
✗ Branch 1 (9→17) not taken.
✓ Branch 2 (10→11) taken 11 times.
✗ Branch 3 (10→17) not taken.
✓ Branch 4 (11→12) taken 11 times.
✗ Branch 5 (11→17) not taken.
11 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
123 }
124
125 50 std::any TypeChecker::visitLenCall(LenCallNode *node) {
126
2/4
✓ Branch 0 (2→3) taken 50 times.
✗ Branch 1 (2→48) not taken.
✓ Branch 2 (3→4) taken 50 times.
✗ Branch 3 (3→46) not taken.
50 QualType argType = std::any_cast<ExprResult>(visit(node->assignExpr)).type;
127
2/8
✓ Branch 0 (5→6) taken 50 times.
✗ Branch 1 (5→61) not taken.
✗ Branch 2 (6→7) not taken.
✓ Branch 3 (6→11) taken 50 times.
✗ Branch 4 (7→8) not taken.
✗ Branch 5 (7→50) not taken.
✗ Branch 6 (8→9) not taken.
✗ Branch 7 (8→50) not taken.
50 HANDLE_UNRESOLVED_TYPE_ER(argType)
128
1/2
✓ Branch 0 (11→12) taken 50 times.
✗ Branch 1 (11→51) not taken.
50 argType = argType.removeReferenceWrapper();
129
130 // Check if arg is of type array
131
8/10
✓ Branch 0 (12→13) taken 50 times.
✗ Branch 1 (12→61) not taken.
✓ Branch 2 (13→14) taken 26 times.
✓ Branch 3 (13→17) taken 24 times.
✓ Branch 4 (14→15) taken 26 times.
✗ Branch 5 (14→61) not taken.
✓ Branch 6 (15→16) taken 1 times.
✓ Branch 7 (15→17) taken 25 times.
✓ Branch 8 (18→19) taken 1 times.
✓ Branch 9 (18→29) taken 49 times.
50 if (!argType.isArray() && !argType.is(TY_STRING))
132
4/8
✓ Branch 0 (21→22) taken 1 times.
✗ Branch 1 (21→54) not taken.
✓ Branch 2 (22→23) taken 1 times.
✗ Branch 3 (22→52) not taken.
✓ Branch 4 (25→26) taken 1 times.
✗ Branch 5 (25→58) not taken.
✓ Branch 6 (26→27) taken 1 times.
✗ Branch 7 (26→58) not taken.
3 SOFT_ERROR_ER(node->assignExpr, EXPECTED_ARRAY_TYPE, "The len builtin can only work on arrays or strings")
133
134 // If we want to use the len builtin on a string, we need to import the string runtime module
135
8/10
✓ Branch 0 (29→30) taken 49 times.
✗ Branch 1 (29→61) not taken.
✓ Branch 2 (30→31) taken 25 times.
✓ Branch 3 (30→36) taken 24 times.
✓ Branch 4 (31→32) taken 25 times.
✗ Branch 5 (31→61) not taken.
✓ Branch 6 (34→35) taken 24 times.
✓ Branch 7 (34→36) taken 1 times.
✓ Branch 8 (37→38) taken 24 times.
✓ Branch 9 (37→39) taken 25 times.
74 if (argType.is(TY_STRING) && !sourceFile->isStringRT())
136
1/2
✓ Branch 0 (38→39) taken 24 times.
✗ Branch 1 (38→61) not taken.
24 sourceFile->requestRuntimeModule(STRING_RT);
137
138
3/6
✓ Branch 0 (39→40) taken 49 times.
✗ Branch 1 (39→59) not taken.
✓ Branch 2 (40→41) taken 49 times.
✗ Branch 3 (40→59) not taken.
✓ Branch 4 (41→42) taken 49 times.
✗ Branch 5 (41→59) not taken.
49 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
139 }
140
141 610 std::any TypeChecker::visitPanicCall(PanicCallNode *node) {
142
2/4
✓ Branch 0 (2→3) taken 610 times.
✗ Branch 1 (2→33) not taken.
✓ Branch 2 (3→4) taken 610 times.
✗ Branch 3 (3→31) not taken.
610 QualType argType = std::any_cast<ExprResult>(visit(node->assignExpr)).type;
143
2/8
✓ Branch 0 (5→6) taken 610 times.
✗ Branch 1 (5→46) not taken.
✗ Branch 2 (6→7) not taken.
✓ Branch 3 (6→11) taken 610 times.
✗ Branch 4 (7→8) not taken.
✗ Branch 5 (7→35) not taken.
✗ Branch 6 (8→9) not taken.
✗ Branch 7 (8→35) not taken.
610 HANDLE_UNRESOLVED_TYPE_ER(argType)
144
1/2
✓ Branch 0 (11→12) taken 610 times.
✗ Branch 1 (11→36) not taken.
610 argType = argType.removeReferenceWrapper();
145
146 // Check if arg is of type array
147
2/4
✓ Branch 0 (12→13) taken 610 times.
✗ Branch 1 (12→46) not taken.
✗ Branch 2 (13→14) not taken.
✓ Branch 3 (13→24) taken 610 times.
610 if (!argType.isErrorObj())
148 SOFT_ERROR_ER(node->assignExpr, EXPECTED_ERROR_TYPE, "The panic builtin can only work with errors")
149
150
3/6
✓ Branch 0 (24→25) taken 610 times.
✗ Branch 1 (24→44) not taken.
✓ Branch 2 (25→26) taken 610 times.
✗ Branch 3 (25→44) not taken.
✓ Branch 4 (26→27) taken 610 times.
✗ Branch 5 (26→44) not taken.
610 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_DYN), manIdx)};
151 }
152
153 1 std::any TypeChecker::visitSysCall(SysCallNode *node) {
154 // Check if the syscall number if of type short
155
2/4
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→62) not taken.
✓ Branch 2 (4→5) taken 1 times.
✗ Branch 3 (4→60) not taken.
1 const QualType sysCallNumberType = std::any_cast<ExprResult>(visit(node->args.front())).type;
156
2/4
✓ Branch 0 (6→7) taken 1 times.
✗ Branch 1 (6→88) not taken.
✗ Branch 2 (7→8) not taken.
✓ Branch 3 (7→19) taken 1 times.
1 if (!sysCallNumberType.is(TY_SHORT))
157 SOFT_ERROR_ER(node->args.front(), INVALID_SYSCALL_NUMBER_TYPE, "Syscall number must be of type short")
158
159 // Check if the syscall number is out of range
160 // According to https://www.chromium.org/chromium-os/developer-library/reference/linux-constants/syscalls/
161
2/4
✓ Branch 0 (19→20) taken 1 times.
✗ Branch 1 (19→88) not taken.
✗ Branch 2 (20→21) not taken.
✓ Branch 3 (20→33) taken 1 times.
1 if (node->hasCompileTimeValue()) {
162 const unsigned short sysCallNumber = node->getCompileTimeValue().shortValue;
163 if (sysCallNumber < 0 || sysCallNumber > 439)
164 SOFT_ERROR_ER(node, SYSCALL_NUMBER_OUT_OF_RANGE, "Only syscall numbers between 0 and 439 are supported")
165 }
166
167 // Check if too many syscall args are given
168 // According to https://www.chromium.org/chromium-os/developer-library/reference/linux-constants/syscalls/
169
1/2
✗ Branch 0 (34→35) not taken.
✓ Branch 1 (34→46) taken 1 times.
1 if (node->args.size() > 6)
170 SOFT_ERROR_ER(node->args.front(), TOO_MANY_SYSCALL_ARGS, "There are no syscalls that support more than 6 arguments")
171
172 // Visit children
173
2/2
✓ Branch 0 (52→47) taken 3 times.
✓ Branch 1 (52→53) taken 1 times.
4 for (size_t i = 1; i < node->args.size(); i++)
174
2/4
✓ Branch 0 (47→48) taken 3 times.
✗ Branch 1 (47→85) not taken.
✓ Branch 2 (48→49) taken 3 times.
✗ Branch 3 (48→85) not taken.
3 visit(node->args.at(i));
175
176
3/6
✓ Branch 0 (53→54) taken 1 times.
✗ Branch 1 (53→86) not taken.
✓ Branch 2 (54→55) taken 1 times.
✗ Branch 3 (54→86) not taken.
✓ Branch 4 (55→56) taken 1 times.
✗ Branch 5 (55→86) not taken.
1 return ExprResult{node->setEvaluatedSymbolType(QualType(TY_LONG), manIdx)};
177 }
178
179 } // namespace spice::compiler
180