diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index a7ed835c0..793523c24 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -2175,6 +2175,10 @@ void CheckStl::uselessCalls() uselessCallsEmptyError(tok->next()); else if (Token::Match(tok, "[{};] std :: remove|remove_if|unique (") && tok->tokAt(5)->nextArgument()) uselessCallsRemoveError(tok->next(), tok->strAt(3)); + else if (printPerformance && Token::Match(tok, "%var% = { %var% . begin ( ) ,") && + tok->valueType() && tok->valueType()->type == ValueType::CONTAINER && tok->varId() == tok->tokAt(3)->varId()) { + uselessCallsConstructorError(tok); + } } } } @@ -2223,6 +2227,12 @@ void CheckStl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type) reportError(tok, Severity::performance, "uselessCallsSubstr", msg, CWE398, Certainty::normal); } +void CheckStl::uselessCallsConstructorError(const Token *tok) +{ + const std::string msg = "Inefficient constructor call: container '" + tok->str() + "' is assigned a partial copy of itself. Use erase() or resize() instead."; + reportError(tok, Severity::performance, "uselessCallsConstructor", msg, CWE398, Certainty::normal); +} + void CheckStl::uselessCallsEmptyError(const Token *tok) { reportError(tok, Severity::warning, "uselessCallsEmpty", "Ineffective call of function 'empty()'. Did you intend to call 'clear()' instead?", CWE398, Certainty::normal); diff --git a/lib/checkstl.h b/lib/checkstl.h index dd450fb2e..11e38e649 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -224,6 +224,7 @@ private: void uselessCallsSubstrError(const Token* tok, SubstrErrorType type); void uselessCallsEmptyError(const Token* tok); void uselessCallsRemoveError(const Token* tok, const std::string& function); + void uselessCallsConstructorError(const Token* tok); void dereferenceInvalidIteratorError(const Token* deref, const std::string& iterName); void dereferenceInvalidIteratorError(const Token* tok, const ValueFlow::Value *value, bool inconclusive); diff --git a/test/teststl.cpp b/test/teststl.cpp index 8656824ba..2ac0aa57e 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -4183,6 +4183,36 @@ private: "}\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()); + + check("std::string f(std::string s, std::size_t end) {\n" + " s = { s.begin(), s.begin() + end };\n" + " return s;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (performance) Inefficient constructor call: container 's' is assigned a partial copy of itself. Use erase() or resize() instead.\n", + errout.str()); + + check("std::list f(std::list l, std::size_t end) {\n" + " l = { l.begin(), l.begin() + end };\n" + " return l;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (performance) Inefficient constructor call: container 'l' is assigned a partial copy of itself. Use erase() or resize() instead.\n", + errout.str()); + + check("std::string f(std::string s, std::size_t end) {\n" + " s = std::string{ s.begin(), s.begin() + end };\n" + " return s;\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (performance) Inefficient constructor call: container 's' is assigned a partial copy of itself. Use erase() or resize() instead.\n", + "", + errout.str()); + + check("std::string f(std::string s, std::size_t end) {\n" + " s = std::string(s.begin(), s.begin() + end);\n" + " return s;\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (performance) Inefficient constructor call: container 's' is assigned a partial copy of itself. Use erase() or resize() instead.\n", + "", + errout.str()); } void stabilityOfChecks() {