Skip to content

Commit 0f9f491

Browse files
Merge pull request #925 from github/jeongsoolee09/FP-M5-0-12
Fix False Positives of `M5-0-12`
2 parents e8b910e + 8dbaa1b commit 0f9f491

File tree

3 files changed

+193
-31
lines changed

3 files changed

+193
-31
lines changed

cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,19 @@
1616
import cpp
1717
import codingstandards.cpp.autosar
1818

19-
from Variable v, Expr aexp
19+
from Conversion c
2020
where
21-
not isExcluded(v,
21+
not isExcluded(c,
2222
StringsPackage::signedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValuesQuery()) and
23-
// We find cases where it is an explicitly signed char type with an assignment
24-
// to a non-numeric type. NOTE: This rule addresses cases where the char type
25-
// is used character data only, the rule does not explicitly cover this.
26-
// Please see M5-0-11 for explicit handling of this case. Get types that are
27-
// char, except for ones that are 'plain', meaning the sign is explicit.
23+
/* 1. Focus on implicit conversions only (explicit conversions are acceptable). */
24+
c.isImplicit() and
25+
/* 2. The target type is explicitly signed or unsigned char. */
2826
(
29-
v.getUnspecifiedType() instanceof SignedCharType or
30-
v.getUnspecifiedType() instanceof UnsignedCharType
27+
c.getUnspecifiedType() instanceof SignedCharType or
28+
c.getUnspecifiedType() instanceof UnsignedCharType
3129
) and
32-
// Identify places where these explicitly signed types are being assigned to a
33-
// non-numeric type.
34-
aexp = v.getAnAssignedValue() and
35-
aexp.getUnspecifiedType() instanceof CharType
36-
select aexp,
37-
"Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type",
38-
v, v.getName()
30+
/* 3. Check if the source expression is a plain char type, i.e. not explicitly signed / unsigned. */
31+
c.getExpr().getUnspecifiedType() instanceof PlainCharType
32+
select c,
33+
"This expression of plain char type is implicitly converted to '" +
34+
c.getUnspecifiedType().getName() + "'."
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
| test.cpp:4:22:4:24 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:4:17:4:18 | a1 | a1 |
2-
| test.cpp:6:20:6:22 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:6:15:6:16 | a3 | a3 |
3-
| test.cpp:9:20:9:22 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:9:15:9:16 | a5 | a5 |
4-
| test.cpp:12:21:12:23 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:12:16:12:17 | a7 | a7 |
1+
| test.cpp:58:7:58:8 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
2+
| test.cpp:61:20:61:21 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
3+
| test.cpp:71:21:71:22 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
4+
| test.cpp:74:20:74:21 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. |
5+
| test.cpp:84:9:84:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
6+
| test.cpp:87:9:87:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
7+
| test.cpp:97:9:97:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
8+
| test.cpp:100:9:100:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
9+
| test.cpp:117:7:117:10 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
10+
| test.cpp:122:7:122:10 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
11+
| test.cpp:137:7:137:10 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
12+
| test.cpp:142:7:142:10 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. |
13+
| test.cpp:153:6:153:7 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
14+
| test.cpp:156:6:156:7 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
15+
| test.cpp:166:6:166:7 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
16+
| test.cpp:169:7:169:8 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. |
Lines changed: 165 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,170 @@
11
#include <cstdint>
22

3-
void f1() {
4-
unsigned char a1 = 'c'; // NON_COMPLIANT
5-
unsigned char a2 = 10;
6-
signed char a3 = 'c'; // NON_COMPLIANT
7-
signed char a4 = 10;
3+
class C1 {
4+
public:
5+
C1(unsigned char y) : x(y) {}
86

9-
std::int8_t a5 = 'c'; // NON_COMPLIANT
10-
std::int8_t a6 = 10;
7+
private:
8+
unsigned char x;
9+
};
1110

12-
std::uint8_t a7 = 'c'; // NON_COMPLIANT
13-
std::uint8_t a8 = 10;
11+
class C2 {
12+
public:
13+
C2(signed char y) : x(y) {}
1414

15-
char a9 = 'c';
16-
}
15+
private:
16+
signed char x;
17+
};
18+
19+
/* Twin classes for std::uint8_t and std::int8_t */
20+
class C5 {
21+
public:
22+
C5(unsigned char y) : x(y) {}
23+
24+
private:
25+
std::uint8_t x;
26+
};
27+
28+
class C6 {
29+
public:
30+
C6(signed char y) : x(y) {}
31+
32+
private:
33+
std::int8_t x;
34+
};
35+
36+
void f1(unsigned char x) {}
37+
void f2(signed char x) {}
38+
39+
/* Twin functions for std::uint8_t and std::int8_t */
40+
void f9(std::uint8_t x) {}
41+
void f10(std::int8_t x) {}
42+
43+
int main() {
44+
45+
/* ========== 1. Assigning a char to another char ========== */
46+
47+
/* ===== 1-1. Assigning a char to a char variable ===== */
48+
49+
unsigned char x1 = 1;
50+
unsigned char y1 =
51+
x1; // COMPLIANT: unsigned char assigned to an unsigned char
52+
53+
signed char x2 = 1;
54+
signed char y2 = x2; // COMPLIANT: signed char assigned to a signed char
55+
56+
char x3 = 'x';
57+
unsigned char y3 =
58+
x3; // NON-COMPLIANT: plain char assigned to a unsigned char
59+
60+
char x4 = 'x';
61+
signed char y4 = x4; // NON-COMPLIANT: plain char assigned to a signed char
62+
63+
/* Twin cases with std::uint8_t and std::int8_t */
64+
std::uint8_t x5 = 1;
65+
std::uint8_t y5 = x5; // COMPLIANT: std::uint8_t assigned to a std::uint8_t
66+
67+
std::int8_t x6 = 1;
68+
std::int8_t y6 = x6; // COMPLIANT: std::int8_t assigned to a std::int8_t
69+
70+
char x7 = 'x';
71+
std::uint8_t y7 = x7; // NON-COMPLIANT: plain char assigned to a std::uint8_t
72+
73+
char x8 = 'x';
74+
std::int8_t y8 = x8; // NON-COMPLIANT: plain char assigned to a std::int8_t
75+
76+
/* ===== 1-2. Assigning a char to a char member ===== */
77+
78+
C1 c1(1); // COMPLIANT: unsigned char arg passed to an unsigned
79+
// char member
80+
81+
C2 c2(1); // COMPLIANT: signed char arg passed to a signed char
82+
// member
83+
84+
C1 c3('x'); // NON-COMPLIANT: plain char arg passed to an unsigned char
85+
// member
86+
87+
C2 c4('x'); // NON-COMPLIANT: plain char arg passed to a signed char
88+
// member
89+
90+
/* Twin cases with std::uint8_t and std::int8_t */
91+
C5 c5(1); // COMPLIANT: std::uint8_t arg passed to a
92+
// std::uint8_t member
93+
94+
C6 c6(1); // COMPLIANT: std::int8_t arg passed to a std::int8_t
95+
// member
96+
97+
C5 c7('x'); // NON-COMPLIANT: plain char arg passed to a
98+
// std::uint8_t member
99+
100+
C6 c8('x'); // NON-COMPLIANT: plain char arg passed to a std::int8_t
101+
// member
102+
103+
/* ========== 1-3. Assigning a char to a char through a pointer ========== */
104+
105+
unsigned char x9 = 1;
106+
unsigned char *y9 = &x9;
107+
unsigned char z1 =
108+
*y9; // COMPLIANT: unsigned char assigned to an *&unsigned char
109+
110+
signed char x10 = 1;
111+
signed char *y10 = &x10;
112+
signed char z2 = *y10; // COMPLIANT: signed char assigned to an *&signed char
113+
114+
char x11 = 1;
115+
char *y11 = &x11;
116+
unsigned char z3 =
117+
*y11; // NON-COMPLIANT: plain char assigned to an *&unsigned char
118+
119+
char x12 = 1;
120+
char *y12 = &x12;
121+
signed char z4 =
122+
*y12; // NON-COMPLIANT: plain char assigned to an *&signed char
123+
124+
/* Twin cases with std::uint8_t and std::int8_t */
125+
std::uint8_t x13 = 1;
126+
std::uint8_t *y13 = &x13;
127+
std::uint8_t z5 =
128+
*y13; // COMPLIANT: std::uint8_t assigned to a *&std::uint8_t
129+
130+
std::int8_t x14 = 1;
131+
std::int8_t *y14 = &x14;
132+
std::int8_t z6 = *y14; // COMPLIANT: std::int8_t assigned to an *&std::int8_t
133+
134+
char x15 = 1;
135+
char *y15 = &x15;
136+
std::uint8_t z7 =
137+
*y15; // NON-COMPLIANT: plain char assigned to an *&std::uint8_t
138+
139+
char x16 = 1;
140+
char *y16 = &x16;
141+
std::int8_t z8 =
142+
*y16; // NON-COMPLIANT: plain char assigned to an *&std::int8_t
143+
144+
/* ========== 2. Passing a char argument to a char parameter ========== */
145+
146+
unsigned char a1 = 1;
147+
f1(a1); // COMPLIANT: unsigned char arg passed to an unsigned char parameter
148+
149+
signed char a2 = 1;
150+
f2(a2); // COMPLIANT: signed char arg passed to a signed char parameter
151+
152+
char a3 = 'a';
153+
f1(a3); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter
154+
155+
char a4 = 'a';
156+
f2(a4); // NON-COMPLIANT: plain char arg passed to a signed char parameter
157+
158+
/* Twin cases with std::uint8_t and std::int8_t */
159+
std::uint8_t a5 = 1;
160+
f9(a5); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter
161+
162+
std::int8_t a6 = 1;
163+
f10(a6); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter
164+
165+
char a7 = 'a';
166+
f9(a7); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter
167+
168+
char a8 = 'a';
169+
f10(a8); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter
170+
}

0 commit comments

Comments
 (0)