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,7 @@
- `RULE-7-0-2` - `NoImplicitBoolConversion.ql`:
- Fixed false positives on the initializer of an `if`/`for` condition
declaration (e.g. `if (T* p = f())` or `if (auto sp = weak.lock())`) when
the initialized type is a pointer or a class with an explicit
`operator bool`. These are contextual conversions, which are permitted.
- Fixed false positives on `static_cast<bool>` of a class type with an
explicit `operator bool` inside a class template.
32 changes: 31 additions & 1 deletion cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@
import cpp
import codingstandards.cpp.misra

/**
* The initializer of a condition declaration is contextually converted to bool, e.g.
* `if (T* p = f())` or `if (auto sp = weak.lock())`.
*/
predicate isInConditionDeclarationInitializer(Expr expr) {
exists(ConditionDeclExpr condDecl |
condDecl.getExpr() = expr and
(
exists(IfStmt ifStmt | ifStmt.getCondition() = condDecl) or
exists(WhileStmt whileStmt | whileStmt.getCondition() = condDecl) or
exists(ForStmt forStmt | forStmt.getCondition() = condDecl)
)
)
}

predicate isInContextualBoolContext(Expr expr) {
exists(IfStmt ifStmt | ifStmt.getCondition() = expr) or
exists(WhileStmt whileStmt | whileStmt.getCondition() = expr) or
Expand All @@ -24,7 +39,8 @@ predicate isInContextualBoolContext(Expr expr) {
exists(ConditionalExpr condExpr | condExpr.getCondition() = expr) or
exists(LogicalAndExpr logicalAnd | logicalAnd.getAnOperand() = expr) or
exists(LogicalOrExpr logicalOr | logicalOr.getAnOperand() = expr) or
exists(NotExpr notExpr | notExpr.getOperand() = expr)
exists(NotExpr notExpr | notExpr.getOperand() = expr) or
isInConditionDeclarationInitializer(expr)
}

predicate isInWhileConditionDeclaration(Expr expr) {
Expand Down Expand Up @@ -88,6 +104,20 @@ where
// an array to a pointer, then the pointer to bool
isInContextualBoolContext(conv.getUnconverted())
) and
// Exception 1: Static cast to bool from a class with an explicit operator bool. In an
// uninstantiated template the cast has no resolved call to the conversion operator, so it
// appears only as a `Conversion` from the class type.
not (
conv instanceof StaticCast and
exists(ConversionOperator op |
op.isExplicit() and
op.getType().getUnspecifiedType() instanceof BoolType and
exists(Class source | source = conv.getExpr().getType().getUnspecifiedType() |
op = source.getAMember() or
op = source.(ClassTemplateInstantiation).getTemplate().getAMember()
)
)
) and
// Exception 3: Unconverted expression is a bit-field of size 1
not isBitFieldOfSizeOne(conv.getUnconverted()) and
// Exception 4: Unconverted expression is in a while condition declaration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
| test.cpp:201:13:201:14 | (bool)... | Conversion from 'int32_t *' to 'bool'. |
| test.cpp:213:13:213:14 | (bool)... | Conversion from '..:: *' to 'bool'. |
| test.cpp:214:13:214:14 | (bool)... | Conversion from '..:: *' to 'bool'. |
| test.cpp:283:20:283:21 | (bool)... | Conversion from 'int32_t' to 'bool'. |
32 changes: 31 additions & 1 deletion cpp/misra/test/rules/RULE-7-0-2/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,34 @@ constexpr bool derived_from_template_v = is_something_v<T>; // COMPLIANT

bool test_dependent_variable_template_instantiation() {
return derived_from_template_v<std::int32_t>; // COMPLIANT
}
}
void test_condition_declaration() {
if (std::int32_t *l1 = f3()) { // COMPLIANT - exception #2
}
if (auto *const l2 = f3()) { // COMPLIANT - exception #2
}
while (std::int32_t *l3 = f3()) { // COMPLIANT - exception #2
}
if (TestClassExplicit l4 = TestClassExplicit{}) { // COMPLIANT
}
if (std::int32_t *l5 = f3(); l5) { // COMPLIANT - exception #2
}
if (std::int32_t l6 = f1()) { // NON_COMPLIANT
}
}

template <typename T> class TestTemplateExplicit {
public:
explicit operator bool() const { return true; }
};

template <typename T>
bool test_static_cast_template(const TestTemplateExplicit<T> &l1) {
return !static_cast<bool>(l1); // COMPLIANT - exception #1
}

bool test_static_cast_template_use(
const TestTemplateExplicit<std::int32_t> &l1) {
bool l2 = static_cast<bool>(l1); // COMPLIANT - exception #1
return l2 && test_static_cast_template(l1);
}
Loading