From c8667096e0d8feaf761ad94c169b18e5611e9722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 14 Aug 2016 10:49:48 +0200 Subject: [PATCH] Fixed #7658 (False positive: Same iterator is used with different containers) --- lib/checkstl.cpp | 67 ++++++++++++++++++++++++++++-------------------- lib/checkstl.h | 2 ++ test/teststl.cpp | 9 +++++++ 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 0058909cc..db813a659 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -72,6 +72,41 @@ static const Token *skipMembers(const Token *tok) return tok; } +bool CheckStl::isIterator(const Variable *var) const +{ + + // Check that its an iterator + if (!var || !var->isLocal() || !Token::Match(var->typeEndToken(), "iterator|const_iterator|reverse_iterator|const_reverse_iterator|auto")) + return false; + + if (var->typeEndToken()->str() == "auto") { + if (Token::Match(var->typeEndToken(), "auto %name% ; %name% = %var% . %name% ( )")) { + const Token* containertok = var->typeEndToken()->tokAt(5); + if (!containertok->variable()) + return false; + + const Library::Container* container = _settings->library.detectContainer(containertok->variable()->typeStartToken()); + if (!container) + return false; + + Library::Container::Yield yield = container->getYield(containertok->strAt(2)); + if (yield != Library::Container::END_ITERATOR && yield != Library::Container::START_ITERATOR && yield != Library::Container::ITERATOR) + return false; + } else + return false; + } + + if (var->type()) { // If it is defined, ensure that it is defined like an iterator + // look for operator* and operator++ + const Function* end = var->type()->getFunction("operator*"); + const Function* incOperator = var->type()->getFunction("operator++"); + if (!end || end->argCount() > 0 || !incOperator) + return false; + } + + return true; +} + void CheckStl::iterators() { const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); @@ -79,35 +114,9 @@ void CheckStl::iterators() for (unsigned int iteratorId = 1; iteratorId < symbolDatabase->getVariableListSize(); iteratorId++) { const Variable* var = symbolDatabase->getVariableFromVarId(iteratorId); - // Check that its an iterator - if (!var || !var->isLocal() || !Token::Match(var->typeEndToken(), "iterator|const_iterator|reverse_iterator|const_reverse_iterator|auto")) + if (!isIterator(var)) continue; - if (var->typeEndToken()->str() == "auto") { - if (Token::Match(var->typeEndToken(), "auto %name% ; %name% = %var% . %name% ( )")) { - const Token* containertok = var->typeEndToken()->tokAt(5); - if (!containertok->variable()) - continue; - - const Library::Container* container = _settings->library.detectContainer(containertok->variable()->typeStartToken()); - if (!container) - continue; - - Library::Container::Yield yield = container->getYield(containertok->strAt(2)); - if (yield != Library::Container::END_ITERATOR && yield != Library::Container::START_ITERATOR && yield != Library::Container::ITERATOR) - continue; - } else - continue; - } - - if (var->type()) { // If it is defined, ensure that it is defined like an iterator - // look for operator* and operator++ - const Function* end = var->type()->getFunction("operator*"); - const Function* incOperator = var->type()->getFunction("operator++"); - if (!end || end->argCount() > 0 || !incOperator) - continue; - } - // the validIterator flag says if the iterator has a valid value or not bool validIterator = Token::Match(var->nameToken()->next(), "[(=:]"); const Scope* invalidationScope = 0; @@ -173,11 +182,13 @@ void CheckStl::iterators() while (par2->str() != ")") { if (par2->varId() == container->declarationId()) break; + if (isIterator(par2->variable())) + break; // TODO: check if iterator points at same container if (par2->str() == "(") par2 = par2->link(); par2 = par2->next(); } - if (par2->varId() == container->declarationId()) + if (par2->str() != ")") continue; } diff --git a/lib/checkstl.h b/lib/checkstl.h index 9d35a305f..b887c092a 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -151,6 +151,8 @@ public: void readingEmptyStlContainer(); private: + bool isIterator(const Variable *var) const; + void readingEmptyStlContainer_parseUsage(const Token* tok, const Library::Container* container, std::map& empty, bool noerror); void missingComparisonError(const Token *incrementToken1, const Token *incrementToken2); diff --git a/test/teststl.cpp b/test/teststl.cpp index a87111212..1e03305f8 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -210,6 +210,15 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + check("void foo() {\n" // #7658 + " list l1;\n" + " list l2;\n" + " list::iterator it = l1.begin();\n" + " list::iterator end = l1.end();\n" + " l2.insert(it, end);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + // only warn for insert when there are preciself 2 arguments. check("void foo() {\n" " list l1;\n"