Skip to content

Commit 0ed1689

Browse files
committed
Rule 7.0.6: Support reference types
Reference types can be numeric types according to the rule. In addition to making NumericTypes reference types, we also add a helper predicate which gets the size of the real type (rather than the size of the reference).
1 parent f870023 commit 0ed1689

File tree

3 files changed

+111
-4
lines changed

3 files changed

+111
-4
lines changed

cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class NumericType extends Type {
4343
Type realType;
4444

4545
NumericType() {
46+
realType = this.getUnspecifiedType().(ReferenceType).getBaseType().(NumericType).getRealType() or
4647
realType = this.getUnspecifiedType().(IntegralType) or
4748
realType = this.getUnspecifiedType().(FloatingPointType) or
4849
realType = this.getUnspecifiedType().(Enum).getExplicitUnderlyingType().getUnspecifiedType()
@@ -52,6 +53,8 @@ class NumericType extends Type {
5253
if realType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed()
5354
}
5455

56+
int getRealSize() { result = realType.getSize() }
57+
5558
TypeCategory getTypeCategory() {
5659
realType instanceof IntegralType and result = Integral()
5760
or
@@ -76,14 +79,15 @@ predicate isAssignment(Expr source, NumericType targetType, string context) {
7679
then
7780
exists(BitField bf |
7881
isAssignedToBitfield(source, bf) and
82+
// TODO integral after numeric?
7983
targetType.(IntegralType).(NumericType).getSignedness() =
8084
bf.getType().(NumericType).getSignedness() and
8185
// smallest integral type that can hold the bit field value
82-
targetType.getSize() * 8 >= bf.getNumBits() and
86+
targetType.getRealSize() * 8 >= bf.getNumBits() and
8387
not exists(IntegralType other |
8488
other.getSize() * 8 >= bf.getNumBits() and
8589
other.(NumericType).getSignedness() = targetType.getSignedness() and
86-
other.getSize() < targetType.getSize()
90+
other.getSize() < targetType.getRealSize()
8791
)
8892
)
8993
else targetType = assign.getLValue().getType()
@@ -159,7 +163,7 @@ predicate isValidTypeMatch(NumericType sourceType, NumericType targetType) {
159163
// Same type category, signedness and size
160164
sourceType.getTypeCategory() = targetType.getTypeCategory() and
161165
sourceType.getSignedness() = targetType.getSignedness() and
162-
sourceType.getSize() = targetType.getSize()
166+
sourceType.getRealSize() = targetType.getRealSize()
163167
}
164168

165169
predicate hasConstructorException(FunctionCall call) {
@@ -209,7 +213,7 @@ predicate isValidWidening(Expr source, NumericType sourceType, NumericType targe
209213
) and
210214
sourceType.getTypeCategory() = targetType.getTypeCategory() and
211215
sourceType.getSignedness() = targetType.getSignedness() and
212-
sourceType.getSize() < targetType.getSize()
216+
sourceType.getRealSize() < targetType.getRealSize()
213217
}
214218

215219
/**

cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,16 @@
2828
| test.cpp:215:9:215:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. |
2929
| test.cpp:244:23:244:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. |
3030
| test.cpp:254:19:254:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. |
31+
| test.cpp:288:8:288:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. |
32+
| test.cpp:289:8:289:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. |
33+
| test.cpp:290:9:290:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. |
34+
| test.cpp:301:6:301:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. |
35+
| test.cpp:302:6:302:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. |
36+
| test.cpp:313:8:313:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. |
37+
| test.cpp:314:8:314:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. |
38+
| test.cpp:327:9:327:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. |
39+
| test.cpp:328:7:328:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. |
40+
| test.cpp:329:7:329:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. |
41+
| test.cpp:340:8:340:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. |
42+
| test.cpp:358:7:358:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. |
43+
| test.cpp:361:7:361:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. |

cpp/misra/test/rules/RULE-7-0-6/test.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,94 @@ void test_switch_cases() {
269269
// case 0xFFFF'FFFF'FFFF:
270270
// break;
271271
}
272+
}
273+
274+
// Test reference types - references to numeric types are considered numeric
275+
void test_reference_types_basic() {
276+
std::uint8_t l1 = 42;
277+
std::uint32_t l2 = 100;
278+
std::int8_t l3 = -5;
279+
float l4 = 3.14f;
280+
281+
std::uint8_t &l5 = l1; // COMPLIANT
282+
std::uint32_t &l6 = l2; // COMPLIANT
283+
std::int8_t &l7 = l3; // COMPLIANT
284+
float &l8 = l4; // COMPLIANT
285+
286+
// Reference types follow same rules as their referred types
287+
u32 = l5; // COMPLIANT - widening of id-expression (reference)
288+
u8 = l6; // NON_COMPLIANT - narrowing from reference
289+
u8 = l7; // NON_COMPLIANT - different signedness from reference
290+
s32 = l8; // NON_COMPLIANT - different type category from reference
291+
}
292+
293+
void test_reference_types_function_parameters() {
294+
std::uint8_t l1 = 42;
295+
std::uint16_t l2 = 1000;
296+
297+
std::uint8_t &l3 = l1;
298+
std::uint16_t &l4 = l2;
299+
300+
// Function calls with reference arguments
301+
f1(l3); // NON_COMPLIANT - widening conversion through reference
302+
f2(l4); // NON_COMPLIANT - narrowing conversion through reference
303+
}
304+
305+
void test_reference_types_signedness() {
306+
std::uint8_t l1 = 42;
307+
std::int8_t l2 = -5;
308+
309+
std::uint8_t &l3 = l1;
310+
std::int8_t &l4 = l2;
311+
312+
// Signedness violations through references
313+
s8 = l3; // NON_COMPLIANT - different signedness through reference
314+
u8 = l4; // NON_COMPLIANT - different signedness through reference
315+
}
316+
317+
void test_reference_types_floating_point() {
318+
float l1 = 3.14f;
319+
double l2 = 2.718;
320+
std::int32_t l3 = 42;
321+
322+
float &l4 = l1;
323+
double &l5 = l2;
324+
std::int32_t &l6 = l3;
325+
326+
// Type category violations through references
327+
s32 = l4; // NON_COMPLIANT - different type category through reference
328+
f = l5; // NON_COMPLIANT - different size through reference
329+
f = l6; // NON_COMPLIANT - different type category through reference
330+
}
331+
332+
void test_reference_types_expressions() {
333+
std::uint8_t l1 = 42;
334+
std::uint8_t l2 = 24;
335+
336+
std::uint8_t &l3 = l1;
337+
std::uint8_t &l4 = l2;
338+
339+
// Expression results with references still follow expression rules
340+
u8 = l3 + l4; // NON_COMPLIANT - addition promotes to int
341+
s32 = l3 + l4; // COMPLIANT - promotion to int
342+
}
343+
344+
// Test reference parameters in functions
345+
void f13(std::uint8_t &l1) {}
346+
void f13(std::uint16_t &l1) {}
347+
348+
void f14(std::uint32_t l1) {}
349+
350+
void test_references() {
351+
std::uint8_t l1 = 42;
352+
std::uint16_t l2 = 1000;
353+
354+
f13(l1); // COMPLIANT - exact match
355+
f13(l2); // COMPLIANT - exact match
356+
357+
std::uint16_t &l3 = l2;
358+
f14(l3); // NON_COMPLIANT - must be the same type, as non-overload-independent
359+
std::uint64_t l4 = 1000;
360+
std::uint64_t &l5 = l4;
361+
f14(l5); // NON_COMPLIANT - narrowing conversion through reference
272362
}

0 commit comments

Comments
 (0)