void CheckStl::pushback() { // Pointer can become invalid after push_back or push_front.. for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (Token::Match(tok, "%var% = & %var% [")) { const unsigned int pointerId(tok->varId()); const unsigned int containerId(tok->tokAt(3)->varId()); if (pointerId == 0 || containerId == 0) continue; int indent = 0; bool invalidPointer = false; for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) { if (tok2->str() == "{" || tok2->str() == "(") ++indent; else if (tok2->str() == "}" || tok2->str() == ")") { if (indent == 0 && Token::simpleMatch(tok2, ") {")) tok2 = tok2->next(); else --indent; } // push_back on vector.. if (Token::Match(tok2, "%varid% . push_front|push_back", containerId)) invalidPointer = true; // Using invalid pointer.. if (invalidPointer && tok2->varId() == pointerId) { if (tok2->previous()->str() == "*") invalidPointerError(tok2, tok2->str()); else if (tok2->next()->str() == ".") invalidPointerError(tok2, tok2->str()); break; } } } } // Iterator becomes invalid after push_back or push_front.. for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (!Token::simpleMatch(tok, "vector <")) continue; // if iterator declaration inside for() loop bool iteratorDeclaredInsideLoop = false; if ((tok->tokAt(-2) && Token::simpleMatch(tok->tokAt(-2), "for (")) || (tok->tokAt(-4) && Token::simpleMatch(tok->tokAt(-4), "for ( std ::"))) { iteratorDeclaredInsideLoop = true; } while (tok && tok->str() != ">") tok = tok->next(); if (!tok) break; if (!Token::Match(tok, "> :: iterator|const_iterator %var% =|;")) continue; const unsigned int iteratorid(tok->tokAt(3)->varId()); if (iteratorid == 0) continue; if (iteratorDeclaredInsideLoop && tok->tokAt(4)->str() == "=") { // skip "> :: iterator|const_iterator" tok = tok->tokAt(3); } unsigned int vectorid = 0; int indent = 0; std::string invalidIterator; for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) { if (tok2->str() == "{" || tok2->str() == "(") ++indent; else if (tok2->str() == "}" || tok2->str() == ")") { if (indent == 0 && Token::simpleMatch(tok2, ") {")) tok2 = tok2->next(); else --indent; } // Using push_back or push_front inside a loop.. if (Token::Match(tok2, "for (")) { tok2 = tok2->tokAt(2); } if (Token::Match(tok2, "%varid% = %var% . begin ( ) ; %varid% != %var% . end ( ) ; ++| %varid% ++| ) {", iteratorid)) { const unsigned int vectorid(tok2->tokAt(2)->varId()); if (vectorid == 0) continue; const Token *pushback = 0; unsigned int indent3 = 0; for (const Token *tok3 = tok2->tokAt(20); tok3; tok3 = tok3->next()) { if (tok3->str() == "{") ++indent3; else if (tok3->str() == "}") { if (indent3 <= 1) break; --indent3; } else if (tok3->str() == "break") { pushback = 0; break; } else if (Token::Match(tok3, "%varid% . push_front|push_back|insert (", vectorid)) { pushback = tok3->tokAt(2); } } if (pushback) invalidIteratorError(pushback, pushback->str(), tok2->strAt(0)); } // Assigning iterator.. if (Token::Match(tok2, "%varid% =", iteratorid)) { if (Token::Match(tok2->tokAt(2), "%var% . begin|end|rbegin|rend ( )")) { vectorid = tok2->tokAt(2)->varId(); tok2 = tok2->tokAt(6); } else { vectorid = 0; } invalidIterator = ""; } // push_back on vector.. if (vectorid > 0 && Token::Match(tok2, "%varid% . push_front|push_back|insert (", vectorid)) { if (!invalidIterator.empty() && Token::Match(tok2->tokAt(2), "insert ( %varid% ,", iteratorid)) { invalidIteratorError(tok2, invalidIterator, tok2->strAt(4)); break; } invalidIterator = tok2->strAt(2); if (!iteratorDeclaredInsideLoop) { tok2 = tok2->tokAt(3)->link(); if (!tok2) break; } } // Using invalid iterator.. if (!invalidIterator.empty()) { if (Token::Match(tok2, "++|--|*|+|-|(|,|=|!= %varid%", iteratorid)) invalidIteratorError(tok2, invalidIterator, tok2->strAt(1)); if (Token::Match(tok2, "%varid% ++|--|+|-", iteratorid)) invalidIteratorError(tok2, invalidIterator, tok2->str()); } } } }
void CheckStl::iterators() { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (!Token::Match(tok, "%var% = %var% . begin ( ) ;|+")) continue; const unsigned int iteratorId(tok->varId()); const unsigned int containerId(tok->tokAt(2)->varId()); if (iteratorId == 0 || containerId == 0) continue; bool validIterator = true; unsigned int indent = 0; for (const Token *tok2 = tok->tokAt(7); tok2; tok2 = tok2->next()) { if (tok2->str() == "{" && ++indent) continue; if (tok2->str() == "}" && --indent == 0) break; if (Token::Match(tok2, "%varid% != %var% . end ( )", iteratorId) && tok2->tokAt(2)->varId() != containerId) { iteratorsError(tok2, tok->strAt(2), tok2->strAt(2)); tok2 = tok2->tokAt(6); } else if (Token::Match(tok2, "%var% . insert|erase ( %varid% )|,", iteratorId)) { if (!validIterator) invalidIteratorError(tok2, tok2->strAt(4)); if (tok2->varId() != containerId && tok2->tokAt(5)->str() != ".") { // skip error message if container is a set.. if (tok2->varId() > 0) { const Token *decltok = Token::findmatch(_tokenizer->tokens(), "%varid%", tok2->varId()); while (decltok && !Token::Match(decltok, "[;{},(]")) decltok = decltok->previous(); if (Token::Match(decltok, "%any% const| std :: set")) continue; // No warning } // Show error message, mismatching iterator is used. iteratorsError(tok2, tok->strAt(2), tok2->str()); } else if (tok2->strAt(2) == std::string("erase")) validIterator = false; tok2 = tok2->tokAt(4); } else if (Token::Match(tok2, "%varid% = %var% . erase (", iteratorId)) { validIterator = true; tok2 = tok2->tokAt(5)->link(); if (!tok2) break; } else if (Token::Match(tok2, "%varid% = %var% ;", iteratorId)) { validIterator = true; tok2 = tok2->tokAt(2); } else if (!validIterator && Token::Match(tok2, "* %varid%", iteratorId)) { dereferenceErasedError(tok2, tok2->strAt(1)); tok2 = tok2->next(); } else if (!validIterator && Token::Match(tok2, "%varid% . %var%", iteratorId)) { 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)); } else if (Token::Match(tok2, "return|break ;")) { validIterator = true; } } } }