Skip to content

Commit 1d2aa2e

Browse files
committed
RULE-7-0-1 - NoConversionFromBool
Detects implicit and explicit conversions from type bool to other types, preventing potential confusion between bitwise and logical operators and ensuring clear type usage. [a]
1 parent 42985d7 commit 1d2aa2e

File tree

4 files changed

+174
-0
lines changed

4 files changed

+174
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @id cpp/misra/no-conversion-from-bool
3+
* @name RULE-7-0-1: There shall be no conversion from type bool
4+
* @description Converting a bool type (implicitly or explicitly) to another type can lead to
5+
* unintended behavior and code obfuscation, particularly when using bitwise operators
6+
* instead of logical operators.
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-7-0-1
11+
* scope/single-translation-unit
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
19+
from Expr e, Conversion conv
20+
where
21+
not isExcluded(e, ConversionsPackage::noConversionFromBoolQuery()) and
22+
conv = e.getConversion() and
23+
conv.getExpr().getType().stripTopLevelSpecifiers() instanceof BoolType and
24+
not conv.getType().stripTopLevelSpecifiers() instanceof BoolType and
25+
// Exclude cases that are explicitly allowed
26+
not (
27+
// Exception: equality operators with both bool operands
28+
exists(EQExpr eq |
29+
eq.getAnOperand() = e and
30+
eq.getLeftOperand().getType().stripTopLevelSpecifiers() instanceof BoolType and
31+
eq.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType
32+
) or
33+
exists(NEExpr ne |
34+
ne.getAnOperand() = e and
35+
ne.getLeftOperand().getType().stripTopLevelSpecifiers() instanceof BoolType and
36+
ne.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType
37+
) or
38+
// Exception: explicit constructor calls
39+
exists(ConstructorCall cc | cc.getAnArgument() = e) or
40+
// Exception: assignment to bit-field of length 1
41+
exists(AssignExpr assign |
42+
assign.getRValue() = e and
43+
assign.getLValue().(ValueFieldAccess).getTarget() instanceof BitField and
44+
assign.getLValue().(ValueFieldAccess).getTarget().(BitField).getNumBits() = 1
45+
)
46+
)
47+
select e, "Conversion from 'bool' to '" + conv.getType().toString() + "'."
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
| test.cpp:23:9:23:10 | b1 | Conversion from 'bool' to 'int'. |
2+
| test.cpp:23:14:23:15 | b2 | Conversion from 'bool' to 'int'. |
3+
| test.cpp:24:9:24:10 | b1 | Conversion from 'bool' to 'int'. |
4+
| test.cpp:24:14:24:15 | b2 | Conversion from 'bool' to 'int'. |
5+
| test.cpp:25:9:25:10 | b1 | Conversion from 'bool' to 'int'. |
6+
| test.cpp:25:14:25:15 | b2 | Conversion from 'bool' to 'int'. |
7+
| test.cpp:26:10:26:11 | b1 | Conversion from 'bool' to 'int'. |
8+
| test.cpp:29:9:29:10 | b1 | Conversion from 'bool' to 'int'. |
9+
| test.cpp:29:14:29:15 | b2 | Conversion from 'bool' to 'int'. |
10+
| test.cpp:30:9:30:10 | b1 | Conversion from 'bool' to 'int'. |
11+
| test.cpp:30:14:30:15 | b2 | Conversion from 'bool' to 'int'. |
12+
| test.cpp:31:9:31:10 | b1 | Conversion from 'bool' to 'int'. |
13+
| test.cpp:31:15:31:16 | b2 | Conversion from 'bool' to 'int'. |
14+
| test.cpp:32:9:32:10 | b1 | Conversion from 'bool' to 'int'. |
15+
| test.cpp:32:15:32:16 | b2 | Conversion from 'bool' to 'int'. |
16+
| test.cpp:35:9:35:10 | b1 | Conversion from 'bool' to 'int'. |
17+
| test.cpp:36:9:36:10 | b1 | Conversion from 'bool' to 'int'. |
18+
| test.cpp:37:9:37:10 | b1 | Conversion from 'bool' to 'int'. |
19+
| test.cpp:40:22:40:23 | b1 | Conversion from 'bool' to 'double'. |
20+
| test.cpp:41:22:41:23 | b1 | Conversion from 'bool' to 'double'. |
21+
| test.cpp:42:30:42:31 | b1 | Conversion from 'bool' to 'int'. |
22+
| test.cpp:45:36:45:37 | b1 | Conversion from 'bool' to 'int8_t'. |
23+
| test.cpp:46:38:46:39 | b1 | Conversion from 'bool' to 'int32_t'. |
24+
| test.cpp:49:8:49:9 | b1 | Conversion from 'bool' to 'int32_t'. |
25+
| test.cpp:50:8:50:9 | b1 | Conversion from 'bool' to 'double'. |
26+
| test.cpp:53:13:53:14 | b1 | Conversion from 'bool' to 'int'. |
27+
| test.cpp:59:11:59:12 | b1 | Conversion from 'bool' to 'int8_t'. |
28+
| test.cpp:60:12:60:13 | b1 | Conversion from 'bool' to 'int32_t'. |
29+
| test.cpp:61:10:61:11 | b1 | Conversion from 'bool' to 'double'. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-7-0-1/NoConversionFromBool.ql
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include <cstdint>
2+
3+
struct A {
4+
explicit A(bool) {}
5+
};
6+
7+
struct BitField {
8+
std::uint8_t bit : 1;
9+
};
10+
11+
void f1(std::int32_t n) {}
12+
void f2(double d) {}
13+
14+
void test_bool_conversion_violations() {
15+
bool b1 = true;
16+
bool b2 = false;
17+
double d1 = 1.0;
18+
std::int8_t s8a = 0;
19+
std::int32_t s32a = 0;
20+
BitField bf;
21+
22+
// Bitwise operations - non-compliant
23+
if (b1 & b2) {} // NON_COMPLIANT
24+
if (b1 | b2) {} // NON_COMPLIANT
25+
if (b1 ^ b2) {} // NON_COMPLIANT
26+
if (~b1) {} // NON_COMPLIANT
27+
28+
// Relational operations - non-compliant
29+
if (b1 < b2) {} // NON_COMPLIANT
30+
if (b1 > b2) {} // NON_COMPLIANT
31+
if (b1 <= b2) {} // NON_COMPLIANT
32+
if (b1 >= b2) {} // NON_COMPLIANT
33+
34+
// Comparison with integer literals - non-compliant
35+
if (b1 == 0) {} // NON_COMPLIANT
36+
if (b1 == 1) {} // NON_COMPLIANT
37+
if (b1 != 0) {} // NON_COMPLIANT
38+
39+
// Arithmetic operations - non-compliant
40+
double l1 = d1 * b1; // NON_COMPLIANT
41+
double l2 = d1 + b1; // NON_COMPLIANT
42+
std::int32_t l3 = s32a + b1; // NON_COMPLIANT
43+
44+
// Explicit casts to integral types - non-compliant
45+
s8a = static_cast<std::int8_t>(b1); // NON_COMPLIANT
46+
s32a = static_cast<std::int32_t>(b1); // NON_COMPLIANT
47+
48+
// Function parameter conversion - non-compliant
49+
f1(b1); // NON_COMPLIANT
50+
f2(b1); // NON_COMPLIANT
51+
52+
// Switch statement - non-compliant
53+
switch (b1) { // NON_COMPLIANT
54+
case 0: break;
55+
case 1: break;
56+
}
57+
58+
// Assignment to integral types - non-compliant
59+
s8a = b1; // NON_COMPLIANT
60+
s32a = b1; // NON_COMPLIANT
61+
d1 = b1; // NON_COMPLIANT
62+
}
63+
64+
void test_bool_conversion_compliant() {
65+
bool b1 = true;
66+
bool b2 = false;
67+
std::int8_t s8a = 0;
68+
BitField bf;
69+
70+
// Boolean equality operations - compliant
71+
if (b1 == false) {} // COMPLIANT
72+
if (b1 == true) {} // COMPLIANT
73+
if (b1 == b2) {} // COMPLIANT
74+
if (b1 != b2) {} // COMPLIANT
75+
76+
// Logical operations - compliant
77+
if (b1 && b2) {} // COMPLIANT
78+
if (b1 || b2) {} // COMPLIANT
79+
if (!b1) {} // COMPLIANT
80+
81+
// Conditional operator without conversion - compliant
82+
s8a = b1 ? 3 : 7; // COMPLIANT
83+
84+
// Function parameter without conversion - compliant
85+
f1(b1 ? 1 : 0); // COMPLIANT
86+
87+
// Explicit constructor calls - compliant
88+
A l1{true}; // COMPLIANT
89+
A l2(false); // COMPLIANT
90+
A l3 = static_cast<A>(true); // COMPLIANT
91+
92+
// Assignment to constructor - compliant
93+
A l4 = A{false}; // COMPLIANT
94+
95+
// Bit-field assignment exception - compliant
96+
bf.bit = b1; // COMPLIANT
97+
}

0 commit comments

Comments
 (0)