From 6cb3a79a647ede9dbaa6692f6e15b3bfa308539c Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Wed, 3 Aug 2022 12:04:44 -0500 Subject: [PATCH] Fix 11147: FP invalidContainer with substr() (#4333) * Fix 11147: FP invalidContainer with substr() * Format --- lib/checkstl.cpp | 19 ++++++++++++++++--- test/teststl.cpp | 12 ++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index bb1be7156..d54b71928 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1068,6 +1068,21 @@ static const ValueFlow::Value* getInnerLifetime(const Token* tok, return nullptr; } +static const Token* endOfExpression(const Token* tok) +{ + if (!tok) + return nullptr; + const Token* parent = tok->astParent(); + while (Token::simpleMatch(parent, ".")) + parent = parent->astParent(); + if (!parent) + return tok->next(); + const Token* endToken = nextAfterAstRightmostLeaf(parent); + if (!endToken) + return parent->next(); + return endToken; +} + void CheckStl::invalidContainer() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -1120,9 +1135,7 @@ void CheckStl::invalidContainer() } if (Token::Match(assignExpr, "%assign%") && Token::Match(assignExpr->astOperand1(), "%var%")) skipVarIds.insert(assignExpr->astOperand1()->varId()); - const Token* endToken = nextAfterAstRightmostLeaf(tok->next()->astParent()); - if (!endToken) - endToken = tok->next(); + const Token* endToken = endOfExpression(tok); const ValueFlow::Value* v = nullptr; ErrorPath errorPath; PathAnalysis::Info info = diff --git a/test/teststl.cpp b/test/teststl.cpp index d7ea7f62f..e279d8e85 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -5465,6 +5465,18 @@ private: "}\n", true); ASSERT_EQUALS("", errout.str()); + + // #11147 + check("void f(std::string& s) {\n" + " if (!s.empty()) {\n" + " std::string::iterator it = s.begin();\n" + " s = s.substr(it - s.begin());\n" + " }\n" + "}\n", + true); + ASSERT_EQUALS( + "[test.cpp:4]: (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()); } void invalidContainerLoop() {