Skip to content

Commit 1af908a

Browse files
committed
Rule 7.0.4: Improve reporting
- Use BinaryOperations library to merge reporting of assign and binary operations. - Report the actual type of the operand. - Report the operand which is in contravention, instead of the operation. - Split reporting of cases where a constant is not valid from cases where the it is not unsigned for better reporting.
1 parent 3e2534b commit 1af908a

File tree

2 files changed

+96
-110
lines changed

2 files changed

+96
-110
lines changed

cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql

Lines changed: 47 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import cpp
1616
import codingstandards.cpp.misra
1717
import codingstandards.cpp.misra.BuiltInTypeRules
18+
import codingstandards.cpp.BinaryOperations
1819

1920
predicate isConstantExpression(Expr e) {
2021
e instanceof Literal or
@@ -50,91 +51,70 @@ predicate isSignedConstantLeftShiftException(LShiftExpr shift) {
5051
)
5152
}
5253

53-
class BinaryShiftOperation extends BinaryOperation {
54-
BinaryShiftOperation() {
55-
this instanceof LShiftExpr or
56-
this instanceof RShiftExpr
57-
}
58-
}
59-
60-
class AssignShiftOperation extends AssignOperation {
61-
AssignShiftOperation() {
62-
this instanceof AssignLShiftExpr or
63-
this instanceof AssignRShiftExpr
64-
}
65-
}
66-
6754
from Expr x, string message
6855
where
6956
not isExcluded(x, ConversionsPackage::inappropriateBitwiseOrShiftOperandsQuery()) and
7057
(
7158
// Binary bitwise operators (excluding shift operations) - both operands must be unsigned
72-
exists(BinaryBitwiseOperation op |
73-
not op instanceof BinaryShiftOperation and
74-
op = x and
75-
not (
76-
isUnsignedType(op.getLeftOperand().getExplicitlyConverted().getType()) and
77-
isUnsignedType(op.getRightOperand().getExplicitlyConverted().getType())
78-
) and
59+
exists(BinaryBitwiseOpOrAssignOp op, Type operandType |
60+
not op instanceof BinaryShiftOpOrAssignOp
61+
|
62+
x = op.getLeftOperand() and
63+
operandType = op.getLeftOperand().getExplicitlyConverted().getType() and
64+
not isUnsignedType(operandType) and
7965
message =
80-
"Binary bitwise operator '" + op.getOperator() + "' requires both operands to be unsigned."
81-
)
82-
or
83-
// Compound assignment bitwise operators - both operands must be unsigned
84-
exists(AssignBitwiseOperation op |
85-
not op instanceof AssignShiftOperation and
86-
op = x and
87-
not (
88-
isUnsignedType(op.getLValue().getExplicitlyConverted().getType()) and
89-
isUnsignedType(op.getRValue().getExplicitlyConverted().getType())
90-
) and
66+
"Bitwise operator '" + op.getOperator() +
67+
"' requires unsigned numeric operands, but the left operand has type '" + operandType +
68+
"'."
69+
or
70+
x = op.getRightOperand() and
71+
operandType = op.getRightOperand().getExplicitlyConverted().getType() and
72+
not isUnsignedType(operandType) and
9173
message =
92-
"Compound assignment bitwise operator '" + op.getOperator() +
93-
"' requires both operands to be unsigned."
74+
"Bitwise operator '" + op.getOperator() +
75+
"' requires unsigned numeric operands, but the right operand has type '" + operandType +
76+
"'."
9477
)
9578
or
9679
// Bit complement operator - operand must be unsigned
97-
exists(ComplementExpr comp |
98-
comp = x and
99-
not isUnsignedType(comp.getOperand().getExplicitlyConverted().getType()) and
100-
message = "Bit complement operator '~' requires unsigned operand."
80+
exists(ComplementExpr comp, Type opType |
81+
x = comp.getOperand() and
82+
opType = comp.getOperand().getExplicitlyConverted().getType() and
83+
not isUnsignedType(opType) and
84+
message =
85+
"Bit complement operator '~' requires unsigned operand, but has type '" + opType + "'."
10186
)
10287
or
10388
// Shift operators - left operand must be unsigned
104-
exists(BinaryShiftOperation shift |
105-
shift = x and
106-
not isUnsignedType(shift.getLeftOperand().getExplicitlyConverted().getType()) and
89+
exists(BinaryShiftOpOrAssignOp shift, Type leftType |
90+
x = shift.getLeftOperand() and
91+
leftType = shift.getLeftOperand().getExplicitlyConverted().getType() and
92+
not isUnsignedType(leftType) and
10793
not isSignedConstantLeftShiftException(shift) and
108-
message = "Shift operator '" + shift.getOperator() + "' requires unsigned left operand."
109-
)
110-
or
111-
// Compound assignment shift operators - left operand must be unsigned
112-
exists(AssignShiftOperation shift |
113-
shift = x and
114-
not isUnsignedType(shift.getLValue().getExplicitlyConverted().getType()) and
115-
message = "Shift operator '" + shift.getOperator() + "' requires unsigned left operand."
116-
)
117-
or
118-
// Shift operators - right operand must be unsigned or constant in valid range
119-
exists(BinaryShiftOperation shift, Expr right |
120-
shift = x and
121-
right = shift.getRightOperand() and
122-
not isUnsignedType(right.getExplicitlyConverted().getType()) and
123-
not isValidShiftConstantRange(right, shift.getLeftOperand().getExplicitlyConverted().getType()) and
12494
message =
12595
"Shift operator '" + shift.getOperator() +
126-
"' requires unsigned right operand or constant in valid range."
96+
"' requires unsigned left operand, but has type '" + leftType + "'."
12797
)
12898
or
129-
// Compound assignment shift operators - right operand must be unsigned or constant in valid range
130-
exists(AssignShiftOperation shift, Expr right |
131-
shift = x and
132-
right = shift.getRValue() and
133-
not isUnsignedType(right.getExplicitlyConverted().getType()) and
134-
not isValidShiftConstantRange(right, shift.getLValue().getExplicitlyConverted().getType()) and
135-
message =
136-
"Shift operator '" + shift.getOperator() +
137-
"' requires unsigned right operand or constant in valid range."
99+
// Shift operators - right operand must be unsigned or constant in valid range
100+
exists(BinaryShiftOpOrAssignOp shift, Expr right, Type rightType, Type leftType |
101+
right = shift.getRightOperand() and
102+
x = right and
103+
rightType = right.getExplicitlyConverted().getType() and
104+
leftType = shift.getLeftOperand().getExplicitlyConverted().getType()
105+
|
106+
if exists(right.getValue().toInt())
107+
then
108+
not isValidShiftConstantRange(right, leftType) and
109+
message =
110+
"Shift operator '" + shift.getOperator() + "' shifts by " + right.getValue().toInt() +
111+
" which is not within the valid range 0.." + ((leftType.getSize() * 8) - 1) + "."
112+
else (
113+
not isUnsignedType(rightType) and
114+
message =
115+
"Shift operator '" + shift.getOperator() +
116+
"' requires unsigned right operand, but has type '" + rightType + "'."
117+
)
138118
)
139119
)
140120
select x, message
Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,49 @@
1-
| test.cpp:14:3:14:13 | ... & ... | Binary bitwise operator '&' requires both operands to be unsigned. |
2-
| test.cpp:15:3:15:13 | ... \| ... | Binary bitwise operator '\|' requires both operands to be unsigned. |
3-
| test.cpp:16:3:16:13 | ... ^ ... | Binary bitwise operator '^' requires both operands to be unsigned. |
4-
| test.cpp:18:3:18:13 | ... & ... | Binary bitwise operator '&' requires both operands to be unsigned. |
5-
| test.cpp:19:3:19:13 | ... \| ... | Binary bitwise operator '\|' requires both operands to be unsigned. |
6-
| test.cpp:30:3:30:15 | ... &= ... | Compound assignment bitwise operator '&=' requires both operands to be unsigned. |
7-
| test.cpp:31:3:31:15 | ... \|= ... | Compound assignment bitwise operator '\|=' requires both operands to be unsigned. |
8-
| test.cpp:32:3:32:15 | ... ^= ... | Compound assignment bitwise operator '^=' requires both operands to be unsigned. |
9-
| test.cpp:42:3:42:6 | ~ ... | Bit complement operator '~' requires unsigned operand. |
10-
| test.cpp:54:3:54:9 | ... << ... | Shift operator '<<' requires unsigned left operand. |
11-
| test.cpp:55:3:55:11 | ... << ... | Shift operator '<<' requires unsigned left operand. |
12-
| test.cpp:63:3:63:18 | ... << ... | Shift operator '<<' requires unsigned left operand. |
13-
| test.cpp:74:3:74:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. |
14-
| test.cpp:75:3:75:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. |
15-
| test.cpp:85:3:85:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. |
16-
| test.cpp:86:3:86:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. |
17-
| test.cpp:87:3:87:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. |
18-
| test.cpp:93:3:93:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. |
19-
| test.cpp:94:3:94:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. |
20-
| test.cpp:95:3:95:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. |
21-
| test.cpp:96:3:96:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. |
22-
| test.cpp:115:3:115:12 | ... <<= ... | Shift operator '<<=' requires unsigned left operand. |
23-
| test.cpp:116:3:116:12 | ... >>= ... | Shift operator '>>=' requires unsigned left operand. |
24-
| test.cpp:117:3:117:11 | ... <<= ... | Shift operator '<<=' requires unsigned left operand. |
25-
| test.cpp:118:3:118:11 | ... >>= ... | Shift operator '>>=' requires unsigned left operand. |
26-
| test.cpp:121:3:121:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. |
27-
| test.cpp:122:3:122:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. |
28-
| test.cpp:125:3:125:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. |
29-
| test.cpp:126:3:126:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. |
30-
| test.cpp:127:3:127:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. |
31-
| test.cpp:130:3:130:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. |
32-
| test.cpp:131:3:131:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. |
33-
| test.cpp:132:3:132:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. |
34-
| test.cpp:133:3:133:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. |
35-
| test.cpp:143:3:143:9 | ... << ... | Shift operator '<<' requires unsigned left operand. |
36-
| test.cpp:144:3:144:9 | ... << ... | Shift operator '<<' requires unsigned left operand. |
37-
| test.cpp:145:3:145:9 | ... << ... | Shift operator '<<' requires unsigned left operand. |
38-
| test.cpp:146:3:146:9 | ... << ... | Shift operator '<<' requires unsigned left operand. |
39-
| test.cpp:150:3:150:11 | ... << ... | Shift operator '<<' requires unsigned left operand. |
40-
| test.cpp:154:3:154:30 | ... << ... | Shift operator '<<' requires unsigned left operand. |
41-
| test.cpp:156:3:156:17 | ... << ... | Shift operator '<<' requires unsigned left operand. |
42-
| test.cpp:162:3:162:10 | ... << ... | Shift operator '<<' requires unsigned left operand. |
43-
| test.cpp:170:3:170:11 | ... >> ... | Shift operator '>>' requires unsigned left operand. |
1+
| test.cpp:14:3:14:6 | s32a | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'int32_t'. |
2+
| test.cpp:14:10:14:13 | s32b | Bitwise operator '&' requires unsigned numeric operands, but the right operand has type 'int32_t'. |
3+
| test.cpp:15:3:15:6 | s32a | Bitwise operator '\|' requires unsigned numeric operands, but the left operand has type 'int32_t'. |
4+
| test.cpp:15:10:15:13 | s32b | Bitwise operator '\|' requires unsigned numeric operands, but the right operand has type 'int32_t'. |
5+
| test.cpp:16:3:16:6 | s32a | Bitwise operator '^' requires unsigned numeric operands, but the left operand has type 'int32_t'. |
6+
| test.cpp:16:10:16:13 | s32b | Bitwise operator '^' requires unsigned numeric operands, but the right operand has type 'int32_t'. |
7+
| test.cpp:18:3:18:6 | s32a | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'int32_t'. |
8+
| test.cpp:19:10:19:13 | s32b | Bitwise operator '\|' requires unsigned numeric operands, but the right operand has type 'int32_t'. |
9+
| test.cpp:30:3:30:5 | s32 | Bitwise operator '&=' requires unsigned numeric operands, but the left operand has type 'int32_t'. |
10+
| test.cpp:30:10:30:15 | 65535 | Bitwise operator '&=' requires unsigned numeric operands, but the right operand has type 'int'. |
11+
| test.cpp:31:3:31:5 | s32 | Bitwise operator '\|=' requires unsigned numeric operands, but the left operand has type 'int32_t'. |
12+
| test.cpp:31:10:31:15 | 4096 | Bitwise operator '\|=' requires unsigned numeric operands, but the right operand has type 'int'. |
13+
| test.cpp:32:3:32:5 | s32 | Bitwise operator '^=' requires unsigned numeric operands, but the left operand has type 'int32_t'. |
14+
| test.cpp:32:10:32:15 | 21845 | Bitwise operator '^=' requires unsigned numeric operands, but the right operand has type 'int'. |
15+
| test.cpp:42:4:42:6 | s32 | Bit complement operator '~' requires unsigned operand, but has type 'int32_t'. |
16+
| test.cpp:54:3:54:3 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
17+
| test.cpp:55:3:55:5 | s32 | Shift operator '<<' requires unsigned left operand, but has type 'int32_t'. |
18+
| test.cpp:63:4:63:11 | ... + ... | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
19+
| test.cpp:74:10:74:11 | s8 | Shift operator '<<' requires unsigned right operand, but has type 'int8_t'. |
20+
| test.cpp:75:10:75:11 | s8 | Shift operator '>>' requires unsigned right operand, but has type 'int8_t'. |
21+
| test.cpp:85:10:85:11 | 32 | Shift operator '<<' shifts by 32 which is not within the valid range 0..31. |
22+
| test.cpp:86:10:86:11 | 64 | Shift operator '<<' shifts by 64 which is not within the valid range 0..31. |
23+
| test.cpp:87:10:87:11 | 32 | Shift operator '>>' shifts by 32 which is not within the valid range 0..31. |
24+
| test.cpp:93:10:93:11 | - ... | Shift operator '<<' shifts by -1 which is not within the valid range 0..31. |
25+
| test.cpp:94:10:94:11 | - ... | Shift operator '<<' shifts by -5 which is not within the valid range 0..31. |
26+
| test.cpp:95:10:95:11 | - ... | Shift operator '>>' shifts by -1 which is not within the valid range 0..31. |
27+
| test.cpp:96:10:96:11 | - ... | Shift operator '>>' shifts by -3 which is not within the valid range 0..31. |
28+
| test.cpp:115:3:115:5 | s32 | Shift operator '<<=' requires unsigned left operand, but has type 'int32_t'. |
29+
| test.cpp:116:3:116:5 | s32 | Shift operator '>>=' requires unsigned left operand, but has type 'int32_t'. |
30+
| test.cpp:117:3:117:5 | s32 | Shift operator '<<=' requires unsigned left operand, but has type 'int32_t'. |
31+
| test.cpp:118:3:118:5 | s32 | Shift operator '>>=' requires unsigned left operand, but has type 'int32_t'. |
32+
| test.cpp:121:11:121:12 | s8 | Shift operator '<<=' requires unsigned right operand, but has type 'int8_t'. |
33+
| test.cpp:122:11:122:12 | s8 | Shift operator '>>=' requires unsigned right operand, but has type 'int8_t'. |
34+
| test.cpp:125:11:125:12 | 32 | Shift operator '<<=' shifts by 32 which is not within the valid range 0..31. |
35+
| test.cpp:126:11:126:12 | 64 | Shift operator '<<=' shifts by 64 which is not within the valid range 0..31. |
36+
| test.cpp:127:11:127:12 | 32 | Shift operator '>>=' shifts by 32 which is not within the valid range 0..31. |
37+
| test.cpp:130:11:130:12 | - ... | Shift operator '<<=' shifts by -1 which is not within the valid range 0..31. |
38+
| test.cpp:131:11:131:12 | - ... | Shift operator '<<=' shifts by -5 which is not within the valid range 0..31. |
39+
| test.cpp:132:11:132:12 | - ... | Shift operator '>>=' shifts by -1 which is not within the valid range 0..31. |
40+
| test.cpp:133:11:133:12 | - ... | Shift operator '>>=' shifts by -3 which is not within the valid range 0..31. |
41+
| test.cpp:143:3:143:3 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
42+
| test.cpp:144:3:144:3 | 2 | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
43+
| test.cpp:145:3:145:3 | 4 | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
44+
| test.cpp:146:3:146:3 | 8 | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
45+
| test.cpp:150:3:150:5 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'long long'. |
46+
| test.cpp:154:3:154:25 | 4611686018427387904 | Shift operator '<<' requires unsigned left operand, but has type 'long long'. |
47+
| test.cpp:156:3:156:12 | 1073741824 | Shift operator '<<' requires unsigned left operand, but has type 'int'. |
48+
| test.cpp:162:3:162:5 | s32 | Shift operator '<<' requires unsigned left operand, but has type 'int32_t'. |
49+
| test.cpp:170:3:170:5 | s32 | Shift operator '>>' requires unsigned left operand, but has type 'int32_t'. |

0 commit comments

Comments
 (0)