CheckStl: Added comments

This commit is contained in:
Daniel Marjamäki 2010-12-30 22:36:25 +01:00
parent d005245188
commit c7f2ddf63c
1 changed files with 43 additions and 0 deletions

View File

@ -47,35 +47,54 @@ void CheckStl::dereferenceErasedError(const Token *tok, const std::string &itern
void CheckStl::iterators() void CheckStl::iterators()
{ {
// Using same iterator against different containers.
// for (it = foo.begin(); it != bar.end(); ++it)
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{ {
// Locate an iterator..
if (!Token::Match(tok, "%var% = %var% . begin ( ) ;|+")) if (!Token::Match(tok, "%var% = %var% . begin ( ) ;|+"))
continue; continue;
// Get variable ids for both the iterator and container
const unsigned int iteratorId(tok->varId()); const unsigned int iteratorId(tok->varId());
const unsigned int containerId(tok->tokAt(2)->varId()); const unsigned int containerId(tok->tokAt(2)->varId());
if (iteratorId == 0 || containerId == 0) if (iteratorId == 0 || containerId == 0)
continue; continue;
// the validIterator flag says if the iterator has a valid value or not
bool validIterator = true; bool validIterator = true;
// counter for { and }
unsigned int indent = 0; unsigned int indent = 0;
// Scan through the rest of the code and see if the iterator is
// used against other containers.
for (const Token *tok2 = tok->tokAt(7); tok2; tok2 = tok2->next()) for (const Token *tok2 = tok->tokAt(7); tok2; tok2 = tok2->next())
{ {
// If a { is found then count it and continue
if (tok2->str() == "{" && ++indent) if (tok2->str() == "{" && ++indent)
continue; continue;
// If a } is found then count it. break if indentlevel becomes 0.
if (tok2->str() == "}" && --indent == 0) if (tok2->str() == "}" && --indent == 0)
break; break;
// Is iterator compared against different container?
if (Token::Match(tok2, "%varid% != %var% . end ( )", iteratorId) && tok2->tokAt(2)->varId() != containerId) if (Token::Match(tok2, "%varid% != %var% . end ( )", iteratorId) && tok2->tokAt(2)->varId() != containerId)
{ {
iteratorsError(tok2, tok->strAt(2), tok2->strAt(2)); iteratorsError(tok2, tok->strAt(2), tok2->strAt(2));
tok2 = tok2->tokAt(6); tok2 = tok2->tokAt(6);
} }
// Is the iterator used in a insert/erase operation?
else if (Token::Match(tok2, "%var% . insert|erase ( %varid% )|,", iteratorId)) else if (Token::Match(tok2, "%var% . insert|erase ( %varid% )|,", iteratorId))
{ {
// It is bad to insert/erase an invalid iterator
if (!validIterator) if (!validIterator)
invalidIteratorError(tok2, tok2->strAt(4)); invalidIteratorError(tok2, tok2->strAt(4));
// If insert/erase is used on different container then
// report an error
if (tok2->varId() != containerId && tok2->tokAt(5)->str() != ".") if (tok2->varId() != containerId && tok2->tokAt(5)->str() != ".")
{ {
// skip error message if container is a set.. // skip error message if container is a set..
@ -91,23 +110,40 @@ void CheckStl::iterators()
// Show error message, mismatching iterator is used. // Show error message, mismatching iterator is used.
iteratorsError(tok2, tok->strAt(2), tok2->str()); iteratorsError(tok2, tok->strAt(2), tok2->str());
} }
// invalidate the iterator if it is erased
else if (tok2->strAt(2) == std::string("erase")) else if (tok2->strAt(2) == std::string("erase"))
validIterator = false; validIterator = false;
// skip the operation
tok2 = tok2->tokAt(4); tok2 = tok2->tokAt(4);
} }
// it = foo.erase(..
// taking the result of an erase is ok
else if (Token::Match(tok2, "%varid% = %var% . erase (", iteratorId)) else if (Token::Match(tok2, "%varid% = %var% . erase (", iteratorId))
{ {
// the returned iterator is valid
validIterator = true; validIterator = true;
// skip the operation
tok2 = tok2->tokAt(5)->link(); tok2 = tok2->tokAt(5)->link();
if (!tok2) if (!tok2)
break; break;
} }
// Reassign the iterator
else if (Token::Match(tok2, "%varid% = %var% ;", iteratorId)) else if (Token::Match(tok2, "%varid% = %var% ;", iteratorId))
{ {
// Assume that the iterator becomes valid.
// TODO: is it valid?
validIterator = true; validIterator = true;
// skip ahead
tok2 = tok2->tokAt(2); tok2 = tok2->tokAt(2);
} }
// Dereferencing invalid iterator?
else if (!validIterator && Token::Match(tok2, "* %varid%", iteratorId)) else if (!validIterator && Token::Match(tok2, "* %varid%", iteratorId))
{ {
dereferenceErasedError(tok2, tok2->strAt(1)); dereferenceErasedError(tok2, tok2->strAt(1));
@ -122,10 +158,16 @@ void CheckStl::iterators()
{ {
// eraseByValueError(tok2, tok2->strAt(0), tok2->strAt(5)); // eraseByValueError(tok2, tok2->strAt(0), tok2->strAt(5));
} }
// bailout handling. Assume that the iterator becomes valid if we see return/break.
// TODO: better handling
else if (Token::Match(tok2, "return|break ;")) else if (Token::Match(tok2, "return|break ;"))
{ {
validIterator = true; validIterator = true;
} }
// bailout handling. Assume that the iterator becomes valid if we see else.
// TODO: better handling
else if (tok2->str() == "else") else if (tok2->str() == "else")
{ {
validIterator = true; validIterator = true;
@ -143,6 +185,7 @@ void CheckStl::mismatchingContainersError(const Token *tok)
void CheckStl::mismatchingContainers() void CheckStl::mismatchingContainers()
{ {
// Check if different containers are used in various calls of standard functions
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{ {
if (tok->str() != "std") if (tok->str() != "std")