diff --git a/cfg/std.cfg b/cfg/std.cfg index 97f5ce015..0acf4a3ce 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -6884,6 +6884,18 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun + + + + + false + + + + + + + diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 868c48f9a..4c7ad9098 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1477,19 +1477,6 @@ static bool astIsBoolLike(const Token* tok) return astIsBool(tok) || isUsedAsBool(tok); } -bool isBooleanFuncArg(const Token* tok) { - if (tok->variable() && tok->variable()->valueType() && tok->variable()->valueType()->type == ValueType::BOOL) // skip trivial case: bool passed as bool - return false; - int argn{}; - const Token* ftok = getTokenArgumentFunction(tok, argn); - if (!ftok) - return false; - std::vector argvars = getArgumentVars(ftok, argn); - if (argvars.size() != 1) - return false; - return !argvars[0]->isReference() && argvars[0]->valueType() && argvars[0]->valueType()->type == ValueType::BOOL; -} - bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure, bool followVar, ErrorPath* errors) { if (tok1 == nullptr && tok2 == nullptr) diff --git a/lib/astutils.h b/lib/astutils.h index af5f6aff6..c34bdd81b 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -256,11 +256,6 @@ const Token* isInLoopCondition(const Token* tok); */ CPPCHECKLIB bool isUsedAsBool(const Token* const tok, const Settings* settings = nullptr); -/** - * Is token passed to a function taking a bool argument - */ -CPPCHECKLIB bool isBooleanFuncArg(const Token* tok); - /** * Are two conditions opposite * @param isNot do you want to know if cond1 is !cond2 or if cond1 and cond2 are non-overlapping. true: cond1==!cond2 false: cond1==true => cond2==false diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 36f67d753..2232c2be6 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -673,7 +673,7 @@ void CheckFunctions::returnLocalStdMove() const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope *scope : symbolDatabase->functionScopes) { // Expect return by-value - if (Function::returnsReference(scope->function, true)) + if (Function::returnsReference(scope->function, /*unknown*/ true, /*includeRValueRef*/ true)) continue; const auto rets = Function::findReturns(scope->function); for (const Token* ret : rets) { diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp index afdad191c..c9965b53e 100644 --- a/lib/checkstring.cpp +++ b/lib/checkstring.cpp @@ -288,13 +288,7 @@ void CheckString::checkIncorrectStringCompare() incorrectStringCompareError(tok->next(), "substr", end->strAt(1)); } } - } else if (Token::Match(tok, "&&|%oror%|( %str%|%char% &&|%oror%|)") && !Token::Match(tok, "( %str%|%char% )")) { - incorrectStringBooleanError(tok->next(), tok->strAt(1)); - } else if (Token::Match(tok, "if|while ( %str%|%char% )") && !tok->tokAt(2)->getValue(0)) { - incorrectStringBooleanError(tok->tokAt(2), tok->strAt(2)); - } else if (tok->str() == "?" && Token::Match(tok->astOperand1(), "%str%|%char%")) { - incorrectStringBooleanError(tok->astOperand1(), tok->astOperand1()->str()); - } else if (Token::Match(tok, "%str%") && isBooleanFuncArg(tok)) + } else if (Token::Match(tok, "%str%|%char%") && isUsedAsBool(tok)) incorrectStringBooleanError(tok, tok->str()); } } diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index c6a044125..4952c79d8 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -4503,6 +4503,11 @@ void stdstring() // valid s.assign("a"); + +#ifdef __cpp_lib_starts_ends_with + // cppcheck-suppress ignoredReturnValue + s.starts_with("abc"); +#endif } void stdvector() diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index 13589ac13..8eacf8b1c 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -1808,6 +1808,12 @@ private: " std::cout << p->msg;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("std::string&& f() {\n" // #11881 + " std::string s;\n" + " return std::move(s);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void negativeMemoryAllocationSizeError() { // #389 diff --git a/test/teststring.cpp b/test/teststring.cpp index 4829c56c8..87ffcccaa 100644 --- a/test/teststring.cpp +++ b/test/teststring.cpp @@ -735,7 +735,9 @@ private: " if('\\0'){}\n" " if(L'\\0'){}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n" + "[test.cpp:3]: (warning) Conversion of char literal L'\\0' to bool always evaluates to false.\n", + errout.str()); check("void f() {\n" " if('\\0' || cond){}\n" @@ -750,6 +752,22 @@ private: " f(\"abc\");\n" "}\n"); ASSERT_EQUALS("[test.cpp:4]: (warning) Conversion of string literal \"abc\" to bool always evaluates to true.\n", errout.str()); + + check("void g(bool);\n" + " void f(std::map>&m) {\n" + " if (m.count(\"abc\"))\n" + " g(m[\"abc\"][0] ? true : false);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("void g(bool b);\n" + "void f() {\n" + " g('\\0');\n" + " g('a');\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n" + "[test.cpp:4]: (warning) Conversion of char literal 'a' to bool always evaluates to true.\n", + errout.str()); } void deadStrcmp() {