Skip to content

Commit f68658a

Browse files
committed
Rule 7.0.6: Support constructor field initializers
1 parent fc63db1 commit f68658a

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ predicate isAssignment(Expr source, NumericType targetType, string context) {
152152
targetType = v.getType()
153153
)
154154
or
155+
exists(ConstructorFieldInit fi |
156+
fi.getExpr() = source and
157+
context = "constructor field initialization"
158+
|
159+
// For the MISRA type rules we treat bit fields as a special case
160+
if fi.getTarget() instanceof BitField
161+
then targetType = getBitFieldType(fi.getTarget())
162+
else
163+
// Regular variable initialization
164+
targetType = fi.getTarget().getType()
165+
)
166+
or
155167
// Passing a function parameter by value
156168
exists(Call call, int i |
157169
call.getArgument(i) = source and

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@
6565
| test.cpp:442:8:442:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. |
6666
| test.cpp:460:7:460:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. |
6767
| test.cpp:463:7:463:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. |
68+
| test.cpp:512:12:512:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. |
69+
| test.cpp:513:12:513:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. |
70+
| test.cpp:515:12:515:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. |
71+
| test.cpp:516:12:516:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. |
72+
| test.cpp:536:12:536:14 | 300 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. |
73+
| test.cpp:537:12:537:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. |
74+
| test.cpp:538:12:538:27 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long long' to 'uint32_t'. |
75+
| test.cpp:539:12:539:14 | 200 | Assignment between incompatible numeric types from 'int' to 'int8_t'. |
76+
| test.cpp:540:12:540:16 | 40000 | Assignment between incompatible numeric types from 'int' to 'int16_t'. |
77+
| test.cpp:541:12:541:26 | 4294967296 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. |
78+
| test.cpp:542:12:542:14 | 1.0 | Assignment between incompatible numeric types from 'double' to 'float'. |
79+
| test.cpp:543:12:543:15 | 1.0 | Assignment between incompatible numeric types from 'float' to 'double'. |
80+
| test.cpp:548:12:548:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. |
81+
| test.cpp:549:12:549:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint16_t'. |
82+
| test.cpp:550:12:550:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. |
83+
| test.cpp:552:12:552:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int16_t'. |
84+
| test.cpp:553:12:553:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. |
85+
| test.cpp:554:12:554:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. |
86+
| test.cpp:555:12:555:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. |
6887
| test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. |
6988
| test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. |
7089
| test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. |

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

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,4 +482,88 @@ void test_compound_assignments() {
482482
l2 >>= 1; // COMPLIANT - compound assignment, rule does not apply
483483
l4 += l1; // COMPLIANT - compound assignment, rule does not apply
484484
l4 -= s32; // COMPLIANT - compound assignment, rule does not apply
485+
}
486+
487+
// Test constructor field initializers
488+
struct ConstructorTest {
489+
std::uint8_t m1;
490+
std::uint16_t m2;
491+
std::uint32_t m3;
492+
std::int8_t m4;
493+
std::int16_t m5;
494+
std::int32_t m6;
495+
float m7;
496+
double m8;
497+
498+
// Constructor with various member initializer scenarios
499+
ConstructorTest(std::uint8_t l1, std::uint16_t l2, std::int8_t l3)
500+
: m1(l1), // COMPLIANT - same type
501+
m2(l2), // COMPLIANT - same type
502+
m3(l1), // COMPLIANT - widening of id-expression
503+
m4(l3), // COMPLIANT - same type
504+
m5(l3), // COMPLIANT - widening of id-expression
505+
m6(l3), // COMPLIANT - widening of id-expression
506+
m7(1.0f), // COMPLIANT - same type
507+
m8(1.0) { // COMPLIANT - same type
508+
}
509+
510+
// Constructor with non-compliant initializers
511+
ConstructorTest(std::uint32_t l1, std::int32_t l2, float l3)
512+
: m1(l1), // NON_COMPLIANT - narrowing
513+
m2(l1), // NON_COMPLIANT - narrowing
514+
m3(l1), // COMPLIANT - same type
515+
m4(l2), // NON_COMPLIANT - narrowing and different signedness
516+
m5(l2), // NON_COMPLIANT - narrowing and different signedness
517+
m6(l2), // COMPLIANT - same type
518+
m7(l3), // COMPLIANT - same type
519+
m8(l3) { // COMPLIANT - allowed to use float to initialize double
520+
}
521+
522+
// Constructor with constant initializers
523+
ConstructorTest()
524+
: m1(100), // COMPLIANT - constant fits
525+
m2(65535), // COMPLIANT - constant fits
526+
m3(4294967295U), // COMPLIANT - constant fits
527+
m4(127), // COMPLIANT - constant fits
528+
m5(32767), // COMPLIANT - constant fits
529+
m6(2147483647), // COMPLIANT - constant fits
530+
m7(3.14f), // COMPLIANT - same type constant
531+
m8(2.718) { // COMPLIANT - same type constant
532+
}
533+
534+
// Constructor with non-compliant constant initializers
535+
ConstructorTest(int)
536+
: m1(300), // NON_COMPLIANT - constant too large
537+
m2(70000), // NON_COMPLIANT - constant too large
538+
m3(0x1'0000'0000ULL), // NON_COMPLIANT - constant too large
539+
m4(200), // NON_COMPLIANT - constant too large
540+
m5(40000), // NON_COMPLIANT - constant too large
541+
m6(0x1'0000'0000LL), // NON_COMPLIANT - constant too large
542+
m7(1.0), // NON_COMPLIANT - different size
543+
m8(1.0f) { // NON_COMPLIANT - different size
544+
}
545+
546+
// Constructor with expression initializers
547+
ConstructorTest(std::uint8_t l1, std::uint8_t l2, std::int8_t l3)
548+
: m1(l1 + l2), // NON_COMPLIANT - expression result is int
549+
m2(l1 + l2), // NON_COMPLIANT - expression result is int
550+
m3(l1 + l2), // NON_COMPLIANT - expression result is int
551+
m4(l3), // COMPLIANT - widening of id-expression
552+
m5(l1), // NON_COMPLIANT - different signedness
553+
m6(l1), // NON_COMPLIANT - different signedness
554+
m7(l1), // NON_COMPLIANT - different type category
555+
m8(l1) { // NON_COMPLIANT - different type category
556+
}
557+
};
558+
559+
void test_constructor_field_initializers() {
560+
std::uint8_t l1 = 42;
561+
std::uint16_t l2 = 1000;
562+
std::int8_t l3 = 10;
563+
564+
ConstructorTest l4(l1, l2, l3); // Test first constructor
565+
ConstructorTest l5(u32, s32, f); // Test second constructor
566+
ConstructorTest l6; // Test third constructor
567+
ConstructorTest l7(0); // Test fourth constructor
568+
ConstructorTest l8(l1, l1, l3); // Test fifth constructor
485569
}

0 commit comments

Comments
 (0)