Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions lib/checkstl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2156,15 +2156,18 @@ void CheckStl::uselessCalls()
if (!var || !var->isStlType())
continue;
uselessCallsSwapError(tok, tok->str());
} else if (printPerformance && Token::Match(tok, "%var% . substr (") &&
tok->variable() && tok->variable()->isStlStringType()) {
if (Token::Match(tok->tokAt(4), "0| )")) {
uselessCallsSubstrError(tok, false);
} else if (tok->strAt(4) == "0" && tok->linkAt(3)->strAt(-1) == "npos") {
if (!tok->linkAt(3)->previous()->variable()) // Make sure that its no variable
uselessCallsSubstrError(tok, false);
} else if (Token::simpleMatch(tok->linkAt(3)->tokAt(-2), ", 0 )"))
uselessCallsSubstrError(tok, true);
} else if (printPerformance && Token::Match(tok, "%var% . substr (") && tok->variable() && tok->variable()->isStlStringType()) {
const Token* funcTok = tok->tokAt(3);
const std::vector<const Token*> args = getArguments(funcTok);
if (Token::Match(tok->tokAt(-2), "%var% =") && tok->varId() == tok->tokAt(-2)->varId() &&
!args.empty() && args[0]->hasKnownIntValue() && args[0]->getKnownIntValue() == 0) {
uselessCallsSubstrError(tok, Token::simpleMatch(funcTok->astParent(), "=") ? SubstrErrorType::PREFIX : SubstrErrorType::PREFIX_CONCAT);
} else if (args.empty() || (args[0]->hasKnownIntValue() && args[0]->getKnownIntValue() == 0 &&
(args.size() == 1 || (args.size() == 2 && tok->linkAt(3)->strAt(-1) == "npos" && !tok->linkAt(3)->previous()->variable())))) {
uselessCallsSubstrError(tok, SubstrErrorType::COPY);
} else if (args.size() == 2 && args[1]->hasKnownIntValue() && args[1]->getKnownIntValue() == 0) {
uselessCallsSubstrError(tok, SubstrErrorType::EMPTY);
}
} else if (printWarning && Token::Match(tok, "[{};] %var% . empty ( ) ;") &&
!tok->tokAt(4)->astParent() &&
tok->next()->variable() && tok->next()->variable()->isStlType(stl_containers_with_empty_and_clear))
Expand Down Expand Up @@ -2199,12 +2202,24 @@ void CheckStl::uselessCallsSwapError(const Token *tok, const std::string &varnam
"code is inefficient. Is the object or the parameter wrong here?", CWE628, Certainty::normal);
}

void CheckStl::uselessCallsSubstrError(const Token *tok, bool empty)
{
if (empty)
reportError(tok, Severity::performance, "uselessCallsSubstr", "Ineffective call of function 'substr' because it returns an empty string.", CWE398, Certainty::normal);
else
reportError(tok, Severity::performance, "uselessCallsSubstr", "Ineffective call of function 'substr' because it returns a copy of the object. Use operator= instead.", CWE398, Certainty::normal);
void CheckStl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type)
{
std::string msg = "Ineffective call of function 'substr' because ";
switch (type) {
case SubstrErrorType::EMPTY:
msg += "it returns an empty string.";
break;
case SubstrErrorType::COPY:
msg += "it returns a copy of the object. Use operator= instead.";
break;
case SubstrErrorType::PREFIX:
msg += "a prefix of the string is assigned to itself. Use resize() or pop_back() instead.";
break;
case SubstrErrorType::PREFIX_CONCAT:
msg += "a prefix of the string is assigned to itself. Use replace() instead.";
break;
}
reportError(tok, Severity::performance, "uselessCallsSubstr", msg, CWE398, Certainty::normal);
}

void CheckStl::uselessCallsEmptyError(const Token *tok)
Expand Down
5 changes: 3 additions & 2 deletions lib/checkstl.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ class CPPCHECKLIB CheckStl : public Check {

void uselessCallsReturnValueError(const Token* tok, const std::string& varname, const std::string& function);
void uselessCallsSwapError(const Token* tok, const std::string& varname);
void uselessCallsSubstrError(const Token* tok, bool empty);
enum class SubstrErrorType { EMPTY, COPY, PREFIX, PREFIX_CONCAT };
void uselessCallsSubstrError(const Token* tok, SubstrErrorType type);
void uselessCallsEmptyError(const Token* tok);
void uselessCallsRemoveError(const Token* tok, const std::string& function);

Expand Down Expand Up @@ -266,7 +267,7 @@ class CPPCHECKLIB CheckStl : public Check {
c.redundantIfRemoveError(nullptr);
c.uselessCallsReturnValueError(nullptr, "str", "find");
c.uselessCallsSwapError(nullptr, "str");
c.uselessCallsSubstrError(nullptr, false);
c.uselessCallsSubstrError(nullptr, SubstrErrorType::COPY);
c.uselessCallsEmptyError(nullptr);
c.uselessCallsRemoveError(nullptr, "remove");
c.dereferenceInvalidIteratorError(nullptr, "i");
Expand Down
2 changes: 1 addition & 1 deletion lib/checkstring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void CheckString::stringLiteralWriteError(const Token *tok, const Token *strValu
std::string s = strValue->str();
// 20 is an arbitrary value, the max string length shown in a warning message
if (s.size() > 20U)
s = s.substr(0,17) + "..\"";
s.replace(17, std::string::npos, "..\"");
errmsg += " " + s;
}
errmsg += " directly or indirectly is undefined behaviour.";
Expand Down
2 changes: 1 addition & 1 deletion lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ static std::string executeAddon(const AddonInfo &addonInfo,
std::string message("Failed to execute addon (command: '" + pythonExe + " " + args + "'). Exitcode is nonzero.");
if (result.size() > 2) {
message = message + "\n" + message + "\nOutput:\n" + result;
message = message.substr(0,message.find_last_not_of("\n\r"));
message.resize(message.find_last_not_of("\n\r"));
}
throw InternalError(nullptr, message);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/errorlogger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ std::string replaceStr(std::string s, const std::string &from, const std::string
pos1++;
continue;
}
s = s.substr(0,pos1) + to + s.substr(pos2);
s.replace(pos1, from.size(), to);
pos1 += to.size();
}
return s;
Expand Down
4 changes: 2 additions & 2 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static bool simplifyPathWithVariables(std::string &s, std::map<std::string, std:
variables[var] = std::string(envValue);
it1 = variables.find(var);
}
s = s.substr(0, start) + it1->second + s.substr(end + 1);
s.replace(start, end - start + 1, it1->second);
}
if (s.find("$(") != std::string::npos)
return false;
Expand Down Expand Up @@ -644,7 +644,7 @@ static void importPropertyGroup(const tinyxml2::XMLElement *node, std::map<std::
std::string path(text);
const std::string::size_type pos = path.find("$(IncludePath)");
if (pos != std::string::npos)
path = path.substr(0,pos) + *includePath + path.substr(pos+14U);
path.replace(pos, 14U, *includePath);
*includePath = path;
}
}
Expand Down
3 changes: 2 additions & 1 deletion lib/token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,8 @@ Token* Token::insertToken(const std::string& tokenStr, const std::string& origin
nextScopeNameAddition.append(nameTok->str());
nextScopeNameAddition.append(" ");
}
if (nextScopeNameAddition.length() > 0) nextScopeNameAddition = nextScopeNameAddition.substr(0, nextScopeNameAddition.length() - 1);
if (!nextScopeNameAddition.empty())
nextScopeNameAddition.pop_back();
}
}

Expand Down
12 changes: 6 additions & 6 deletions lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2190,7 +2190,7 @@ namespace {
while (!newScope1.empty()) {
std::string::size_type separator = newScope1.rfind(" :: ", index - 1);
if (separator != std::string::npos)
newScope1 = newScope1.substr(0, separator);
newScope1.resize(separator);
else
newScope1.clear();

Expand Down Expand Up @@ -3352,8 +3352,8 @@ void Tokenizer::calculateScopes()
usingNamespaceName += namespaceNameToken->str();
usingNamespaceName += " ";
}
if (usingNamespaceName.length() > 0)
usingNamespaceName = usingNamespaceName.substr(0, usingNamespaceName.length() - 1);
if (!usingNamespaceName.empty())
usingNamespaceName.pop_back();
tok->scopeInfo()->usingNamespaces.insert(usingNamespaceName);
} else if (Token::Match(tok, "namespace|class|struct|union %name% {|::|:|<")) {
for (Token* nameTok = tok->next(); nameTok && !Token::Match(nameTok, "{|:"); nameTok = nameTok->next()) {
Expand All @@ -3364,8 +3364,8 @@ void Tokenizer::calculateScopes()
nextScopeNameAddition.append(nameTok->str());
nextScopeNameAddition.append(" ");
}
if (nextScopeNameAddition.length() > 0)
nextScopeNameAddition = nextScopeNameAddition.substr(0, nextScopeNameAddition.length() - 1);
if (!nextScopeNameAddition.empty())
nextScopeNameAddition.pop_back();
}

if (Token::simpleMatch(tok, "{")) {
Expand Down Expand Up @@ -8106,7 +8106,7 @@ std::string Tokenizer::simplifyString(const std::string &source)
sz++;
std::istringstream istr(str.substr(i+1, sz-1));
istr >> std::oct >> c;
str = str.substr(0,i) + (char)c + str.substr(i+sz);
str = str.replace(i, sz, std::string(1U, (char)c));
continue;
}

Expand Down
15 changes: 15 additions & 0 deletions test/teststl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4161,6 +4161,21 @@ class TestStl : public TestFixture {
" for (;s.empty();) {}\n"
"}");
ASSERT_EQUALS("", errout.str());

// #11166
check("std::string f(std::string s) {\n"
" s = s.substr(0, s.size() - 1);\n"
" return s;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (performance) Ineffective call of function 'substr' because a prefix of the string is assigned to itself. Use resize() or pop_back() instead.\n",
errout.str());

check("std::string f(std::string s, std::size_t start, std::size_t end, const std::string& i) {\n"
" s = s.substr(0, start) + i + s.substr(end + 1);\n"
" return s;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (performance) Ineffective call of function 'substr' because a prefix of the string is assigned to itself. Use replace() instead.\n",
errout.str());
}

void stabilityOfChecks() {
Expand Down