Fix #11881 FP returnStdMoveLocal / Fix FP incorrectStringBooleanError / Support std::string::starts/ends_with() (#5347)

This commit is contained in:
chrchr-github 2023-08-21 10:43:54 +02:00 committed by GitHub
parent 03b952d5eb
commit 725c431ecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 44 additions and 27 deletions

View File

@ -6884,6 +6884,18 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/>
</arg>
</function>
<!-- constexpr bool std::string::starts_with( std::basic_string_view<CharT,Traits> sv ) const noexcept; // since C++20 -->
<!-- constexpr bool starts_with( CharT ch ) const noexcept; // since C++20 -->
<!-- constexpr bool starts_with( const CharT* s ) const; // since C++20 -->
<function name="std::string::starts_with,std::wstring::starts_with,std::string::ends_with,std::wstring::ends_with">
<noreturn>false</noreturn>
<use-retval/>
<returnValue type="bool"/>
<const/>
<arg nr="1" direction="in">
<not-uninit/>
</arg>
</function>
<!-- size_type std::string::copy( CharT* dest, size_type count, size_type pos = 0) const; -->
<!-- size_type std::wstring::copy( CharT* dest, size_type count, size_type pos = 0) const; -->
<function name="std::string::copy,std::wstring::copy">

View File

@ -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<const Variable*> 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)

View File

@ -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

View File

@ -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) {

View File

@ -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());
}
}

View File

@ -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()

View File

@ -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

View File

@ -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<std::string, std::vector<int>>&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() {