diff --git a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql index 3b6e436c56..8e48c05ada 100644 --- a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql +++ b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql @@ -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() + "'." diff --git a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected index 1be5b7b9fc..b23be388c6 100644 --- a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected +++ b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected @@ -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'. | diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 453c37bf1e..036db12b04 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -1,16 +1,170 @@ #include -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'; -} \ No newline at end of file +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 +}