Skip to content

Commit a65c4cc

Browse files
committed
StandardConversions: Handle aggregate initialization
1 parent 06eddfa commit a65c4cc

File tree

3 files changed

+153
-6
lines changed

3 files changed

+153
-6
lines changed

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,26 @@ predicate isAssignment(Expr source, NumericType targetType, string context) {
168168
targetType = switch.getExpr().getFullyConverted().getType() and
169169
context = "switch case"
170170
)
171+
or
172+
// Class aggregate literal initialization
173+
exists(ClassAggregateLiteral al, Field f |
174+
source = al.getAFieldExpr(f) and
175+
context = "class aggregate literal"
176+
|
177+
// For the MISRA type rules we treat bit fields as a special case
178+
if f instanceof BitField
179+
then targetType = getBitFieldType(f)
180+
else
181+
// Regular variable initialization
182+
targetType = f.getType()
183+
)
184+
or
185+
// Array or vector aggregate literal initialization
186+
exists(ArrayOrVectorAggregateLiteral vl |
187+
source = vl.getAnElementExpr(_) and
188+
targetType = vl.getElementType() and
189+
context = "array or vector aggregate literal"
190+
)
171191
}
172192

173193
/**
@@ -200,9 +220,4 @@ CanonicalIntegerTypes getBitFieldType(BitField bf) {
200220
/**
201221
* Holds if the `source` expression is assigned to a bit field.
202222
*/
203-
predicate isAssignedToBitfield(Expr source, BitField bf) {
204-
exists(Assignment assign |
205-
assign.getRValue() = source and
206-
assign.getLValue() = bf.getAnAccess()
207-
)
208-
}
223+
predicate isAssignedToBitfield(Expr source, BitField bf) { source = bf.getAnAssignedValue() }

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,36 @@
137137
| test.cpp:766:8:766:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. |
138138
| test.cpp:767:8:767:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. |
139139
| test.cpp:768:8:768:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. |
140+
| test.cpp:786:22:786:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. |
141+
| test.cpp:788:26:788:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. |
142+
| test.cpp:790:31:790:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. |
143+
| test.cpp:792:22:792:24 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. |
144+
| test.cpp:795:22:795:24 | 256 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. |
145+
| test.cpp:795:27:795:31 | 65536 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. |
146+
| test.cpp:796:22:796:33 | 2147483648 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. |
147+
| test.cpp:808:22:808:24 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. |
148+
| test.cpp:808:27:808:29 | 400 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. |
149+
| test.cpp:808:32:808:34 | 500 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. |
150+
| test.cpp:809:22:809:23 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. |
151+
| test.cpp:809:26:809:27 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. |
152+
| test.cpp:809:30:809:31 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. |
153+
| test.cpp:810:22:810:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. |
154+
| test.cpp:810:27:810:29 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. |
155+
| test.cpp:810:32:810:34 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. |
156+
| test.cpp:815:26:815:28 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. |
157+
| test.cpp:815:31:815:33 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. |
158+
| test.cpp:815:38:815:40 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. |
159+
| test.cpp:815:43:815:45 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. |
160+
| test.cpp:816:26:816:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. |
161+
| test.cpp:816:30:816:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. |
162+
| test.cpp:817:26:817:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. |
163+
| test.cpp:817:30:817:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. |
164+
| test.cpp:833:8:833:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. |
165+
| test.cpp:837:7:837:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. |
166+
| test.cpp:853:24:853:26 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. |
167+
| test.cpp:853:29:853:33 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. |
168+
| test.cpp:853:36:853:39 | 5000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. |
169+
| test.cpp:854:24:854:26 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. |
170+
| test.cpp:854:29:854:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. |
171+
| test.cpp:854:34:854:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. |
172+
| test.cpp:864:28:864:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. |

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

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,4 +766,103 @@ void test_user_defined_operators_constants() {
766766
l1 = 42L; // NON_COMPLIANT
767767
l1 = 42LL; // NON_COMPLIANT
768768
l1 = 42U; // NON_COMPLIANT
769+
}
770+
771+
// Test aggregate initialization - struct with multiple members
772+
struct SimpleAggregate {
773+
std::uint8_t m1;
774+
std::uint16_t m2;
775+
std::int32_t m3;
776+
float m4;
777+
};
778+
779+
void test_aggregate_initialization_basic() {
780+
// Compliant cases - exact types or constants that fit
781+
SimpleAggregate l1{42, 1000, -50, 3.14f}; // COMPLIANT
782+
SimpleAggregate l2{u8, u16, s32, f}; // COMPLIANT
783+
SimpleAggregate l3{255, 65535, 2147483647, 0.0f}; // COMPLIANT
784+
785+
// Non-compliant cases - type violations
786+
SimpleAggregate l4{u16, u8, s32, // NON_COMPLIANT - narrowing u16 to uint8_t
787+
f};
788+
SimpleAggregate l5{u8, u32, s32, // NON_COMPLIANT - narrowing u32 to uint16_t
789+
f};
790+
SimpleAggregate l6{u8, u16, u32, f}; // NON_COMPLIANT - different signedness
791+
SimpleAggregate l7{u8, u16, s32,
792+
s32}; // NON_COMPLIANT - different type category
793+
794+
// Constants that don't fit
795+
SimpleAggregate l8{256, 65536, // NON_COMPLIANT - constants don't fit
796+
2147483648LL, // NON_COMPLIANT - constants don't fit
797+
0.0f};
798+
799+
// Widening of id-expressions is allowed
800+
SimpleAggregate l9{u8, u8, s8, f}; // COMPLIANT - widening allowed
801+
}
802+
803+
// Test aggregate initialization - arrays
804+
void test_aggregate_initialization_arrays() {
805+
// Basic arrays
806+
std::uint8_t l1[3]{10, 20, 30}; // COMPLIANT
807+
std::uint8_t l2[3]{u8, u8, u8}; // COMPLIANT
808+
std::uint8_t l3[3]{300, 400, 500}; // NON_COMPLIANT - constants don't fit
809+
std::uint8_t l4[3]{s8, s8, s8}; // NON_COMPLIANT - signedness mismatch
810+
std::uint8_t l5[3]{u16, u16, u16}; // NON_COMPLIANT - narrowing
811+
812+
// Multi-dimensional arrays
813+
std::int16_t l6[2][2]{{1, 2}, {3, 4}}; // COMPLIANT
814+
std::int16_t l7[2][2]{{s8, s8}, {s8, s8}}; // COMPLIANT - widening allowed
815+
std::int16_t l8[2][2]{{s32, s32}, {s32, s32}}; // NON_COMPLIANT - narrowing
816+
std::int16_t l9[2][2]{{u8, u8}, // NON_COMPLIANT - signedness mismatch
817+
{u8, u8}}; // NON_COMPLIANT - signedness mismatch
818+
}
819+
820+
// Test aggregate initialization - nested structs
821+
struct NestedAggregate {
822+
SimpleAggregate m1;
823+
std::uint32_t m2;
824+
};
825+
826+
void test_aggregate_initialization_nested() {
827+
// Compliant nested initialization
828+
NestedAggregate l1{{10, 100, -5, 1.0f}, 500}; // COMPLIANT
829+
NestedAggregate l2{{u8, u16, s32, f}, u32}; // COMPLIANT
830+
831+
// Non-compliant nested initialization
832+
NestedAggregate l3{
833+
{u16, u8, s32, f}, // NON_COMPLIANT - narrowing in nested struct
834+
u32};
835+
NestedAggregate l4{
836+
{u8, u16, s32, f},
837+
s32}; // NON_COMPLIANT - signedness mismatch in outer member
838+
}
839+
840+
// Test aggregate initialization - struct with bit-fields
841+
struct BitfieldAggregate {
842+
std::uint32_t m1 : 8;
843+
std::uint32_t m2 : 16;
844+
std::int32_t m3 : 12;
845+
};
846+
847+
void test_aggregate_initialization_bitfields() {
848+
// Compliant cases
849+
BitfieldAggregate l1{100, 30000, -500}; // COMPLIANT
850+
BitfieldAggregate l2{u8, u16, s16}; // COMPLIANT - appropriate sizes
851+
852+
// Non-compliant cases
853+
BitfieldAggregate l3{300, 70000, 5000}; // NON_COMPLIANT - constants don't fit
854+
BitfieldAggregate l4{u16, u32, s32}; // NON_COMPLIANT - narrowing
855+
}
856+
857+
// Test aggregate initialization with designated initializers (C++20 feature,
858+
// but test for basic cases)
859+
void test_aggregate_initialization_designated() {
860+
// Note: Designated initializers are C++20, but we can test basic aggregate
861+
// init patterns
862+
SimpleAggregate l1{.m1 = 10, .m2 = 100, .m3 = -5, .m4 = 1.0f}; // COMPLIANT
863+
SimpleAggregate l2{.m1 = u8, .m2 = u16, .m3 = s32, .m4 = f}; // COMPLIANT
864+
SimpleAggregate l3{.m1 = u16, // NON_COMPLIANT - type violation
865+
.m2 = u8,
866+
.m3 = s32,
867+
.m4 = f};
769868
}

0 commit comments

Comments
 (0)