Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include "OpRuleManager.h" | ||
4 | |||
5 | #include <SourceFile.h> | ||
6 | #include <ast/ASTNodes.h> | ||
7 | #include <global/GlobalResourceManager.h> | ||
8 | #include <global/RuntimeModuleManager.h> | ||
9 | #include <typechecker/MacroDefs.h> | ||
10 | #include <typechecker/TypeChecker.h> | ||
11 | |||
12 | namespace spice::compiler { | ||
13 | |||
14 | 4327 | OpRuleManager::OpRuleManager(TypeChecker *typeChecker) | |
15 | 4327 | : typeChecker(typeChecker), resourceManager(typeChecker->resourceManager) {} | |
16 | |||
17 | 17496 | QualType OpRuleManager::getAssignResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, bool isDecl, | |
18 | bool isReturn, const char *errMsgPrefix) const { | ||
19 | // Retrieve types | ||
20 | 17496 | const QualType lhsType = lhs.type; | |
21 | 17496 | const QualType rhsType = rhs.type; | |
22 | |||
23 | // Skip type compatibility check if the lhs is of type dyn -> perform type inference | ||
24 |
3/4✓ Branch 1 taken 17496 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
✓ Branch 4 taken 17431 times.
|
17496 | if (lhsType.is(TY_DYN)) |
25 | 65 | return rhsType; | |
26 | |||
27 | // Check if we try to assign a constant value | ||
28 |
2/2✓ Branch 1 taken 17429 times.
✓ Branch 2 taken 2 times.
|
17431 | ensureNoConstAssign(node, lhsType, isDecl, isReturn); |
29 | |||
30 | // Allow pointers and arrays of the same type straight away | ||
31 |
8/10✓ Branch 1 taken 17429 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2297 times.
✓ Branch 4 taken 15132 times.
✓ Branch 6 taken 2297 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2001 times.
✓ Branch 9 taken 296 times.
✓ Branch 10 taken 2001 times.
✓ Branch 11 taken 15428 times.
|
17429 | if (lhsType.isOneOf({TY_PTR, TY_REF}) && lhsType.matches(rhsType, false, false, true)) { |
32 | // If we perform a heap x* = heap x* assignment, we need set the right hand side to MOVED | ||
33 |
15/22✓ Branch 0 taken 615 times.
✓ Branch 1 taken 1386 times.
✓ Branch 3 taken 615 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 454 times.
✓ Branch 6 taken 161 times.
✓ Branch 8 taken 454 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 377 times.
✓ Branch 11 taken 77 times.
✓ Branch 13 taken 377 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 377 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 377 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 377 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 377 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 377 times.
✓ Branch 26 taken 1624 times.
|
2001 | if (rhs.entry && lhsType.isPtr() && lhsType.isHeap() && rhsType.removeReferenceWrapper().isPtr() && rhsType.isHeap()) |
34 |
1/2✓ Branch 1 taken 377 times.
✗ Branch 2 not taken.
|
377 | rhs.entry->updateState(MOVED, node); |
35 | 2001 | return rhsType; | |
36 | } | ||
37 | // Allow ref type to type of the same contained type straight away | ||
38 |
3/4✓ Branch 1 taken 15428 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 221 times.
✓ Branch 4 taken 15207 times.
|
15428 | if (rhsType.isRef()) { |
39 | // If this is const ref, remove both: the reference and the constness | ||
40 |
2/4✓ Branch 1 taken 221 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 221 times.
✗ Branch 5 not taken.
|
221 | const QualType rhsModified = rhsType.getContained().toNonConst(); |
41 |
4/6✓ Branch 1 taken 221 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 221 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 219 times.
✓ Branch 7 taken 2 times.
|
221 | if (lhsType.matches(rhsModified, false, !lhsType.isRef(), true)) { |
42 | // In case of a return expression, we perform temp stealing | ||
43 |
9/10✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 129 times.
✓ Branch 4 taken 90 times.
✓ Branch 6 taken 117 times.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 115 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 115 times.
✓ Branch 11 taken 104 times.
|
219 | if (rhsModified.is(TY_STRUCT) && !rhs.isTemporary() && !isReturn) |
44 |
1/2✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
|
115 | typeChecker->implicitlyCallStructCopyCtor(rhs.entry, rhs.entry->declNode); |
45 | 219 | return lhsType; | |
46 | } | ||
47 | } | ||
48 | // Allow arrays, structs, interfaces, functions, procedures of the same type straight away | ||
49 |
8/10✓ Branch 1 taken 15209 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✓ Branch 4 taken 15131 times.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 71 times.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 71 times.
✓ Branch 11 taken 15138 times.
|
15209 | if (lhsType.isOneOf({TY_ARRAY, TY_INTERFACE, TY_FUNCTION, TY_PROCEDURE}) && lhsType.matches(rhsType, false, true, true)) |
50 | 71 | return rhsType; | |
51 | // Allow struct of the same type straight away | ||
52 |
8/10✓ Branch 1 taken 15138 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1661 times.
✓ Branch 4 taken 13477 times.
✓ Branch 6 taken 1661 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1660 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1660 times.
✓ Branch 11 taken 13478 times.
|
15138 | if (lhsType.is(TY_STRUCT) && lhsType.matches(rhsType, false, true, true)) { |
53 | // In case of a return expression, we perform temp stealing | ||
54 |
6/6✓ Branch 1 taken 51 times.
✓ Branch 2 taken 1609 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 1654 times.
|
1660 | if (!rhs.isTemporary() && !isReturn) |
55 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | typeChecker->implicitlyCallStructCopyCtor(rhs.entry, rhs.entry->declNode); |
56 | 1660 | return rhsType; | |
57 | } | ||
58 | |||
59 | // Check common type combinations | ||
60 |
2/2✓ Branch 1 taken 13477 times.
✓ Branch 2 taken 1 times.
|
13478 | const QualType resultType = getAssignResultTypeCommon(node, lhs, rhs, isDecl, isReturn); |
61 |
3/4✓ Branch 1 taken 13477 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 268 times.
✓ Branch 4 taken 13209 times.
|
13477 | if (!resultType.is(TY_INVALID)) |
62 | 268 | return resultType; | |
63 | |||
64 | // Check primitive type combinations | ||
65 |
2/2✓ Branch 1 taken 13197 times.
✓ Branch 2 taken 12 times.
|
13209 | return validateBinaryOperation(node, ASSIGN_OP_RULES, std::size(ASSIGN_OP_RULES), "=", lhsType, rhsType, true, errMsgPrefix); |
66 | } | ||
67 | |||
68 | 245 | QualType OpRuleManager::getFieldAssignResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, bool imm, | |
69 | bool isDecl) const { | ||
70 | // Retrieve types | ||
71 | 245 | const QualType lhsType = lhs.type; | |
72 | 245 | const QualType rhsType = rhs.type; | |
73 |
2/4✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 245 times.
|
245 | assert(!lhsType.is(TY_DYN)); |
74 | |||
75 | // Check if we try to assign a constant value | ||
76 |
1/2✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
|
245 | ensureNoConstAssign(node, lhsType, isDecl); |
77 | |||
78 | // Allow pointers, arrays and structs of the same type straight away | ||
79 |
8/10✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 135 times.
✓ Branch 4 taken 110 times.
✓ Branch 6 taken 135 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 133 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 133 times.
✓ Branch 11 taken 112 times.
|
245 | if (lhsType.isOneOf({TY_PTR, TY_ARRAY}) && lhsType == rhsType) { |
80 | // If we perform a heap x* = heap x* assignment, we need set the right hand side to MOVED | ||
81 |
8/22✓ Branch 0 taken 45 times.
✓ Branch 1 taken 88 times.
✓ Branch 3 taken 45 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 43 times.
✓ Branch 6 taken 2 times.
✓ Branch 8 taken 43 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 43 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 133 times.
|
133 | if (rhs.entry && lhsType.isPtr() && lhsType.isHeap() && rhsType.removeReferenceWrapper().isPtr() && rhsType.isHeap()) |
82 | ✗ | rhs.entry->updateState(MOVED, node); | |
83 | 133 | return rhsType; | |
84 | } | ||
85 | // Allow struct of the same type straight away | ||
86 |
8/10✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 107 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 108 times.
|
112 | if (lhsType.is(TY_STRUCT) && lhsType.matches(rhsType, false, true, true)) { |
87 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if (!rhs.isTemporary()) |
88 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | typeChecker->implicitlyCallStructCopyCtor(rhs.entry, rhs.entry->declNode); |
89 | 4 | return rhsType; | |
90 | } | ||
91 | // Allow ref type to type of the same contained type straight away | ||
92 |
9/12✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 94 times.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 14 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 13 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 107 times.
|
108 | if (rhsType.isRef() && lhsType.matches(rhsType.getContained(), false, false, true)) { |
93 | // In case of a return expression, we perform temp stealing | ||
94 |
4/10✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
|
1 | if (rhsType.getContained().is(TY_STRUCT) && !rhs.isTemporary()) |
95 | ✗ | typeChecker->implicitlyCallStructCopyCtor(rhs.entry, rhs.entry->declNode); | |
96 | 1 | return lhsType; | |
97 | } | ||
98 | // Allow const ref type to type of the same contained type straight away | ||
99 |
9/14✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 94 times.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 13 times.
✓ Branch 17 taken 94 times.
|
107 | if (rhsType.isConstRef() && lhsType.matches(rhsType.getContained().toNonConst(), false, false, true)) |
100 | 13 | return lhsType; | |
101 | // Allow immediate value to const ref of the same contained type straight away | ||
102 |
6/8✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 93 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 93 times.
|
94 | if (lhsType.isConstRef() && imm) |
103 | 1 | return rhsType; | |
104 | |||
105 | // Check common type combinations | ||
106 |
1/2✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
|
93 | const QualType resultType = getAssignResultTypeCommon(node, lhs, rhs, isDecl, false); |
107 |
3/4✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 89 times.
|
93 | if (!resultType.is(TY_INVALID)) |
108 | 4 | return resultType; | |
109 | |||
110 | // Check primitive type combinations | ||
111 |
2/2✓ Branch 1 taken 88 times.
✓ Branch 2 taken 1 times.
|
89 | return validateBinaryOperation(node, ASSIGN_OP_RULES, std::size(ASSIGN_OP_RULES), "=", lhsType, rhsType, true, |
112 | 88 | ERROR_FIELD_ASSIGN); | |
113 | } | ||
114 | |||
115 | 13571 | QualType OpRuleManager::getAssignResultTypeCommon(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, bool isDecl, | |
116 | bool isReturn) { | ||
117 | // Retrieve types | ||
118 | 13571 | const QualType lhsType = lhs.type; | |
119 | 13571 | const QualType rhsType = rhs.type; | |
120 | |||
121 | // Allow type to ref type of the same contained type straight away | ||
122 |
9/12✓ Branch 1 taken 13571 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 175 times.
✓ Branch 4 taken 13396 times.
✓ Branch 6 taken 175 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 175 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 172 times.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 172 times.
✓ Branch 14 taken 13399 times.
|
13571 | if (lhsType.isRef() && lhsType.getContained().matches(rhsType, false, false, true)) { |
123 |
4/4✓ Branch 0 taken 106 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 43 times.
|
172 | const bool isDeclOrReturn = isDecl || isReturn; |
124 |
7/8✓ Branch 0 taken 129 times.
✓ Branch 1 taken 43 times.
✓ Branch 4 taken 129 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 128 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 171 times.
|
172 | if (isDeclOrReturn && !lhsType.canBind(rhsType, rhs.isTemporary())) |
125 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
3 | throw SemanticError(node, TEMP_TO_NON_CONST_REF, "Temporary values can only be bound to const reference variables/fields"); |
126 | 171 | return lhsType; | |
127 | } | ||
128 | // Allow dyn[] (empty array literal) to any array | ||
129 |
8/10✓ Branch 1 taken 13399 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 13396 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 13397 times.
|
13399 | if (lhsType.isArray() && rhsType.isArrayOf(TY_DYN)) |
130 | 2 | return lhsType; | |
131 | // Allow char* = string | ||
132 |
9/14✓ Branch 1 taken 13397 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 13396 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✓ Branch 18 taken 13396 times.
|
13397 | if (lhsType.isPtrTo(TY_CHAR) && rhsType.is(TY_STRING) && lhsType.getSpecifiers() == rhsType.getSpecifiers()) |
133 | 1 | return lhsType; | |
134 | // Allow array to pointer | ||
135 |
12/18✓ Branch 1 taken 13396 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
✓ Branch 4 taken 13298 times.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 93 times.
✓ Branch 11 taken 5 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 5 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 5 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 5 times.
✓ Branch 22 taken 13391 times.
|
13396 | if (lhsType.isPtr() && rhsType.isArray() && lhsType.getContained().matches(rhsType.getContained(), false, false, true)) |
136 | 5 | return lhsType; | |
137 | // Allow interface* = struct* or interface& = struct that implements this interface | ||
138 |
1/2✓ Branch 3 taken 13391 times.
✗ Branch 4 not taken.
|
13391 | const bool sameChainDepth = Type::hasSameTypeChainDepth(lhsType.getType(), rhsType.getType()); |
139 |
10/14✓ Branch 1 taken 13391 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
✓ Branch 4 taken 13298 times.
✓ Branch 6 taken 93 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 92 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 92 times.
✓ Branch 13 taken 13299 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 13296 times.
|
13391 | const bool typesCompatible = (lhsType.isPtr() && rhsType.isPtr() && sameChainDepth) || lhsType.isRef(); |
140 |
9/12✓ Branch 0 taken 95 times.
✓ Branch 1 taken 13296 times.
✓ Branch 3 taken 95 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 90 times.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✓ Branch 13 taken 13386 times.
|
13391 | if (typesCompatible && lhsType.isBase(TY_INTERFACE) && rhsType.isBase(TY_STRUCT)) { |
141 | 5 | QualType lhsTypeCopy = lhsType; | |
142 | 5 | QualType rhsTypeCopy = rhsType; | |
143 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | QualType::unwrapBoth(lhsTypeCopy, rhsTypeCopy); |
144 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | if (lhsTypeCopy.matchesInterfaceImplementedByStruct(rhsTypeCopy)) |
145 | 5 | return lhsType; | |
146 | } | ||
147 | // Allow type* = heap type* straight away. This is used for initializing non-owning pointers to heap allocations | ||
148 |
10/14✓ Branch 1 taken 13386 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89 times.
✓ Branch 4 taken 13297 times.
✓ Branch 6 taken 89 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 88 times.
✓ Branch 9 taken 1 times.
✓ Branch 11 taken 88 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 88 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 88 times.
✓ Branch 16 taken 13298 times.
|
13386 | if (lhsType.isPtr() && rhsType.isHeap() && lhsType.matches(rhsType, false, true, true)) { |
149 | 88 | TypeSpecifiers rhsSpecifiers = rhsType.getSpecifiers(); | |
150 | 88 | rhsSpecifiers.isHeap = false; | |
151 |
2/4✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
|
88 | if (lhsType.getSpecifiers() == rhsSpecifiers) |
152 | 88 | return lhsType; | |
153 | } | ||
154 | |||
155 | // Nothing matched | ||
156 |
1/2✓ Branch 1 taken 13298 times.
✗ Branch 2 not taken.
|
13298 | return QualType(TY_INVALID); |
157 | } | ||
158 | |||
159 | 213 | ExprResult OpRuleManager::getPlusEqualResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
160 | // Check is there is an overloaded operator function available | ||
161 |
1/2✓ Branch 1 taken 213 times.
✗ Branch 2 not taken.
|
213 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_PLUS_EQUAL, {lhs, rhs}, opIdx); |
162 |
3/4✓ Branch 1 taken 213 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 79 times.
✓ Branch 4 taken 134 times.
|
213 | if (!resultType.type.is(TY_INVALID)) |
163 | 79 | return resultType; | |
164 | |||
165 | // Check if we try to assign a constant value | ||
166 |
1/2✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
|
134 | ensureNoConstAssign(node, lhs.type); |
167 | |||
168 | // Remove reference wrappers | ||
169 |
1/2✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
|
134 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
170 |
1/2✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
|
134 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
171 | |||
172 | // Check if this is an unsafe operation | ||
173 |
7/10✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 133 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 133 times.
|
134 | if (lhsType.isPtr() && rhsType.isOneOf({TY_INT, TY_LONG, TY_SHORT})) { |
174 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ensureUnsafeAllowed(node, "+=", lhsType, rhsType); |
175 | 1 | return {lhs}; | |
176 | } | ||
177 | |||
178 |
1/2✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
|
133 | return {validateBinaryOperation(node, PLUS_EQUAL_OP_RULES, std::size(PLUS_EQUAL_OP_RULES), "+=", lhsType, rhsType)}; |
179 | } | ||
180 | |||
181 | 27 | ExprResult OpRuleManager::getMinusEqualResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
182 | // Check is there is an overloaded operator function available | ||
183 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_MINUS_EQUAL, {lhs, rhs}, opIdx); |
184 |
3/4✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 20 times.
|
27 | if (!resultType.type.is(TY_INVALID)) |
185 | 7 | return resultType; | |
186 | |||
187 | // Check if we try to assign a constant value | ||
188 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | ensureNoConstAssign(node, lhs.type); |
189 | |||
190 | // Remove reference wrappers | ||
191 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
192 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
193 | |||
194 | // Check if this is an unsafe operation | ||
195 |
7/10✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 19 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 19 times.
|
20 | if (lhsType.isPtr() && rhsType.isOneOf({TY_INT, TY_LONG, TY_SHORT})) { |
196 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ensureUnsafeAllowed(node, "-=", lhsType, rhsType); |
197 | 1 | return {lhs}; | |
198 | } | ||
199 | |||
200 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | return {validateBinaryOperation(node, MINUS_EQUAL_OP_RULES, std::size(MINUS_EQUAL_OP_RULES), "-=", lhsType, rhsType)}; |
201 | } | ||
202 | |||
203 | 15 | ExprResult OpRuleManager::getMulEqualResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
204 | // Check is there is an overloaded operator function available | ||
205 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_MUL_EQUAL, {lhs, rhs}, opIdx); |
206 |
3/4✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 13 times.
|
15 | if (!resultType.type.is(TY_INVALID)) |
207 | 2 | return resultType; | |
208 | |||
209 | // Check if we try to assign a constant value | ||
210 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | ensureNoConstAssign(node, lhs.type); |
211 | |||
212 | // Remove reference wrappers | ||
213 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
214 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
215 | |||
216 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | return {validateBinaryOperation(node, MUL_EQUAL_OP_RULES, std::size(MUL_EQUAL_OP_RULES), "*=", lhsType, rhsType)}; |
217 | } | ||
218 | |||
219 | 35 | ExprResult OpRuleManager::getDivEqualResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
220 | // Check is there is an overloaded operator function available | ||
221 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
35 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_DIV_EQUAL, {lhs, rhs}, opIdx); |
222 |
3/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
✓ Branch 4 taken 3 times.
|
35 | if (!resultType.type.is(TY_INVALID)) |
223 | 32 | return resultType; | |
224 | |||
225 | // Check if we try to assign a constant value | ||
226 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | ensureNoConstAssign(node, lhs.type); |
227 | |||
228 | // Remove reference wrappers | ||
229 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
230 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
231 | |||
232 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | return {validateBinaryOperation(node, DIV_EQUAL_OP_RULES, std::size(DIV_EQUAL_OP_RULES), "/=", lhsType, rhsType)}; |
233 | } | ||
234 | |||
235 | 5 | QualType OpRuleManager::getRemEqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
236 | // Check if we try to assign a constant value | ||
237 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | ensureNoConstAssign(node, lhs.type); |
238 | |||
239 | // Remove reference wrappers | ||
240 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
241 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
242 | |||
243 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
10 | return validateBinaryOperation(node, REM_EQUAL_OP_RULES, std::size(REM_EQUAL_OP_RULES), "%=", lhsType, rhsType); |
244 | } | ||
245 | |||
246 | 1 | QualType OpRuleManager::getSHLEqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
247 | // Check if we try to assign a constant value | ||
248 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ensureNoConstAssign(node, lhs.type); |
249 | |||
250 | // Remove reference wrappers | ||
251 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
252 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
253 | |||
254 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | return validateBinaryOperation(node, SHL_EQUAL_OP_RULES, std::size(SHL_EQUAL_OP_RULES), "<<=", lhsType, rhsType); |
255 | } | ||
256 | |||
257 | 2 | QualType OpRuleManager::getSHREqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
258 | // Check if we try to assign a constant value | ||
259 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | ensureNoConstAssign(node, lhs.type); |
260 | |||
261 | // Remove reference wrappers | ||
262 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
263 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
264 | |||
265 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | return validateBinaryOperation(node, SHR_EQUAL_OP_RULES, std::size(SHR_EQUAL_OP_RULES), ">>=", lhsType, rhsType); |
266 | } | ||
267 | |||
268 | 1 | QualType OpRuleManager::getAndEqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
269 | // Check if we try to assign a constant value | ||
270 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ensureNoConstAssign(node, lhs.type); |
271 | |||
272 | // Remove reference wrappers | ||
273 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
274 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
275 | |||
276 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | return validateBinaryOperation(node, AND_EQUAL_OP_RULES, std::size(AND_EQUAL_OP_RULES), "&=", lhsType, rhsType); |
277 | } | ||
278 | |||
279 | 1 | QualType OpRuleManager::getOrEqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
280 | // Check if we try to assign a constant value | ||
281 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ensureNoConstAssign(node, lhs.type); |
282 | |||
283 | // Remove reference wrappers | ||
284 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
285 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
286 | |||
287 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | return validateBinaryOperation(node, OR_EQUAL_OP_RULES, std::size(OR_EQUAL_OP_RULES), "|=", lhsType, rhsType); |
288 | } | ||
289 | |||
290 | 231 | QualType OpRuleManager::getXorEqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
291 | // Check if we try to assign a constant value | ||
292 |
1/2✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
|
231 | ensureNoConstAssign(node, lhs.type); |
293 | |||
294 | // Remove reference wrappers | ||
295 |
1/2✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
|
231 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
296 |
1/2✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
|
231 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
297 | |||
298 |
1/2✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
|
462 | return validateBinaryOperation(node, XOR_EQUAL_OP_RULES, std::size(XOR_EQUAL_OP_RULES), "^=", lhsType, rhsType); |
299 | } | ||
300 | |||
301 | 288 | QualType OpRuleManager::getLogicalOrResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
302 | // Remove reference wrappers | ||
303 |
1/2✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
|
288 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
304 |
1/2✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
|
288 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
305 | |||
306 |
2/2✓ Branch 1 taken 287 times.
✓ Branch 2 taken 1 times.
|
575 | return validateBinaryOperation(node, LOGICAL_OR_OP_RULES, std::size(LOGICAL_OR_OP_RULES), "||", lhsType, rhsType); |
307 | } | ||
308 | |||
309 | 65 | QualType OpRuleManager::getLogicalAndResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
310 | // Remove reference wrappers | ||
311 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
312 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
313 | |||
314 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
130 | return validateBinaryOperation(node, LOGICAL_AND_OP_RULES, std::size(LOGICAL_AND_OP_RULES), "&&", lhsType, rhsType); |
315 | } | ||
316 | |||
317 | 36 | QualType OpRuleManager::getBitwiseOrResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
318 | // Remove reference wrappers | ||
319 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
320 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
321 | |||
322 |
2/2✓ Branch 1 taken 35 times.
✓ Branch 2 taken 1 times.
|
71 | return validateBinaryOperation(node, BITWISE_OR_OP_RULES, std::size(BITWISE_OR_OP_RULES), "|", lhsType, rhsType); |
323 | } | ||
324 | |||
325 | 7 | QualType OpRuleManager::getBitwiseXorResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
326 | // Remove reference wrappers | ||
327 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
328 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
329 | |||
330 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
14 | return validateBinaryOperation(node, BITWISE_XOR_OP_RULES, std::size(BITWISE_XOR_OP_RULES), "^", lhsType, rhsType); |
331 | } | ||
332 | |||
333 | 33 | QualType OpRuleManager::getBitwiseAndResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
334 | // Remove reference wrappers | ||
335 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
33 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
336 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
33 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
337 | |||
338 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
66 | return validateBinaryOperation(node, BITWISE_AND_OP_RULES, std::size(BITWISE_AND_OP_RULES), "&", lhsType, rhsType); |
339 | } | ||
340 | |||
341 | 2379 | ExprResult OpRuleManager::getEqualResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
342 | // Check is there is an overloaded operator function available | ||
343 |
1/2✓ Branch 1 taken 2379 times.
✗ Branch 2 not taken.
|
2379 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_EQUAL, {lhs, rhs}, opIdx); |
344 |
3/4✓ Branch 1 taken 2379 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 357 times.
✓ Branch 4 taken 2022 times.
|
2379 | if (!resultType.type.is(TY_INVALID)) |
345 | 357 | return resultType; | |
346 | |||
347 | // Remove reference wrappers | ||
348 |
1/2✓ Branch 1 taken 2022 times.
✗ Branch 2 not taken.
|
2022 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
349 |
1/2✓ Branch 1 taken 2022 times.
✗ Branch 2 not taken.
|
2022 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
350 | |||
351 | // Allow 'pointer == pointer' straight away | ||
352 |
7/10✓ Branch 1 taken 2022 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 593 times.
✓ Branch 4 taken 1429 times.
✓ Branch 6 taken 593 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 593 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 593 times.
✓ Branch 11 taken 1429 times.
|
2022 | if (lhsType.isPtr() && rhsType.isPtr()) |
353 |
1/2✓ Branch 1 taken 593 times.
✗ Branch 2 not taken.
|
593 | return ExprResult(QualType(TY_BOOL)); |
354 | |||
355 | // Allow 'pointer == int' straight away | ||
356 |
3/10✓ Branch 1 taken 1429 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1429 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1429 times.
|
1429 | if (lhsType.isPtr() && rhsType.is(TY_INT)) |
357 | ✗ | return ExprResult(QualType(TY_BOOL)); | |
358 | |||
359 | // Allow 'string == char*' and vice versa straight away | ||
360 |
8/18✓ Branch 1 taken 1429 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 119 times.
✓ Branch 4 taken 1310 times.
✓ Branch 6 taken 119 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 119 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1429 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1429 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 1429 times.
|
1429 | if ((lhsType.is(TY_STRING) && rhsType.isPtrTo(TY_CHAR)) || (lhsType.isPtrTo(TY_CHAR) && rhsType.is(TY_STRING))) |
361 | ✗ | return ExprResult(QualType(TY_BOOL)); | |
362 | |||
363 | // Check primitive type combinations | ||
364 |
2/2✓ Branch 1 taken 1428 times.
✓ Branch 2 taken 1 times.
|
1429 | return ExprResult(validateBinaryOperation(node, EQUAL_OP_RULES, std::size(EQUAL_OP_RULES), "==", lhsType, rhsType)); |
365 | } | ||
366 | |||
367 | 1315 | ExprResult OpRuleManager::getNotEqualResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
368 | // Check is there is an overloaded operator function available | ||
369 |
1/2✓ Branch 1 taken 1315 times.
✗ Branch 2 not taken.
|
1315 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_NOT_EQUAL, {lhs, rhs}, opIdx); |
370 |
3/4✓ Branch 1 taken 1315 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1305 times.
|
1315 | if (!resultType.type.is(TY_INVALID)) |
371 | 10 | return resultType; | |
372 | |||
373 | // Remove reference wrappers | ||
374 |
1/2✓ Branch 1 taken 1305 times.
✗ Branch 2 not taken.
|
1305 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
375 |
1/2✓ Branch 1 taken 1305 times.
✗ Branch 2 not taken.
|
1305 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
376 | |||
377 | // Allow 'pointer != pointer' straight away | ||
378 |
7/10✓ Branch 1 taken 1305 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 146 times.
✓ Branch 4 taken 1159 times.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 146 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 146 times.
✓ Branch 11 taken 1159 times.
|
1305 | if (lhsType.isPtr() && rhsType.isPtr()) |
379 |
1/2✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
|
146 | return ExprResult(QualType(TY_BOOL)); |
380 | |||
381 | // Allow 'pointer != int' straight away | ||
382 |
3/10✓ Branch 1 taken 1159 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1159 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1159 times.
|
1159 | if (lhsType.isPtr() && rhsType.is(TY_INT)) |
383 | ✗ | return ExprResult(QualType(TY_BOOL)); | |
384 | |||
385 | // Allow 'string != char*' and vice versa straight away | ||
386 |
8/18✓ Branch 1 taken 1159 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 1148 times.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1159 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1159 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 1159 times.
|
1159 | if ((lhsType.is(TY_STRING) && rhsType.isPtrTo(TY_CHAR)) || (lhsType.isPtrTo(TY_CHAR) && rhsType.is(TY_STRING))) |
387 | ✗ | return ExprResult(QualType(TY_BOOL)); | |
388 | |||
389 | // Check primitive type combinations | ||
390 |
1/2✓ Branch 1 taken 1159 times.
✗ Branch 2 not taken.
|
1159 | return ExprResult(validateBinaryOperation(node, NOT_EQUAL_OP_RULES, std::size(NOT_EQUAL_OP_RULES), "!=", lhsType, rhsType)); |
391 | } | ||
392 | |||
393 | 1476 | QualType OpRuleManager::getLessResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
394 | // Remove reference wrappers | ||
395 |
1/2✓ Branch 1 taken 1476 times.
✗ Branch 2 not taken.
|
1476 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
396 |
1/2✓ Branch 1 taken 1476 times.
✗ Branch 2 not taken.
|
1476 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
397 | |||
398 |
1/2✓ Branch 1 taken 1476 times.
✗ Branch 2 not taken.
|
2952 | return validateBinaryOperation(node, LESS_OP_RULES, std::size(LESS_OP_RULES), "<", lhsType, rhsType); |
399 | } | ||
400 | |||
401 | 246 | QualType OpRuleManager::getGreaterResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
402 | // Remove reference wrappers | ||
403 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
404 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
405 | |||
406 |
2/2✓ Branch 1 taken 245 times.
✓ Branch 2 taken 1 times.
|
491 | return validateBinaryOperation(node, GREATER_OP_RULES, std::size(GREATER_OP_RULES), ">", lhsType, rhsType); |
407 | } | ||
408 | |||
409 | 263 | QualType OpRuleManager::getLessEqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
410 | // Remove reference wrappers | ||
411 |
1/2✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
|
263 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
412 |
1/2✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
|
263 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
413 | |||
414 |
1/2✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
|
526 | return validateBinaryOperation(node, LESS_EQUAL_OP_RULES, std::size(LESS_EQUAL_OP_RULES), "<=", lhsType, rhsType); |
415 | } | ||
416 | |||
417 | 564 | QualType OpRuleManager::getGreaterEqualResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
418 | // Remove reference wrappers | ||
419 |
1/2✓ Branch 1 taken 564 times.
✗ Branch 2 not taken.
|
564 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
420 |
1/2✓ Branch 1 taken 564 times.
✗ Branch 2 not taken.
|
564 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
421 | |||
422 |
1/2✓ Branch 1 taken 564 times.
✗ Branch 2 not taken.
|
1128 | return validateBinaryOperation(node, GREATER_EQUAL_OP_RULES, std::size(GREATER_EQUAL_OP_RULES), ">=", lhsType, rhsType); |
423 | } | ||
424 | |||
425 | 10 | ExprResult OpRuleManager::getShiftLeftResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
426 | // Check is there is an overloaded operator function available | ||
427 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_SHL, {lhs, rhs}, opIdx); |
428 |
3/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 9 times.
|
10 | if (!resultType.type.is(TY_INVALID)) |
429 | 1 | return resultType; | |
430 | |||
431 | // Remove reference wrappers | ||
432 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
433 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
434 | |||
435 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | return {validateBinaryOperation(node, SHIFT_LEFT_OP_RULES, std::size(SHIFT_LEFT_OP_RULES), "<<", lhsType, rhsType)}; |
436 | } | ||
437 | |||
438 | 7 | ExprResult OpRuleManager::getShiftRightResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
439 | // Check is there is an overloaded operator function available | ||
440 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_SHR, {lhs, rhs}, opIdx); |
441 |
3/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 6 times.
|
7 | if (!resultType.type.is(TY_INVALID)) |
442 | 1 | return resultType; | |
443 | |||
444 | // Remove reference wrappers | ||
445 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
446 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
447 | |||
448 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | return {validateBinaryOperation(node, SHIFT_RIGHT_OP_RULES, std::size(SHIFT_RIGHT_OP_RULES), ">>", lhsType, rhsType)}; |
449 | } | ||
450 | |||
451 | 2178 | ExprResult OpRuleManager::getPlusResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
452 | // Check is there is an overloaded operator function available | ||
453 |
1/2✓ Branch 1 taken 2178 times.
✗ Branch 2 not taken.
|
2178 | const ExprResult result = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_PLUS, {lhs, rhs}, opIdx); |
454 |
3/4✓ Branch 1 taken 2178 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 2132 times.
|
2178 | if (!result.type.is(TY_INVALID)) |
455 | 46 | return result; | |
456 | |||
457 | // Remove reference wrappers | ||
458 |
1/2✓ Branch 1 taken 2132 times.
✗ Branch 2 not taken.
|
2132 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
459 |
1/2✓ Branch 1 taken 2132 times.
✗ Branch 2 not taken.
|
2132 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
460 | |||
461 | // Allow any* + <int/long/short> | ||
462 |
7/10✓ Branch 1 taken 2132 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 462 times.
✓ Branch 4 taken 1670 times.
✓ Branch 6 taken 462 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 462 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 462 times.
✓ Branch 11 taken 1670 times.
|
2132 | if (lhsType.isPtr() && rhsType.isOneOf({TY_INT, TY_LONG, TY_SHORT})) { |
463 |
1/2✓ Branch 1 taken 462 times.
✗ Branch 2 not taken.
|
462 | ensureUnsafeAllowed(node, "+", lhsType, rhsType); |
464 | 462 | return {lhsType}; | |
465 | } | ||
466 | // Allow <int/long/short> + any* | ||
467 |
6/10✓ Branch 1 taken 1670 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1635 times.
✓ Branch 4 taken 35 times.
✓ Branch 6 taken 1635 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1635 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1670 times.
|
1670 | if (lhsType.isOneOf({TY_INT, TY_LONG, TY_SHORT}) && rhsType.isPtr()) { |
468 | ✗ | ensureUnsafeAllowed(node, "+", lhsType, rhsType); | |
469 | ✗ | return {rhsType}; | |
470 | } | ||
471 | |||
472 |
2/2✓ Branch 1 taken 1669 times.
✓ Branch 2 taken 1 times.
|
1670 | return {validateBinaryOperation(node, PLUS_OP_RULES, std::size(PLUS_OP_RULES), "+", lhsType, rhsType)}; |
473 | } | ||
474 | |||
475 | 1259 | ExprResult OpRuleManager::getMinusResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
476 | // Check is there is an overloaded operator function available | ||
477 |
1/2✓ Branch 1 taken 1259 times.
✗ Branch 2 not taken.
|
1259 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_MINUS, {lhs, rhs}, opIdx); |
478 |
3/4✓ Branch 1 taken 1259 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1258 times.
|
1259 | if (!resultType.type.is(TY_INVALID)) |
479 | 1 | return resultType; | |
480 | |||
481 | // Remove reference wrappers | ||
482 |
1/2✓ Branch 1 taken 1258 times.
✗ Branch 2 not taken.
|
1258 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
483 |
1/2✓ Branch 1 taken 1258 times.
✗ Branch 2 not taken.
|
1258 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
484 | |||
485 | // Allow any* - <int/long/short> | ||
486 |
3/10✓ Branch 1 taken 1258 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1258 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1258 times.
|
1258 | if (lhsType.isPtr() && rhsType.isOneOf({TY_INT, TY_LONG, TY_SHORT})) { |
487 | ✗ | ensureUnsafeAllowed(node, "-", lhsType, rhsType); | |
488 | ✗ | return {lhs}; | |
489 | } | ||
490 | // Allow <int/long/short> - any* | ||
491 |
6/10✓ Branch 1 taken 1258 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1250 times.
✓ Branch 4 taken 8 times.
✓ Branch 6 taken 1250 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1250 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1258 times.
|
1258 | if (lhsType.isOneOf({TY_INT, TY_LONG, TY_SHORT}) && rhsType.isPtr()) { |
492 | ✗ | ensureUnsafeAllowed(node, "-", lhsType, rhsType); | |
493 | ✗ | return {rhs}; | |
494 | } | ||
495 | |||
496 |
1/2✓ Branch 1 taken 1258 times.
✗ Branch 2 not taken.
|
1258 | return {validateBinaryOperation(node, MINUS_OP_RULES, std::size(MINUS_OP_RULES), "-", lhsType, rhsType)}; |
497 | } | ||
498 | |||
499 | 654 | ExprResult OpRuleManager::getMulResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
500 | // Check is there is an overloaded operator function available | ||
501 |
1/2✓ Branch 1 taken 654 times.
✗ Branch 2 not taken.
|
654 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_MUL, {lhs, rhs}, opIdx); |
502 |
3/4✓ Branch 1 taken 654 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 645 times.
|
654 | if (!resultType.type.is(TY_INVALID)) |
503 | 9 | return resultType; | |
504 | |||
505 | // Remove reference wrappers | ||
506 |
1/2✓ Branch 1 taken 645 times.
✗ Branch 2 not taken.
|
645 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
507 |
1/2✓ Branch 1 taken 645 times.
✗ Branch 2 not taken.
|
645 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
508 | |||
509 |
2/2✓ Branch 1 taken 644 times.
✓ Branch 2 taken 1 times.
|
645 | return {validateBinaryOperation(node, MUL_OP_RULES, std::size(MUL_OP_RULES), "*", lhsType, rhsType)}; |
510 | } | ||
511 | |||
512 | 205 | ExprResult OpRuleManager::getDivResultType(ASTNode *node, const ExprResult &lhs, const ExprResult &rhs, size_t opIdx) { | |
513 | // Check is there is an overloaded operator function available | ||
514 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | const ExprResult resultType = isOperatorOverloadingFctAvailable<2>(node, OP_FCT_DIV, {lhs, rhs}, opIdx); |
515 |
3/4✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 202 times.
|
205 | if (!resultType.type.is(TY_INVALID)) |
516 | 3 | return resultType; | |
517 | |||
518 | // Remove reference wrappers | ||
519 |
1/2✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
|
202 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
520 |
1/2✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
|
202 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
521 | |||
522 |
1/2✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
|
202 | return {validateBinaryOperation(node, DIV_OP_RULES, std::size(DIV_OP_RULES), "/", lhsType, rhsType)}; |
523 | } | ||
524 | |||
525 | 9 | ExprResult OpRuleManager::getRemResultType(const ASTNode *node, const ExprResult &lhs, const ExprResult &rhs) { | |
526 | // Remove reference wrappers | ||
527 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
528 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | const QualType rhsType = rhs.type.removeReferenceWrapper(); |
529 | |||
530 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
18 | return {validateBinaryOperation(node, REM_OP_RULES, std::size(REM_OP_RULES), "%", lhsType, rhsType)}; |
531 | } | ||
532 | |||
533 | 16 | QualType OpRuleManager::getPrefixMinusResultType(const ASTNode *node, const ExprResult &lhs) { | |
534 | // Remove reference wrappers | ||
535 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
536 | |||
537 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
32 | return validateUnaryOperation(node, PREFIX_MINUS_OP_RULES, std::size(PREFIX_MINUS_OP_RULES), "-", lhsType); |
538 | } | ||
539 | |||
540 | 28 | QualType OpRuleManager::getPrefixPlusPlusResultType(const ASTNode *node, const ExprResult &lhs) const { | |
541 | // Check if we try to assign a constant value | ||
542 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | ensureNoConstAssign(node, lhs.type); |
543 | |||
544 | // Remove reference wrappers | ||
545 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
546 | |||
547 | // Check if this is an unsafe operation | ||
548 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
|
28 | if (lhsType.isPtr()) { |
549 | ✗ | ensureUnsafeAllowed(node, "++", lhsType); | |
550 | ✗ | return lhsType; | |
551 | } | ||
552 | |||
553 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | return validateUnaryOperation(node, PREFIX_PLUS_PLUS_OP_RULES, std::size(PREFIX_PLUS_PLUS_OP_RULES), "++", lhsType); |
554 | } | ||
555 | |||
556 | 7 | QualType OpRuleManager::getPrefixMinusMinusResultType(const ASTNode *node, const ExprResult &lhs) const { | |
557 | // Check if we try to assign a constant value | ||
558 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | ensureNoConstAssign(node, lhs.type); |
559 | |||
560 | // Remove reference wrappers | ||
561 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
562 | |||
563 | // Check if this is an unsafe operation | ||
564 |
2/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
|
7 | if (lhsType.isPtr()) { |
565 | ✗ | ensureUnsafeAllowed(node, "--", lhsType); | |
566 | ✗ | return lhsType; | |
567 | } | ||
568 | |||
569 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
|
7 | return validateUnaryOperation(node, PREFIX_MINUS_MINUS_OP_RULES, std::size(PREFIX_MINUS_MINUS_OP_RULES), "--", lhsType); |
570 | } | ||
571 | |||
572 | 561 | QualType OpRuleManager::getPrefixNotResultType(const ASTNode *node, const ExprResult &lhs) { | |
573 | // Remove reference wrappers | ||
574 |
1/2✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
|
561 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
575 | |||
576 |
1/2✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
|
1122 | return validateUnaryOperation(node, PREFIX_NOT_OP_RULES, std::size(PREFIX_NOT_OP_RULES), "!", lhsType); |
577 | } | ||
578 | |||
579 | 1 | QualType OpRuleManager::getPrefixBitwiseNotResultType(const ASTNode *node, const ExprResult &lhs) { | |
580 | // Remove reference wrappers | ||
581 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
582 | |||
583 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | return validateUnaryOperation(node, PREFIX_BITWISE_NOT_OP_RULES, std::size(PREFIX_BITWISE_NOT_OP_RULES), "~", lhsType); |
584 | } | ||
585 | |||
586 | 162 | QualType OpRuleManager::getPrefixMulResultType(const ASTNode *node, const ExprResult &lhs) { | |
587 | // Remove reference wrappers | ||
588 |
1/2✓ Branch 1 taken 162 times.
✗ Branch 2 not taken.
|
162 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
589 | |||
590 |
2/4✓ Branch 1 taken 162 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 162 times.
|
162 | if (!lhsType.isPtr()) |
591 | ✗ | throw SemanticError(node, OPERATOR_WRONG_DATA_TYPE, "Cannot apply de-referencing operator on type " + lhsType.getName(true)); | |
592 |
1/2✓ Branch 1 taken 162 times.
✗ Branch 2 not taken.
|
324 | return lhsType.getContained(); |
593 | } | ||
594 | |||
595 | 63 | QualType OpRuleManager::getPrefixBitwiseAndResultType(const ASTNode *node, const ExprResult &lhs) { | |
596 | // Remove reference wrappers | ||
597 |
1/2✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
|
63 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
598 | |||
599 |
1/2✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
|
126 | return lhsType.toPtr(node); |
600 | } | ||
601 | |||
602 | 1353 | ExprResult OpRuleManager::getPostfixPlusPlusResultType(ASTNode *node, const ExprResult &lhs, size_t opIdx) { | |
603 | // Check is there is an overloaded operator function available | ||
604 |
1/2✓ Branch 1 taken 1353 times.
✗ Branch 2 not taken.
|
1353 | const ExprResult resultType = isOperatorOverloadingFctAvailable<1>(node, OP_FCT_POSTFIX_PLUS_PLUS, {lhs}, opIdx); |
605 |
3/4✓ Branch 1 taken 1353 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1344 times.
|
1353 | if (!resultType.type.is(TY_INVALID)) |
606 | 9 | return resultType; | |
607 | |||
608 | // Check if we try to assign a constant value | ||
609 |
1/2✓ Branch 1 taken 1344 times.
✗ Branch 2 not taken.
|
1344 | ensureNoConstAssign(node, lhs.type); |
610 | |||
611 | // Remove reference wrappers | ||
612 |
1/2✓ Branch 1 taken 1344 times.
✗ Branch 2 not taken.
|
1344 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
613 | |||
614 | // Check if this is an unsafe operation | ||
615 |
3/4✓ Branch 1 taken 1344 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1343 times.
|
1344 | if (lhsType.isPtr()) { |
616 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ensureUnsafeAllowed(node, "++", lhsType); |
617 | 1 | return {lhs}; | |
618 | } | ||
619 | |||
620 |
2/2✓ Branch 1 taken 1342 times.
✓ Branch 2 taken 1 times.
|
1343 | return {validateUnaryOperation(node, POSTFIX_PLUS_PLUS_OP_RULES, std::size(POSTFIX_PLUS_PLUS_OP_RULES), "++", lhsType)}; |
621 | } | ||
622 | |||
623 | 270 | ExprResult OpRuleManager::getPostfixMinusMinusResultType(ASTNode *node, const ExprResult &lhs, size_t opIdx) { | |
624 | // Check is there is an overloaded operator function available | ||
625 |
1/2✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
|
270 | const ExprResult resultType = isOperatorOverloadingFctAvailable<1>(node, OP_FCT_POSTFIX_MINUS_MINUS, {lhs}, opIdx); |
626 |
3/4✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 264 times.
|
270 | if (!resultType.type.is(TY_INVALID)) |
627 | 6 | return resultType; | |
628 | |||
629 | // Check if we try to assign a constant value | ||
630 |
1/2✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
|
264 | ensureNoConstAssign(node, lhs.type); |
631 | |||
632 | // Remove reference wrappers | ||
633 |
1/2✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
|
264 | const QualType lhsType = lhs.type.removeReferenceWrapper(); |
634 | |||
635 | // Check if this is an unsafe operation | ||
636 |
3/4✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 263 times.
|
264 | if (lhsType.isPtr()) { |
637 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ensureUnsafeAllowed(node, "--", lhsType); |
638 | 1 | return {lhs}; | |
639 | } | ||
640 | |||
641 |
1/2✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
|
263 | return {validateUnaryOperation(node, POSTFIX_MINUS_MINUS_OP_RULES, std::size(POSTFIX_MINUS_MINUS_OP_RULES), "--", lhsType)}; |
642 | } | ||
643 | |||
644 | 2357 | QualType OpRuleManager::getCastResultType(const ASTNode *node, QualType lhsType, const ExprResult &rhs) const { | |
645 | // Remove reference wrappers | ||
646 |
1/2✓ Branch 1 taken 2357 times.
✗ Branch 2 not taken.
|
2357 | lhsType = lhsType.removeReferenceWrapper(); |
647 |
1/2✓ Branch 1 taken 2357 times.
✗ Branch 2 not taken.
|
2357 | QualType rhsType = rhs.type.removeReferenceWrapper(); |
648 | |||
649 | // Only allow to cast the 'heap' specifier away, if we are in unsafe mode | ||
650 |
2/2✓ Branch 2 taken 91 times.
✓ Branch 3 taken 2266 times.
|
2357 | if (lhsType.getSpecifiers().isHeap != rhsType.getSpecifiers().isHeap) |
651 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); |
652 | |||
653 | // Allow identity casts | ||
654 |
3/4✓ Branch 1 taken 2357 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1006 times.
✓ Branch 4 taken 1351 times.
|
2357 | if (lhsType.matches(rhsType, false, true, true)) |
655 | 1006 | return lhsType; | |
656 | // Allow casts string -> char* and string -> char[] | ||
657 |
12/16✓ Branch 1 taken 1351 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 900 times.
✓ Branch 4 taken 451 times.
✓ Branch 6 taken 900 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 900 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 707 times.
✓ Branch 12 taken 193 times.
✓ Branch 14 taken 707 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 703 times.
✓ Branch 17 taken 4 times.
✓ Branch 18 taken 703 times.
✓ Branch 19 taken 648 times.
|
1351 | if (lhsType.isOneOf({TY_PTR, TY_ARRAY}) && lhsType.getContained().is(TY_CHAR) && rhsType.is(TY_STRING)) |
658 | 703 | return lhsType; | |
659 | // Allow casts char* -> string and char[] -> string | ||
660 |
10/16✓ Branch 1 taken 648 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
✓ Branch 4 taken 571 times.
✓ Branch 6 taken 77 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 77 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 77 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 77 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 77 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 77 times.
✓ Branch 19 taken 571 times.
|
648 | if (lhsType.is(TY_STRING) && rhsType.isOneOf({TY_PTR, TY_ARRAY}) && rhsType.getContained().is(TY_CHAR)) |
661 | 77 | return lhsType; | |
662 | // Allow casts any* -> any* | ||
663 |
7/10✓ Branch 1 taken 571 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 197 times.
✓ Branch 4 taken 374 times.
✓ Branch 6 taken 197 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 197 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 197 times.
✓ Branch 11 taken 374 times.
|
571 | if (lhsType.isOneOf({TY_PTR, TY_STRING}) && rhsType.isOneOf({TY_PTR, TY_STRING})) { |
664 |
2/4✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 197 times.
✗ Branch 4 not taken.
|
197 | if (lhsType != rhsType) |
665 |
1/2✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
|
197 | ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); |
666 | 197 | return lhsType; | |
667 | } | ||
668 | // Check primitive type combinations | ||
669 |
1/2✓ Branch 1 taken 374 times.
✗ Branch 2 not taken.
|
374 | return validateBinaryOperation(node, CAST_OP_RULES, std::size(CAST_OP_RULES), "(cast)", lhsType, rhsType, true); |
670 | } | ||
671 | |||
672 | template <size_t N> | ||
673 | 19840 | ExprResult OpRuleManager::isOperatorOverloadingFctAvailable(ASTNode *node, const char *const fctName, | |
674 | const std::array<ExprResult, N> &op, size_t opIdx) { | ||
675 | 19840 | Scope *calleeParentScope = nullptr; | |
676 | 19840 | const Function *callee = nullptr; | |
677 |
7/10✓ Branch 1 taken 9920 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9920 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9920 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 27464 times.
✓ Branch 12 taken 563 times.
✓ Branch 15 taken 68581 times.
✓ Branch 16 taken 9357 times.
|
211930 | for (const auto &sourceFile : typeChecker->resourceManager.sourceFiles | std::views::values) { |
678 | // Check if there is a registered operator function | ||
679 |
4/6✓ Branch 2 taken 68581 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 68581 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 40554 times.
✓ Branch 9 taken 28027 times.
|
411486 | if (!sourceFile->getNameRegistryEntry(fctName)) |
680 | 81108 | continue; | |
681 | |||
682 | // Match callees in the global scope of this source file | ||
683 | 56054 | calleeParentScope = sourceFile->globalScope.get(); | |
684 |
1/2✓ Branch 1 taken 28027 times.
✗ Branch 2 not taken.
|
56054 | const QualType thisType(TY_DYN); |
685 |
1/2✓ Branch 1 taken 28027 times.
✗ Branch 2 not taken.
|
56054 | ArgList args(N); |
686 |
1/2✓ Branch 2 taken 28027 times.
✗ Branch 3 not taken.
|
56054 | args[0] = {typeChecker->mapLocalTypeToImportedScopeType(calleeParentScope, op[0].type), op[0].isTemporary()}; |
687 | if constexpr (N == 2) | ||
688 |
1/2✓ Branch 2 taken 26592 times.
✗ Branch 3 not taken.
|
53184 | args[1] = {typeChecker->mapLocalTypeToImportedScopeType(calleeParentScope, op[1].type), op[1].isTemporary()}; |
689 |
2/4✓ Branch 2 taken 28027 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28027 times.
✗ Branch 6 not taken.
|
168162 | callee = FunctionManager::match(typeChecker, calleeParentScope, fctName, thisType, args, {}, false, node); |
690 |
2/2✓ Branch 0 taken 563 times.
✓ Branch 1 taken 27464 times.
|
56054 | if (callee) |
691 | 1126 | break; | |
692 | } | ||
693 | |||
694 | // Return invalid type if the callee was not found | ||
695 |
2/2✓ Branch 0 taken 9357 times.
✓ Branch 1 taken 563 times.
|
19840 | if (!callee) |
696 | 18714 | return ExprResult(QualType(TY_INVALID)); | |
697 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 563 times.
|
1126 | assert(calleeParentScope != nullptr); |
698 | |||
699 | // Save the pointer to the operator function in the AST node | ||
700 | 1126 | std::vector<const Function *> &opFctPointers = typeChecker->getOpFctPointers(node); | |
701 |
2/2✓ Branch 1 taken 19 times.
✓ Branch 2 taken 544 times.
|
1126 | if (opFctPointers.size() <= opIdx) |
702 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
38 | opFctPointers.resize(opIdx + 1, nullptr); |
703 | 1126 | opFctPointers.at(opIdx) = callee; | |
704 | |||
705 | // Check if we need to request a re-visit, because the function body was not type-checked yet | ||
706 | 1126 | typeChecker->requestRevisitIfRequired(callee); | |
707 | |||
708 | // Check if the called function has sufficient visibility | ||
709 |
3/4✓ Branch 0 taken 563 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 243 times.
✓ Branch 4 taken 320 times.
|
1126 | const bool isImported = calleeParentScope != nullptr && calleeParentScope->isImportedBy(typeChecker->rootScope); |
710 | 1126 | const SymbolTableEntry *calleeEntry = callee->entry; | |
711 |
4/6✓ Branch 0 taken 243 times.
✓ Branch 1 taken 320 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 243 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 563 times.
|
1126 | if (isImported && !calleeEntry->getQualType().isPublic()) |
712 | ✗ | throw SemanticError(node, INSUFFICIENT_VISIBILITY, | |
713 | "Overloaded operator '" + callee->getSignature() + "' has insufficient visibility"); | ||
714 | |||
715 | // Procedures always have the return type 'bool' | ||
716 |
2/2✓ Branch 0 taken 134 times.
✓ Branch 1 taken 429 times.
|
1126 | if (callee->isProcedure()) |
717 | 268 | return ExprResult(QualType(TY_BOOL)); | |
718 | |||
719 | // Add anonymous symbol to keep track of de-allocation | ||
720 | 858 | SymbolTableEntry *anonymousSymbol = nullptr; | |
721 |
2/2✓ Branch 1 taken 61 times.
✓ Branch 2 taken 368 times.
|
858 | if (callee->returnType.is(TY_STRUCT)) |
722 | 122 | anonymousSymbol = typeChecker->currentScope->symbolTable.insertAnonymous(callee->returnType, node, opIdx); | |
723 | |||
724 | 858 | return {typeChecker->mapImportedScopeTypeToLocalType(calleeParentScope, callee->returnType), anonymousSymbol}; | |
725 | } | ||
726 | |||
727 | 2219 | QualType OpRuleManager::validateUnaryOperation(const ASTNode *node, const UnaryOpRule opRules[], size_t opRulesSize, | |
728 | const char *name, const QualType &lhs) { | ||
729 |
2/2✓ Branch 0 taken 5284 times.
✓ Branch 1 taken 2 times.
|
5286 | for (size_t i = 0; i < opRulesSize; i++) { |
730 | 5284 | const UnaryOpRule &rule = opRules[i]; | |
731 |
2/2✓ Branch 2 taken 2217 times.
✓ Branch 3 taken 3067 times.
|
5284 | if (std::get<0>(rule) == lhs.getSuperType()) |
732 |
1/2✓ Branch 2 taken 2217 times.
✗ Branch 3 not taken.
|
2217 | return QualType(std::get<1>(rule)); |
733 | } | ||
734 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | throw getExceptionUnary(node, name, lhs); |
735 | } | ||
736 | |||
737 | 23446 | QualType OpRuleManager::validateBinaryOperation(const ASTNode *node, const BinaryOpRule opRules[], size_t opRulesSize, | |
738 | const char *name, const QualType &lhs, const QualType &rhs, | ||
739 | bool preserveSpecifiersFromLhs, const char *customMessagePrefix) { | ||
740 |
2/2✓ Branch 0 taken 216646 times.
✓ Branch 1 taken 19 times.
|
216665 | for (size_t i = 0; i < opRulesSize; i++) { |
741 | 216646 | const BinaryOpRule &rule = opRules[i]; | |
742 |
6/6✓ Branch 2 taken 46808 times.
✓ Branch 3 taken 169838 times.
✓ Branch 6 taken 23427 times.
✓ Branch 7 taken 23381 times.
✓ Branch 8 taken 23427 times.
✓ Branch 9 taken 193219 times.
|
216646 | if (std::get<0>(rule) == lhs.getSuperType() && std::get<1>(rule) == rhs.getSuperType()) { |
743 |
1/2✓ Branch 2 taken 23427 times.
✗ Branch 3 not taken.
|
23427 | QualType resultType((std::get<2>(rule))); |
744 |
2/2✓ Branch 0 taken 13659 times.
✓ Branch 1 taken 9768 times.
|
23427 | if (preserveSpecifiersFromLhs) |
745 | 13659 | resultType.setSpecifiers(lhs.getSpecifiers()); | |
746 | 23427 | return resultType; | |
747 | } | ||
748 | } | ||
749 |
1/2✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | throw getExceptionBinary(node, name, lhs, rhs, customMessagePrefix); |
750 | } | ||
751 | |||
752 | 2 | SemanticError OpRuleManager::getExceptionUnary(const ASTNode *node, const char *name, const QualType &lhs) { | |
753 |
6/12✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
|
8 | return {node, OPERATOR_WRONG_DATA_TYPE, "Cannot apply '" + std::string(name) + "' operator on type " + lhs.getName(true)}; |
754 | } | ||
755 | |||
756 | 19 | SemanticError OpRuleManager::getExceptionBinary(const ASTNode *node, const char *name, const QualType &lhs, const QualType &rhs, | |
757 | const char *messagePrefix) { | ||
758 | // Build error message | ||
759 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | std::stringstream errorMsg; |
760 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
|
19 | if (strlen(messagePrefix) != 0) |
761 |
7/14✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
|
4 | errorMsg << messagePrefix << ". Expected " << lhs.getName(true) << " but got " << rhs.getName(true); |
762 | else | ||
763 |
8/16✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 15 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 15 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 15 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 15 times.
✗ Branch 23 not taken.
|
15 | errorMsg << "Cannot apply '" << name << "' operator on types " << lhs.getName(true) << " and " << rhs.getName(true); |
764 | |||
765 | // Return the exception | ||
766 |
2/4✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
|
57 | return {node, OPERATOR_WRONG_DATA_TYPE, errorMsg.str()}; |
767 | 19 | } | |
768 | |||
769 | 2 | void OpRuleManager::ensureUnsafeAllowed(const ASTNode *node, const char *name, const QualType &lhs) const { | |
770 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | if (typeChecker->currentScope->doesAllowUnsafeOperations()) |
771 | 2 | return; | |
772 | // Print error message | ||
773 | ✗ | const std::string lhsName = lhs.getName(true); | |
774 | ✗ | const std::string errorMsg = "Cannot apply '" + std::string(name) + "' operator on type " + lhsName + | |
775 | ✗ | " as this is an unsafe operation. Please use unsafe blocks if you know what you are doing."; | |
776 | ✗ | SOFT_ERROR_VOID(node, UNSAFE_OPERATION_IN_SAFE_CONTEXT, errorMsg) | |
777 | ✗ | } | |
778 | |||
779 | 752 | void OpRuleManager::ensureUnsafeAllowed(const ASTNode *node, const char *name, const QualType &lhs, const QualType &rhs) const { | |
780 |
3/4✓ Branch 1 taken 752 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 751 times.
✓ Branch 4 taken 1 times.
|
752 | if (typeChecker->currentScope->doesAllowUnsafeOperations()) |
781 | 751 | return; | |
782 | // Print error message | ||
783 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const std::string lhsName = lhs.getName(true); |
784 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const std::string rhsName = rhs.getName(true); |
785 |
6/12✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
|
2 | const std::string errorMsg = "Cannot apply '" + std::string(name) + "' operator on types " + lhsName + " and " + rhsName + |
786 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | " as this is an unsafe operation. Please use unsafe blocks if you know what you are doing."; |
787 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | SOFT_ERROR_VOID(node, UNSAFE_OPERATION_IN_SAFE_CONTEXT, errorMsg) |
788 | 1 | } | |
789 | |||
790 | 19730 | void OpRuleManager::ensureNoConstAssign(const ASTNode *node, const QualType &lhs, bool isDecl, bool isReturn) { | |
791 | // Check if we try to assign a constant value | ||
792 |
10/12✓ Branch 1 taken 19730 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19730 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2797 times.
✓ Branch 7 taken 16933 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 2782 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 13 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 19728 times.
|
19730 | if (lhs.removeReferenceWrapper().isConst() && !isDecl && !isReturn) { |
793 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | const std::string errorMessage = "Trying to assign value to an immutable variable of type " + lhs.getName(true); |
794 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | throw SemanticError(node, REASSIGN_CONST_VARIABLE, errorMessage); |
795 | 2 | } | |
796 | 19728 | } | |
797 | |||
798 | } // namespace spice::compiler | ||
799 |