Skip to content

Commit c76e634

Browse files
authored
Fix FPs in bitwiseOnBoolean (#3455)
1 parent 9e9a982 commit c76e634

3 files changed

Lines changed: 51 additions & 9 deletions

File tree

lib/checkbool.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ void CheckBool::incrementBooleanError(const Token *tok)
7272
);
7373
}
7474

75+
static bool isConvertedToBool(const Token* tok)
76+
{
77+
if (!tok->astParent())
78+
return false;
79+
return astIsBool(tok->astParent()) || Token::Match(tok->astParent()->previous(), "if|while (");
80+
}
81+
7582
//---------------------------------------------------------------------------
7683
// if (bool & bool) -> if (bool && bool)
7784
// if (bool | bool) -> if (bool || bool)
@@ -90,20 +97,29 @@ void CheckBool::checkBitwiseOnBoolean()
9097
for (const Scope * scope : symbolDatabase->functionScopes) {
9198
for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
9299
if (tok->isBinaryOp() && (tok->str() == "&" || tok->str() == "|")) {
93-
if (astIsBool(tok->astOperand1()) || astIsBool(tok->astOperand2())) {
94-
if (tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2())
95-
continue;
96-
const std::string expression = astIsBool(tok->astOperand1()) ? tok->astOperand1()->expressionString() : tok->astOperand2()->expressionString();
97-
bitwiseOnBooleanError(tok, expression, tok->str() == "&" ? "&&" : "||");
98-
}
100+
if (!(astIsBool(tok->astOperand1()) || astIsBool(tok->astOperand2())))
101+
continue;
102+
if (tok->str() == "|" && !isConvertedToBool(tok) && !(astIsBool(tok->astOperand1()) && astIsBool(tok->astOperand2())))
103+
continue;
104+
if (!isConstExpression(tok->astOperand1(), mSettings->library, true, mTokenizer->isCPP()))
105+
continue;
106+
if (!isConstExpression(tok->astOperand2(), mSettings->library, true, mTokenizer->isCPP()))
107+
continue;
108+
if (tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2())
109+
continue;
110+
const std::string expression = astIsBool(tok->astOperand1()) ? tok->astOperand1()->expressionString()
111+
: tok->astOperand2()->expressionString();
112+
bitwiseOnBooleanError(tok, expression, tok->str() == "&" ? "&&" : "||");
99113
}
100114
}
101115
}
102116
}
103117

104-
void CheckBool::bitwiseOnBooleanError(const Token *tok, const std::string &expression, const std::string &op)
118+
void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op)
105119
{
106-
reportError(tok, Severity::style, "bitwiseOnBoolean",
120+
reportError(tok,
121+
Severity::style,
122+
"bitwiseOnBoolean",
107123
"Boolean expression '" + expression + "' is used in bitwise operation. Did you mean '" + op + "'?",
108124
CWE398,
109125
Certainty::inconclusive);

lib/checkbool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class CPPCHECKLIB CheckBool : public Check {
104104
void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression);
105105
void assignBoolToPointerError(const Token *tok);
106106
void assignBoolToFloatError(const Token *tok);
107-
void bitwiseOnBooleanError(const Token *tok, const std::string &expression, const std::string &op);
107+
void bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op);
108108
void comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1);
109109
void pointerArithBoolError(const Token *tok);
110110
void returnValueBoolError(const Token *tok);

test/testbool.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,26 @@ class TestBool : public TestFixture {
810810
"}");
811811
ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean expression 'a>0' is used in bitwise operation. Did you mean '&&'?\n", errout.str());
812812

813+
check("void f(bool a, int b) {\n"
814+
" if(a | b) {}\n"
815+
"}");
816+
ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean expression 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str());
817+
818+
check("void f(int a, bool b) {\n"
819+
" if(a | b) {}\n"
820+
"}");
821+
ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean expression 'b' is used in bitwise operation. Did you mean '||'?\n", errout.str());
822+
823+
check("int f(bool a, int b) {\n"
824+
" return a | b;\n"
825+
"}");
826+
ASSERT_EQUALS("", errout.str());
827+
828+
check("bool f(bool a, int b) {\n"
829+
" return a | b;\n"
830+
"}");
831+
ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean expression 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str());
832+
813833
check("void f(int a, int b) {\n"
814834
" if(a & b) {}\n"
815835
"}");
@@ -824,6 +844,12 @@ class TestBool : public TestFixture {
824844
" class C { void foo(bool &b) {} };\n"
825845
"}");
826846
ASSERT_EQUALS("", errout.str());
847+
848+
check("bool f();\n"
849+
"bool g() {\n"
850+
" return f() | f();\n"
851+
"}\n");
852+
ASSERT_EQUALS("", errout.str());
827853
}
828854

829855
void incrementBoolean() {

0 commit comments

Comments
 (0)