Skip to content

Commit 1778977

Browse files
Fix #11547 FN stlcstrParam with std::string_view (#5093)
* Fix #11547 FN stlcstrParam with std::string_view * Add suppression * Use emplace()
1 parent 6b9fac4 commit 1778977

5 files changed

Lines changed: 33 additions & 15 deletions

File tree

lib/checkstl.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,15 +1899,19 @@ void CheckStl::string_c_str()
18991899
const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
19001900

19011901
// Find all functions that take std::string as argument
1902-
std::multimap<const Function*, int> c_strFuncParam;
1902+
struct StrArg {
1903+
nonneg int n; // cppcheck-suppress unusedStructMember // FP used through iterator/pair
1904+
std::string argtype; // cppcheck-suppress unusedStructMember
1905+
};
1906+
std::multimap<const Function*, StrArg> c_strFuncParam;
19031907
if (printPerformance) {
19041908
for (const Scope &scope : symbolDatabase->scopeList) {
19051909
for (const Function &func : scope.functionList) {
1906-
int numpar = 0;
1910+
nonneg int numpar = 0;
19071911
for (const Variable &var : func.argumentList) {
19081912
numpar++;
1909-
if (var.isStlStringType() && (!var.isReference() || var.isConst()))
1910-
c_strFuncParam.insert(std::make_pair(&func, numpar));
1913+
if ((var.isStlStringType() || var.isStlStringViewType()) && (!var.isReference() || var.isConst()))
1914+
c_strFuncParam.emplace(&func, StrArg{ numpar, var.getTypeName() });
19111915
}
19121916
}
19131917
}
@@ -1959,32 +1963,32 @@ void CheckStl::string_c_str()
19591963
string_c_strAssignment(tok);
19601964
}
19611965
} else if (printPerformance && tok->function() && Token::Match(tok, "%name% ( !!)") && tok->str() != scope.className) {
1962-
const std::pair<std::multimap<const Function*, int>::const_iterator, std::multimap<const Function*, int>::const_iterator> range = c_strFuncParam.equal_range(tok->function());
1963-
for (std::multimap<const Function*, int>::const_iterator i = range.first; i != range.second; ++i) {
1964-
if (i->second == 0)
1966+
const auto range = c_strFuncParam.equal_range(tok->function());
1967+
for (std::multimap<const Function*, StrArg>::const_iterator i = range.first; i != range.second; ++i) {
1968+
if (i->second.n == 0)
19651969
continue;
19661970

19671971
const Token* tok2 = tok->tokAt(2);
19681972
int j;
1969-
for (j = 0; tok2 && j < i->second-1; j++)
1973+
for (j = 0; tok2 && j < i->second.n - 1; j++)
19701974
tok2 = tok2->nextArgument();
19711975
if (tok2)
19721976
tok2 = tok2->nextArgument();
19731977
else
19741978
break;
1975-
if (!tok2 && j == i->second-1)
1979+
if (!tok2 && j == i->second.n - 1)
19761980
tok2 = tok->next()->link();
19771981
else if (tok2)
19781982
tok2 = tok2->previous();
19791983
else
19801984
break;
19811985
if (tok2 && Token::Match(tok2->tokAt(-4), ". c_str|data ( )")) {
19821986
if (isString(tok2->tokAt(-4)->astOperand1())) {
1983-
string_c_strParam(tok, i->second);
1987+
string_c_strParam(tok, i->second.n, i->second.argtype);
19841988
} else if (Token::Match(tok2->tokAt(-9), "%name% . str ( )")) { // Check ss.str().c_str() as parameter
19851989
const Variable* ssVar = tok2->tokAt(-9)->variable();
19861990
if (ssVar && ssVar->isStlType(stl_string_stream))
1987-
string_c_strParam(tok, i->second);
1991+
string_c_strParam(tok, i->second.n, i->second.argtype);
19881992
}
19891993
}
19901994
}
@@ -2103,11 +2107,11 @@ void CheckStl::string_c_strReturn(const Token* tok)
21032107
"The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly returning the string.", CWE704, Certainty::normal);
21042108
}
21052109

2106-
void CheckStl::string_c_strParam(const Token* tok, nonneg int number)
2110+
void CheckStl::string_c_strParam(const Token* tok, nonneg int number, const std::string& argtype)
21072111
{
21082112
std::ostringstream oss;
2109-
oss << "Passing the result of c_str() to a function that takes std::string as argument no. " << number << " is slow and redundant.\n"
2110-
"The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly passing the string.";
2113+
oss << "Passing the result of c_str() to a function that takes " << argtype << " as argument no. " << number << " is slow and redundant.\n"
2114+
"The conversion from const char* as returned by c_str() to " << argtype << " creates an unnecessary string copy or length calculation. Solve that by directly passing the string.";
21112115
reportError(tok, Severity::performance, "stlcstrParam", oss.str(), CWE704, Certainty::normal);
21122116
}
21132117

lib/checkstl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class CPPCHECKLIB CheckStl : public Check {
192192
void string_c_strThrowError(const Token* tok);
193193
void string_c_strError(const Token* tok);
194194
void string_c_strReturn(const Token* tok);
195-
void string_c_strParam(const Token* tok, nonneg int number);
195+
void string_c_strParam(const Token* tok, nonneg int number, const std::string& argtype = "std::string");
196196
void string_c_strConstructor(const Token* tok);
197197
void string_c_strAssignment(const Token* tok);
198198
void string_c_strConcat(const Token* tok);

lib/symboldatabase.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,6 +2335,11 @@ const Type* Variable::iteratorType() const
23352335
return nullptr;
23362336
}
23372337

2338+
bool Variable::isStlStringViewType() const
2339+
{
2340+
return getFlag(fIsStlType) && valueType() && valueType()->container && valueType()->container->stdStringLike && valueType()->container->view;
2341+
}
2342+
23382343
std::string Variable::getTypeName() const
23392344
{
23402345
std::string ret;

lib/symboldatabase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,8 @@ class CPPCHECKLIB Variable {
594594
return getFlag(fIsStlString);
595595
}
596596

597+
bool isStlStringViewType() const;
598+
597599
bool isSmartPointer() const {
598600
return getFlag(fIsSmartPointer);
599601
}

test/teststl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4195,6 +4195,13 @@ class TestStl : public TestFixture {
41954195
ASSERT_EQUALS("[test.cpp:6]: (performance) Assigning the result of c_str() to a std::string is slow and redundant.\n"
41964196
"[test.cpp:8]: (performance) Assigning the result of c_str() to a std::string is slow and redundant.\n",
41974197
errout.str());
4198+
4199+
check("void f(std::string_view);\n" // #11547
4200+
"void g(const std::string & s) {\n"
4201+
" f(s.c_str());\n"
4202+
"}\n");
4203+
ASSERT_EQUALS("[test.cpp:3]: (performance) Passing the result of c_str() to a function that takes std::string_view as argument no. 1 is slow and redundant.\n",
4204+
errout.str());
41984205
}
41994206

42004207
void uselessCalls() {

0 commit comments

Comments
 (0)