Fix #11881 FP returnStdMoveLocal / Fix FP incorrectStringBooleanError / Support std::string::starts/ends_with() (#5347)
This commit is contained in:
parent
03b952d5eb
commit
725c431ecc
12
cfg/std.cfg
12
cfg/std.cfg
|
@ -6884,6 +6884,18 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</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::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; -->
|
<!-- size_type std::wstring::copy( CharT* dest, size_type count, size_type pos = 0) const; -->
|
||||||
<function name="std::string::copy,std::wstring::copy">
|
<function name="std::string::copy,std::wstring::copy">
|
||||||
|
|
|
@ -1477,19 +1477,6 @@ static bool astIsBoolLike(const Token* tok)
|
||||||
return astIsBool(tok) || isUsedAsBool(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)
|
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)
|
if (tok1 == nullptr && tok2 == nullptr)
|
||||||
|
|
|
@ -256,11 +256,6 @@ const Token* isInLoopCondition(const Token* tok);
|
||||||
*/
|
*/
|
||||||
CPPCHECKLIB bool isUsedAsBool(const Token* const tok, const Settings* settings = nullptr);
|
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
|
* 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
|
* @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
|
||||||
|
|
|
@ -673,7 +673,7 @@ void CheckFunctions::returnLocalStdMove()
|
||||||
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
for (const Scope *scope : symbolDatabase->functionScopes) {
|
for (const Scope *scope : symbolDatabase->functionScopes) {
|
||||||
// Expect return by-value
|
// Expect return by-value
|
||||||
if (Function::returnsReference(scope->function, true))
|
if (Function::returnsReference(scope->function, /*unknown*/ true, /*includeRValueRef*/ true))
|
||||||
continue;
|
continue;
|
||||||
const auto rets = Function::findReturns(scope->function);
|
const auto rets = Function::findReturns(scope->function);
|
||||||
for (const Token* ret : rets) {
|
for (const Token* ret : rets) {
|
||||||
|
|
|
@ -288,13 +288,7 @@ void CheckString::checkIncorrectStringCompare()
|
||||||
incorrectStringCompareError(tok->next(), "substr", end->strAt(1));
|
incorrectStringCompareError(tok->next(), "substr", end->strAt(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (Token::Match(tok, "&&|%oror%|( %str%|%char% &&|%oror%|)") && !Token::Match(tok, "( %str%|%char% )")) {
|
} else if (Token::Match(tok, "%str%|%char%") && isUsedAsBool(tok))
|
||||||
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))
|
|
||||||
incorrectStringBooleanError(tok, tok->str());
|
incorrectStringBooleanError(tok, tok->str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4503,6 +4503,11 @@ void stdstring()
|
||||||
|
|
||||||
// valid
|
// valid
|
||||||
s.assign("a");
|
s.assign("a");
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_starts_ends_with
|
||||||
|
// cppcheck-suppress ignoredReturnValue
|
||||||
|
s.starts_with("abc");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void stdvector()
|
void stdvector()
|
||||||
|
|
|
@ -1808,6 +1808,12 @@ private:
|
||||||
" std::cout << p->msg;\n"
|
" std::cout << p->msg;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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
|
void negativeMemoryAllocationSizeError() { // #389
|
||||||
|
|
|
@ -735,7 +735,9 @@ private:
|
||||||
" if('\\0'){}\n"
|
" if('\\0'){}\n"
|
||||||
" if(L'\\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"
|
check("void f() {\n"
|
||||||
" if('\\0' || cond){}\n"
|
" if('\\0' || cond){}\n"
|
||||||
|
@ -750,6 +752,22 @@ private:
|
||||||
" f(\"abc\");\n"
|
" f(\"abc\");\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (warning) Conversion of string literal \"abc\" to bool always evaluates to true.\n", errout.str());
|
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() {
|
void deadStrcmp() {
|
||||||
|
|
Loading…
Reference in New Issue