Skip to content

Fix False Positives of M5-0-12 #925

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jul 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,19 @@
import cpp
import codingstandards.cpp.autosar

from Variable v, Expr aexp
from Conversion c
where
not isExcluded(v,
not isExcluded(c,
StringsPackage::signedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValuesQuery()) and
// We find cases where it is an explicitly signed char type with an assignment
// to a non-numeric type. NOTE: This rule addresses cases where the char type
// is used character data only, the rule does not explicitly cover this.
// Please see M5-0-11 for explicit handling of this case. Get types that are
// char, except for ones that are 'plain', meaning the sign is explicit.
/* 1. Focus on implicit conversions only (explicit conversions are acceptable). */
c.isImplicit() and
/* 2. The target type is explicitly signed or unsigned char. */
(
v.getUnspecifiedType() instanceof SignedCharType or
v.getUnspecifiedType() instanceof UnsignedCharType
c.getUnspecifiedType() instanceof SignedCharType or
c.getUnspecifiedType() instanceof UnsignedCharType
) and
// Identify places where these explicitly signed types are being assigned to a
// non-numeric type.
aexp = v.getAnAssignedValue() and
aexp.getUnspecifiedType() instanceof CharType
select aexp,
"Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type",
v, v.getName()
/* 3. Check if the source expression is a plain char type, i.e. not explicitly signed / unsigned. */
c.getExpr().getUnspecifiedType() instanceof PlainCharType
select c,
"This expression of plain char type is implicitly converted to '" +
c.getUnspecifiedType().getName() + "'."
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
| 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 |
| 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 |
| 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 |
| 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 |
| test.cpp:58:7:58:8 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:61:20:61:21 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
| test.cpp:71:21:71:22 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:74:20:74:21 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. |
| test.cpp:84:9:84:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:87:9:87:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
| test.cpp:97:9:97:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:100:9:100:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
| test.cpp:117:7:117:10 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:122:7:122:10 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
| test.cpp:137:7:137:10 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:142:7:142:10 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. |
| test.cpp:153:6:153:7 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:156:6:156:7 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. |
| test.cpp:166:6:166:7 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. |
| test.cpp:169:7:169:8 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. |
176 changes: 165 additions & 11 deletions cpp/autosar/test/rules/M5-0-12/test.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,170 @@
#include <cstdint>

void f1() {
unsigned char a1 = 'c'; // NON_COMPLIANT
unsigned char a2 = 10;
signed char a3 = 'c'; // NON_COMPLIANT
signed char a4 = 10;
class C1 {
public:
C1(unsigned char y) : x(y) {}

std::int8_t a5 = 'c'; // NON_COMPLIANT
std::int8_t a6 = 10;
private:
unsigned char x;
};

std::uint8_t a7 = 'c'; // NON_COMPLIANT
std::uint8_t a8 = 10;
class C2 {
public:
C2(signed char y) : x(y) {}

char a9 = 'c';
}
private:
signed char x;
};

/* Twin classes for std::uint8_t and std::int8_t */
class C5 {
public:
C5(unsigned char y) : x(y) {}

private:
std::uint8_t x;
};

class C6 {
public:
C6(signed char y) : x(y) {}

private:
std::int8_t x;
};

void f1(unsigned char x) {}
void f2(signed char x) {}

/* Twin functions for std::uint8_t and std::int8_t */
void f9(std::uint8_t x) {}
void f10(std::int8_t x) {}

int main() {

/* ========== 1. Assigning a char to another char ========== */

/* ===== 1-1. Assigning a char to a char variable ===== */

unsigned char x1 = 1;
unsigned char y1 =
x1; // COMPLIANT: unsigned char assigned to an unsigned char

signed char x2 = 1;
signed char y2 = x2; // COMPLIANT: signed char assigned to a signed char

char x3 = 'x';
unsigned char y3 =
x3; // NON-COMPLIANT: plain char assigned to a unsigned char

char x4 = 'x';
signed char y4 = x4; // NON-COMPLIANT: plain char assigned to a signed char

/* Twin cases with std::uint8_t and std::int8_t */
std::uint8_t x5 = 1;
std::uint8_t y5 = x5; // COMPLIANT: std::uint8_t assigned to a std::uint8_t

std::int8_t x6 = 1;
std::int8_t y6 = x6; // COMPLIANT: std::int8_t assigned to a std::int8_t

char x7 = 'x';
std::uint8_t y7 = x7; // NON-COMPLIANT: plain char assigned to a std::uint8_t

char x8 = 'x';
std::int8_t y8 = x8; // NON-COMPLIANT: plain char assigned to a std::int8_t

/* ===== 1-2. Assigning a char to a char member ===== */

C1 c1(1); // COMPLIANT: unsigned char arg passed to an unsigned
// char member

C2 c2(1); // COMPLIANT: signed char arg passed to a signed char
// member

C1 c3('x'); // NON-COMPLIANT: plain char arg passed to an unsigned char
// member

C2 c4('x'); // NON-COMPLIANT: plain char arg passed to a signed char
// member

/* Twin cases with std::uint8_t and std::int8_t */
C5 c5(1); // COMPLIANT: std::uint8_t arg passed to a
// std::uint8_t member

C6 c6(1); // COMPLIANT: std::int8_t arg passed to a std::int8_t
// member

C5 c7('x'); // NON-COMPLIANT: plain char arg passed to a
// std::uint8_t member

C6 c8('x'); // NON-COMPLIANT: plain char arg passed to a std::int8_t
// member

/* ========== 1-3. Assigning a char to a char through a pointer ========== */

unsigned char x9 = 1;
unsigned char *y9 = &x9;
unsigned char z1 =
*y9; // COMPLIANT: unsigned char assigned to an *&unsigned char

signed char x10 = 1;
signed char *y10 = &x10;
signed char z2 = *y10; // COMPLIANT: signed char assigned to an *&signed char

char x11 = 1;
char *y11 = &x11;
unsigned char z3 =
*y11; // NON-COMPLIANT: plain char assigned to an *&unsigned char

char x12 = 1;
char *y12 = &x12;
signed char z4 =
*y12; // NON-COMPLIANT: plain char assigned to an *&signed char

/* Twin cases with std::uint8_t and std::int8_t */
std::uint8_t x13 = 1;
std::uint8_t *y13 = &x13;
std::uint8_t z5 =
*y13; // COMPLIANT: std::uint8_t assigned to a *&std::uint8_t

std::int8_t x14 = 1;
std::int8_t *y14 = &x14;
std::int8_t z6 = *y14; // COMPLIANT: std::int8_t assigned to an *&std::int8_t

char x15 = 1;
char *y15 = &x15;
std::uint8_t z7 =
*y15; // NON-COMPLIANT: plain char assigned to an *&std::uint8_t

char x16 = 1;
char *y16 = &x16;
std::int8_t z8 =
*y16; // NON-COMPLIANT: plain char assigned to an *&std::int8_t

/* ========== 2. Passing a char argument to a char parameter ========== */

unsigned char a1 = 1;
f1(a1); // COMPLIANT: unsigned char arg passed to an unsigned char parameter

signed char a2 = 1;
f2(a2); // COMPLIANT: signed char arg passed to a signed char parameter

char a3 = 'a';
f1(a3); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter

char a4 = 'a';
f2(a4); // NON-COMPLIANT: plain char arg passed to a signed char parameter

/* Twin cases with std::uint8_t and std::int8_t */
std::uint8_t a5 = 1;
f9(a5); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter

std::int8_t a6 = 1;
f10(a6); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter

char a7 = 'a';
f9(a7); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter

char a8 = 'a';
f10(a8); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter
}
Loading