diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp index f0d58bf60..ef63ce9f1 100644 --- a/lib/checkbool.cpp +++ b/lib/checkbool.cpp @@ -172,7 +172,7 @@ void CheckBool::comparisonOfBoolWithInvalidComparator(const Token *tok, const st static bool tokenIsFunctionReturningBool(const Token* tok) { - const Function* func = tok->function(); + const Function* func = tok ? tok->function() : nullptr; if (func && Token::Match(tok, "%name% (")) { if (func->tokenDef && Token::Match(func->tokenDef->previous(), "bool|_Bool")) { return true; @@ -190,19 +190,26 @@ void CheckBool::checkComparisonOfFuncReturningBool() return; const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase(); + auto getFunctionTok = [](const Token* tok) -> const Token* { + while (Token::simpleMatch(tok, "!") || (tok && tok->isCast() && !isCPPCast(tok))) + tok = tok->astOperand1(); + if (isCPPCast(tok)) + tok = tok->astOperand2(); + if (tok) + return tok->previous(); + return nullptr; + }; for (const Scope * scope : symbolDatabase->functionScopes) { for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { if (!tok->isComparisonOp() || tok->str() == "==" || tok->str() == "!=") continue; - const Token *firstToken = tok->previous(); - if (tok->strAt(-1) == ")") { - firstToken = firstToken->link()->previous(); - } - const Token *secondToken = tok->next(); - while (secondToken->str() == "!") { - secondToken = secondToken->next(); - } + + const Token* firstToken = getFunctionTok(tok->astOperand1()); + const Token* secondToken = getFunctionTok(tok->astOperand2()); + if (!firstToken || !secondToken) + continue; + const bool firstIsFunctionReturningBool = tokenIsFunctionReturningBool(firstToken); const bool secondIsFunctionReturningBool = tokenIsFunctionReturningBool(secondToken); if (firstIsFunctionReturningBool && secondIsFunctionReturningBool) { diff --git a/test/testbool.cpp b/test/testbool.cpp index 6f0dbde10..eb4443313 100644 --- a/test/testbool.cpp +++ b/test/testbool.cpp @@ -63,6 +63,7 @@ private: TEST_CASE(checkComparisonOfFuncReturningBool4); TEST_CASE(checkComparisonOfFuncReturningBool5); TEST_CASE(checkComparisonOfFuncReturningBool6); + TEST_CASE(checkComparisonOfFuncReturningBool7); // #7197 // Integration tests.. TEST_CASE(checkComparisonOfFuncReturningBoolIntegrationTest1); // #7798 overloaded functions @@ -710,6 +711,24 @@ private: ASSERT_EQUALS("", errout.str()); } + void checkComparisonOfFuncReturningBool7() { // #7197 + check("struct C {\n" + " bool isEmpty();\n" + "};\n" + "void f() {\n" + " C c1, c2;\n" + " if ((c1.isEmpty()) < (c2.isEmpty())) {}\n" + " if (!c1.isEmpty() < !!c2.isEmpty()) {}\n" + " if ((int)c1.isEmpty() < (int)c2.isEmpty()) {}\n" + " if (static_cast(c1.isEmpty()) < static_cast(c2.isEmpty())) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n" + "[test.cpp:7]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n" + "[test.cpp:8]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n" + "[test.cpp:9]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n", + errout.str()); + } + void checkComparisonOfFuncReturningBoolIntegrationTest1() { // #7798 check("bool eval(double *) { return false; }\n" "double eval(char *) { return 1.0; }\n"