Detect more instances of c_str() misuse (#4392)

* Fix #7515 New check: Not needed c_str() operation

* Comment

* Detect more instances of c_str() misuse

* Fix bad merge

* Check for data() also

* Fix

* Format

* Format
This commit is contained in:
chrchr-github 2022-08-22 14:06:10 +02:00 committed by GitHub
parent f81fc1129b
commit 66fca7ba91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 12 deletions

View File

@ -1936,6 +1936,14 @@ void CheckStl::string_c_str()
}
}
auto isString = [](const Token* str) -> bool {
if (Token::Match(str, "(|[") && !(str->valueType() && str->valueType()->type == ValueType::ITERATOR))
str = str->previous();
return str && ((str->variable() && str->variable()->isStlStringType()) || // variable
(str->function() && isStlStringType(str->function()->retDef)) || // function returning string
(str->valueType() && str->valueType()->type == ValueType::ITERATOR && isStlStringType(str->valueType()->containerTypeToken))); // iterator pointing to string
};
// Try to detect common problems when using string::c_str()
for (const Scope &scope : symbolDatabase->scopeList) {
if (scope.type != Scope::eFunction || !scope.function)
@ -1991,16 +1999,13 @@ void CheckStl::string_c_str()
else
break;
if (tok2 && Token::Match(tok2->tokAt(-4), ". c_str|data ( )")) {
const Variable* var = tok2->tokAt(-5)->variable();
if (var && (var->isStlStringType() ||
(var->valueType() && var->valueType()->type == ValueType::ITERATOR && isStlStringType(var->valueType()->containerTypeToken)))) {
if (isString(tok2->tokAt(-4)->astOperand1())) {
string_c_strParam(tok, i->second);
} else if (Token::Match(tok2->tokAt(-9), "%name% . str ( )")) { // Check ss.str().c_str() as parameter
const Variable* ssVar = tok2->tokAt(-9)->variable();
if (ssVar && ssVar->isStlType(stl_string_stream))
string_c_strParam(tok, i->second);
}
}
}
} else if (printPerformance && Token::Match(tok, "%var% (|{ %var% . c_str|data ( )") &&
@ -2010,13 +2015,9 @@ void CheckStl::string_c_str()
((Token::Match(tok->previous(), "%var% + %var% . c_str|data ( )") && tok->previous()->variable() && tok->previous()->variable()->isStlStringType()) ||
(Token::Match(tok->tokAt(-5), "%var% . c_str|data ( ) + %var%") && tok->tokAt(-5)->variable() && tok->tokAt(-5)->variable()->isStlStringType()))) {
string_c_strConcat(tok);
} else if (printPerformance && Token::simpleMatch(tok, "<<") && tok->astOperand2() && Token::simpleMatch(tok->astOperand2()->astOperand1(), ". c_str ( )")) {
} else if (printPerformance && Token::simpleMatch(tok, "<<") && tok->astOperand2() && Token::Match(tok->astOperand2()->astOperand1(), ". c_str|data ( )")) {
const Token* str = tok->astOperand2()->astOperand1()->astOperand1();
if (Token::Match(str, "(|[") && !(str->valueType() && str->valueType()->type == ValueType::ITERATOR))
str = str->previous();
if (str && ((str->variable() && str->variable()->isStlStringType()) ||
(str->function() && isStlStringType(str->function()->retDef)) ||
(str->valueType() && str->valueType()->type == ValueType::ITERATOR && isStlStringType(str->valueType()->containerTypeToken)))) {
if (isString(str)) {
const Token* strm = tok;
while (Token::simpleMatch(strm, "<<"))
strm = strm->astOperand1();

View File

@ -3895,11 +3895,21 @@ private:
errout.str());
check("void f(const std::string& s);\n" // #8336
"void g(const std::vector<std::string>& v) {\n"
"struct T {\n"
" std::string g();\n"
" std::string a[1];\n"
"};\n"
"void g(const std::vector<std::string>& v, T& t) {\n"
" for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it)\n"
" f(it->c_str());\n"
" f(v.begin()->c_str());\n"
" f(t.g().c_str());\n"
" f(t.a[0].c_str());\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n",
ASSERT_EQUALS("[test.cpp:8]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n"
"[test.cpp:9]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n"
"[test.cpp:10]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n"
"[test.cpp:11]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n",
errout.str());
check("void svgFile(const std::string &content, const std::string &fileName, const double end = 1000., const double start = 0.);\n"