Fixed #7658 (False positive: Same iterator is used with different containers)

This commit is contained in:
Daniel Marjamäki 2016-08-14 10:49:48 +02:00
parent 73e1378af8
commit c8667096e0
3 changed files with 50 additions and 28 deletions

View File

@ -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;
}

View File

@ -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<unsigned int, const Library::Container*>& empty, bool noerror);
void missingComparisonError(const Token *incrementToken1, const Token *incrementToken2);

View File

@ -210,6 +210,15 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
check("void foo() {\n" // #7658
" list<int> l1;\n"
" list<int> l2;\n"
" list<int>::iterator it = l1.begin();\n"
" list<int>::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<int> l1;\n"