diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 882f4588eeb..65bf3792615 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1989,6 +1989,23 @@ static bool isc_strConcat(const Token* tok) return false; } +static bool isc_strInPlusChain(const Token* tok, const Library::Container* container) +{ + if (!tok || !tok->valueType() || !tok->valueType()->pointer) + return false; + bool result = false; + visitAstNodes(tok, [&](const Token* tok2) { + if (Token::simpleMatch(tok2, "+")) + return ChildrenToVisit::op1_and_op2; + if (isc_strCall(tok2, container)) { + result = true; + return ChildrenToVisit::done; + } + return ChildrenToVisit::none; + }); + return result; +} + static bool isc_strAssignment(const Token* tok) { if (!Token::simpleMatch(tok, "=")) @@ -2003,7 +2020,7 @@ static bool isc_strConstructor(const Token* tok) { if (!tok->valueType() || !Token::Match(tok, "%var% (|{")) return false; - return isc_strCall(tok->tokAt(1)->astOperand2(), tok->valueType()->container); + return isc_strInPlusChain(tok->tokAt(1)->astOperand2(), tok->valueType()->container); } namespace { diff --git a/test/teststl.cpp b/test/teststl.cpp index 2c88f17dd14..29cd85f5759 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -4719,6 +4719,13 @@ class TestStl : public TestFixture { " auto a = + s.c_str();\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("std::string f(const std::string& a) {\n" // #14600 + " std::string b(a.c_str() + 1 + 2);\n" + " return b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:17]: (performance) Constructing a std::string from the result of c_str() is slow and redundant. [stlcstrConstructor]\n", + errout_str()); } void uselessCalls() {