diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 8f025b6b7..317ad3161 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -46,6 +46,11 @@ void CheckStl::dereferenceErasedError(const Token *tok, const std::string &itern reportError(tok, Severity::error, "eraseDereference", "Dereferenced iterator '" + itername + "' has been erased"); } +void CheckStl::eraseByValueError(const Token *tok, const std::string &containername, const std::string &itername) +{ + reportError(tok, Severity::error, "eraseByValue", "Iterator '" + itername + "' becomes invalid when deleted by value from '" + containername + "'"); +} + void CheckStl::iterators() { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) @@ -111,6 +116,10 @@ void CheckStl::iterators() dereferenceErasedError(tok2, tok2->strAt(0)); tok2 = tok2->tokAt(2); } + else if (Token::Match(tok2, "%var% . erase ( * %varid%", iteratorId) && tok2->varId() == containerId) + { + eraseByValueError(tok2, tok2->strAt(0), tok2->strAt(5)); + } } } } diff --git a/lib/checkstl.h b/lib/checkstl.h index b1a1e32c1..2de554d6c 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -124,6 +124,7 @@ private: void stlBoundriesError(const Token *tok, const std::string &container_name); void if_findError(const Token *tok, bool str); void sizeError(const Token *tok); + void eraseByValueError(const Token *tok, const std::string &containername, const std::string &itername); void getErrorMessages() { @@ -139,6 +140,7 @@ private: if_findError(0, false); if_findError(0, true); sizeError(0); + eraseByValueError(0, "container", "iterator"); } std::string name() const diff --git a/test/teststl.cpp b/test/teststl.cpp index 9b09b52be..4a051b1b7 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -56,6 +56,7 @@ private: TEST_CASE(eraseGoto); TEST_CASE(eraseAssign); TEST_CASE(eraseErase); + TEST_CASE(eraseByValue); TEST_CASE(pushback1); TEST_CASE(pushback2); @@ -475,6 +476,18 @@ private: ASSERT_EQUALS("[test.cpp:6]: (error) Invalid iterator: iter\n", errout.str()); } + void eraseByValue() + { + check("void f()\n" + "{\n" + " std::set foo;\n" + " for (std::set it = foo.begin(); it != foo.end(); ++it)\n" + " {\n" + " foo.erase(*it);\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) Iterator 'it' becomes invalid when deleted by value from 'foo'\n", errout.str()); + } void pushback1()