Skip to content

Commit f870023

Browse files
committed
Rule 7.0.6: Fix id-expression detection
- Add additional test cases - Allow name qualifiers - Prohibit explicit casts (inc. parameters)
1 parent 229705f commit f870023

File tree

3 files changed

+103
-41
lines changed

3 files changed

+103
-41
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ class IdExpression extends VariableAccess {
194194
// Member variable, but the qualifier is not explicit
195195
this.getQualifier().isCompilerGenerated()
196196
) and
197-
// No name qualifiers
198-
not exists(NameQualifier qual | qual.getExpr() = this)
197+
// Not an id-expression if it's an explicit conversion
198+
not this.hasExplicitConversion()
199199
}
200200
}
201201

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
1-
| test.cpp:21:8:21:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. |
2-
| test.cpp:24:7:24:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. |
3-
| test.cpp:30:8:30:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. |
4-
| test.cpp:31:8:31:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. |
5-
| test.cpp:36:8:36:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. |
6-
| test.cpp:37:9:37:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. |
7-
| test.cpp:42:7:42:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. |
8-
| test.cpp:43:9:43:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. |
9-
| test.cpp:55:8:55:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. |
10-
| test.cpp:56:21:56:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. |
11-
| test.cpp:67:11:67:13 | 32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. |
12-
| test.cpp:69:11:69:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. |
13-
| test.cpp:81:8:81:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. |
14-
| test.cpp:91:6:91:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. |
15-
| test.cpp:94:6:94:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. |
16-
| test.cpp:96:6:96:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. |
17-
| test.cpp:109:6:109:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. |
18-
| test.cpp:118:6:118:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. |
19-
| test.cpp:126:14:126:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. |
20-
| test.cpp:138:6:138:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. |
21-
| test.cpp:160:9:160:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. |
22-
| test.cpp:189:23:189:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. |
23-
| test.cpp:199:19:199:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. |
1+
| test.cpp:36:8:36:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. |
2+
| test.cpp:39:7:39:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. |
3+
| test.cpp:45:8:45:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. |
4+
| test.cpp:46:8:46:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. |
5+
| test.cpp:51:8:51:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. |
6+
| test.cpp:52:9:52:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. |
7+
| test.cpp:57:7:57:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. |
8+
| test.cpp:58:9:58:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. |
9+
| test.cpp:95:12:95:13 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. |
10+
| test.cpp:96:12:96:13 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. |
11+
| test.cpp:97:13:97:14 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. |
12+
| test.cpp:98:13:98:14 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. |
13+
| test.cpp:103:9:103:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. |
14+
| test.cpp:104:10:104:11 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. |
15+
| test.cpp:105:35:105:36 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. |
16+
| test.cpp:110:8:110:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. |
17+
| test.cpp:111:21:111:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. |
18+
| test.cpp:122:11:122:13 | 32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. |
19+
| test.cpp:124:11:124:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. |
20+
| test.cpp:136:8:136:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. |
21+
| test.cpp:146:6:146:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. |
22+
| test.cpp:149:6:149:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. |
23+
| test.cpp:151:6:151:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. |
24+
| test.cpp:164:6:164:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. |
25+
| test.cpp:173:6:173:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. |
26+
| test.cpp:181:14:181:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. |
27+
| test.cpp:193:6:193:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. |
28+
| test.cpp:215:9:215:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. |
29+
| test.cpp:244:23:244:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. |
30+
| test.cpp:254:19:254:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. |

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

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,30 @@ std::int64_t s64;
1313
float f;
1414
double d;
1515

16+
namespace TestNamespace {
17+
std::uint8_t g1;
18+
std::uint16_t g2;
19+
} // namespace TestNamespace
20+
21+
struct TestStruct {
22+
std::uint8_t m1;
23+
std::uint16_t m2;
24+
static std::uint8_t s1;
25+
static std::uint16_t s2;
26+
};
27+
28+
std::uint8_t TestStruct::s1;
29+
std::uint16_t TestStruct::s2;
30+
1631
// Test basic constant assignments
1732
void test_constant_assignments() {
18-
u32 = 1; // COMPLIANT
19-
s32 = 4u * 2u; // COMPLIANT
20-
u8 = 3u; // COMPLIANT
21-
u8 = 300u; // NON_COMPLIANT
33+
u32 = 1; // COMPLIANT
34+
s32 = 4u * 2u; // COMPLIANT
35+
u8 = 3u; // COMPLIANT
36+
u8 = 300u; // NON_COMPLIANT
2237
f = 1; // COMPLIANT
2338
f = 9999999999; // COMPLIANT
24-
d = 0.0f; // NON_COMPLIANT
39+
d = 0.0f; // NON_COMPLIANT
2540
f = 0.0f; // COMPLIANT
2641
}
2742

@@ -33,7 +48,7 @@ void test_signedness_violations() {
3348

3449
// Test size violations
3550
void test_size_violations() {
36-
u8 = u16; // NON_COMPLIANT
51+
u8 = u16; // NON_COMPLIANT
3752
u16 = u64; // NON_COMPLIANT
3853
}
3954

@@ -45,9 +60,49 @@ void test_type_category_violations() {
4560

4661
// Test widening of id-expressions
4762
void test_widening_id_expressions() {
48-
u32 = u8; // COMPLIANT
49-
s64 = s8; // COMPLIANT
50-
u64 = u16; // COMPLIANT
63+
u32 = u8; // COMPLIANT - widening of id-expression
64+
s64 = s8; // COMPLIANT - widening of id-expression
65+
u64 = u16; // COMPLIANT - widening of id-expression
66+
}
67+
68+
// Test widening with namespace qualifiers (allowed)
69+
void test_widening_namespace_qualified() {
70+
u32 = TestNamespace::g1; // COMPLIANT - namespace qualified id-expression
71+
u64 = TestNamespace::g2; // COMPLIANT - namespace qualified id-expression
72+
}
73+
74+
// Test widening with type qualifiers (allowed)
75+
void test_widening_type_qualified() {
76+
u32 = TestStruct::s1; // COMPLIANT - type qualified id-expression
77+
u64 = TestStruct::s2; // COMPLIANT - type qualified id-expression
78+
}
79+
80+
// Test widening with decltype (allowed)
81+
void test_widening_decltype_qualified() {
82+
std::uint8_t l1 = 42;
83+
std::uint16_t l2 = 42;
84+
u32 = decltype(l1){}; // COMPLIANT - treated as a constant
85+
u64 = decltype(l2){}; // COMPLIANT - treated as a constant
86+
TestStruct l3;
87+
u32 = decltype(l3)::s1; // COMPLIANT - decltype qualified
88+
u64 = decltype(l3)::s2; // COMPLIANT - decltype qualified
89+
}
90+
91+
// Test widening with object member access (not allowed)
92+
void test_widening_object_member_access() {
93+
TestStruct l1;
94+
TestStruct *l2 = &l1;
95+
u32 = l1.m1; // NON_COMPLIANT - object member access, not id-expression
96+
u64 = l1.m2; // NON_COMPLIANT - object member access, not id-expression
97+
u32 = l2->m1; // NON_COMPLIANT - object member access, not id-expression
98+
u64 = l2->m2; // NON_COMPLIANT - object member access, not id-expression
99+
}
100+
101+
// Test widening with expressions (not allowed)
102+
void test_widening_expressions() {
103+
u32 = u8 + 0; // NON_COMPLIANT - not id-expression
104+
u32 = (u8); // NON_COMPLIANT - not id-expression (parenthesized)
105+
u32 = static_cast<std::uint8_t>(u8); // NON_COMPLIANT - not id-expression
51106
}
52107

53108
// Test expression results
@@ -66,7 +121,7 @@ void test_bitfields() {
66121
l1.m1 = 2; // COMPLIANT
67122
l1.m1 = 32u; // NON_COMPLIANT
68123
l1.m1 = u8; // COMPLIANT
69-
l1.m1 = u16; // NON_COMPLIANT
124+
l1.m1 = u16; // NON_COMPLIANT
70125
}
71126

72127
// Test enums
@@ -77,9 +132,9 @@ enum States { enabled, disabled };
77132
void test_enums() {
78133
Colour l1 = red;
79134
u8 = red; // COMPLIANT
80-
u32 = red; // COMPLIANT
135+
u32 = red; // COMPLIANT
81136
u8 = l1; // NON_COMPLIANT
82-
u32 = l1; // COMPLIANT
137+
u32 = l1; // COMPLIANT
83138
u8 = enabled; // COMPLIANT - enabled is not numeric
84139
}
85140

@@ -106,7 +161,7 @@ void f3(std::int32_t l1) {}
106161

107162
void test_overloaded_functions() {
108163
f3(s32); // COMPLIANT
109-
f3(s8); // NON_COMPLIANT
164+
f3(s8); // NON_COMPLIANT
110165
f3(s64); // COMPLIANT
111166
}
112167

@@ -123,7 +178,7 @@ void test_function_pointers() {
123178
void f5(const char *l1, ...) {}
124179

125180
void test_variadic_functions() {
126-
f5("test", u8); // NON_COMPLIANT - will be promoted to `int`
181+
f5("test", u8); // NON_COMPLIANT - will be promoted to `int`
127182
f5("test", s32); // COMPLIANT - already `int`, no promotion needed
128183
}
129184

@@ -136,8 +191,8 @@ struct A {
136191

137192
void A::f7() {
138193
f6(u32, "answer"); // NON_COMPLIANT - extensible, could call a global
139-
// function instead - e.g. `void f6(std::uint32_t l1,
140-
// std::string l2)`
194+
// function instead - e.g. `void f6(std::uint32_t l1,
195+
// std::string l2)`
141196
this->f6(u32, "answer"); // COMPLIANT
142197
this->f6(u32, 42); // COMPLIANT
143198
}

0 commit comments

Comments
 (0)