Skip to content
Open
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
@@ -0,0 +1,11 @@
- `RULE-7-0-4` - `InappropriateBitwiseOrShiftOperands.ql`:
- Fixes #1177 - the rule no longer reports operands whose type is not a MISRA numeric type. The
operand checks used `not isUnsignedType(operandType)`, which is vacuously true for every type
that has no MISRA numeric type at all, such as class types and the unresolved dependent types
of uninstantiated template bodies. As a result the rule reported operations that do not use
the built-in operators, most notably the stream insertion and extraction operators. The checks
now use `isSignedType(operandType)` instead.
- Operands of character type, of a non-standard integral type, and of an unscoped enumeration
type without a fixed underlying type are consequently no longer reported, because none of them
has a MISRA numeric type. Unscoped enumerations without a fixed underlying type are covered by
`RULE-10-2-3`.
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ where
|
x = op.getLeftOperand() and
operandType = op.getLeftOperand().getExplicitlyConverted().getType() and
not MisraCpp23BuiltInTypes::isUnsignedType(operandType) and
MisraCpp23BuiltInTypes::isSignedType(operandType) and
message =
"Bitwise operator '" + op.getOperator() +
"' requires unsigned numeric operands, but the left operand has type '" + operandType +
"'."
or
x = op.getRightOperand() and
operandType = op.getRightOperand().getExplicitlyConverted().getType() and
not MisraCpp23BuiltInTypes::isUnsignedType(operandType) and
MisraCpp23BuiltInTypes::isSignedType(operandType) and
message =
"Bitwise operator '" + op.getOperator() +
"' requires unsigned numeric operands, but the right operand has type '" + operandType +
Expand All @@ -82,7 +82,7 @@ where
exists(ComplementExpr comp, Type opType |
x = comp.getOperand() and
opType = comp.getOperand().getExplicitlyConverted().getType() and
not MisraCpp23BuiltInTypes::isUnsignedType(opType) and
MisraCpp23BuiltInTypes::isSignedType(opType) and
message =
"Bit complement operator '~' requires unsigned operand, but has type '" + opType + "'."
)
Expand All @@ -91,7 +91,7 @@ where
exists(BinaryShiftOpOrAssignOp shift, Type leftType |
x = shift.getLeftOperand() and
leftType = shift.getLeftOperand().getExplicitlyConverted().getType() and
not MisraCpp23BuiltInTypes::isUnsignedType(leftType) and
MisraCpp23BuiltInTypes::isSignedType(leftType) and
not isSignedConstantLeftShiftException(shift) and
message =
"Shift operator '" + shift.getOperator() +
Expand All @@ -112,7 +112,7 @@ where
"Shift operator '" + shift.getOperator() + "' shifts by " + right.getValue().toInt() +
" which is not within the valid range 0.." + ((leftType.getSize() * 8) - 1) + "."
else (
not MisraCpp23BuiltInTypes::isUnsignedType(rightType) and
MisraCpp23BuiltInTypes::isSignedType(rightType) and
message =
"Shift operator '" + shift.getOperator() +
"' requires unsigned right operand, but has type '" + rightType + "'."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@
| test.cpp:156:3:156:12 | 1073741824 | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
| test.cpp:162:3:162:5 | s32 | Shift operator '<<' requires unsigned left operand, but has type 'int32_t'. |
| test.cpp:170:3:170:5 | s32 | Shift operator '>>' requires unsigned left operand, but has type 'int32_t'. |
| test.cpp:201:3:201:7 | value | Shift operator '<<' requires unsigned left operand, but has type 'signed int'. |
| test.cpp:226:3:226:4 | e3 | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'UnscopedEnumSignedUnderlyingType'. |
| test.cpp:226:7:226:8 | e3 | Bitwise operator '&' requires unsigned numeric operands, but the right operand has type 'UnscopedEnumSignedUnderlyingType'. |
68 changes: 67 additions & 1 deletion cpp/misra/test/rules/RULE-7-0-4/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,70 @@ void test_right_shift_signed_operands() {

u32 >> 1U; // COMPLIANT
s32 >> 1U; // NON_COMPLIANT
}
}

class TestStream {
public:
TestStream &operator<<(std::int32_t value);
TestStream &operator>>(std::int32_t &value);
};

void test_overloaded_shift_operators() {
TestStream stream;
std::int32_t s32 = 1;

// User provided operators, not the built-in shift operators
stream << 1; // COMPLIANT
stream << s32; // COMPLIANT
stream >> s32; // COMPLIANT
}

template <typename T>
void test_overloaded_shift_operators_in_template(TestStream &stream,
const T &value) {
// The left operand of the second `<<` is the `TestStream &` returned by the
// first one, and the right operand is dependent, so the operation is
// unresolved in the uninstantiated template body
stream << 1 << value; // COMPLIANT
}

template <typename T> void test_dependent_shift_operands(T value) {
// Dependent operands are unresolved in the uninstantiated template body, but
// reported through the instantiation below
value << 2; // NON_COMPLIANT
}

void test_template_instantiations() {
TestStream stream;
test_overloaded_shift_operators_in_template(stream, 1);
test_dependent_shift_operands<std::int32_t>(1);
}
enum UnscopedEnumNoFixedUnderlyingType { EnumeratorA = 1, EnumeratorB = 2 };

enum UnscopedEnumUnsignedUnderlyingType : unsigned int { EnumeratorC = 1 };

enum UnscopedEnumSignedUnderlyingType : int { EnumeratorD = 1 };

void test_enum_operands() {
UnscopedEnumNoFixedUnderlyingType e1 = EnumeratorA;
UnscopedEnumUnsignedUnderlyingType e2 = EnumeratorC;
UnscopedEnumSignedUnderlyingType e3 = EnumeratorD;

// Without a fixed underlying type the enum has no MISRA numeric type, so the
// operands are not analysed by this rule
e1 &e1; // COMPLIANT

e2 &e2; // COMPLIANT

e3 &e3; // NON_COMPLIANT
}

void test_character_type_operands() {
char32_t c32 = 1;

// `char32_t` is of character type, not of numeric type, and is always
// unsigned
c32 &c32; // COMPLIANT
c32 << 1U; // COMPLIANT
~c32; // COMPLIANT
}
Loading