speed up checks by caching commonly looked up stuff in the symbol database (checkother, checkstl, checkunusedvar). Ticket: #4266

This commit is contained in:
Robert Reif 2012-11-16 06:50:49 +01:00 committed by Daniel Marjamäki
parent a2febc49d6
commit 6b8e83a181
3 changed files with 316 additions and 278 deletions

View File

@ -3180,26 +3180,29 @@ void CheckOther::checkSuspiciousStringCompare()
return; return;
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (tok->next()->type() != Token::eComparisonOp)
continue;
for (const Token* tok = _tokenizer->list.front(); tok && tok->tokAt(3); tok = tok->next()) { const Token* varTok = tok;
if (tok->next()->type() != Token::eComparisonOp) const Token* litTok = tok->tokAt(2);
continue;
const Token* varTok = tok; if (varTok->strAt(-1) == "+" || litTok->strAt(1) == "+")
const Token* litTok = tok->tokAt(2); continue;
if (varTok->strAt(-1) == "+" || litTok->strAt(1) == "+") if ((varTok->type() == Token::eString || varTok->type() == Token::eVariable) && (litTok->type() == Token::eString || litTok->type() == Token::eVariable) && litTok->type() != varTok->type()) {
continue; if (varTok->type() == Token::eString)
std::swap(varTok, litTok);
if ((varTok->type() == Token::eString || varTok->type() == Token::eVariable) && (litTok->type() == Token::eString || litTok->type() == Token::eVariable) && litTok->type() != varTok->type()) { const Variable* var = symbolDatabase->getVariableFromVarId(varTok->varId());
if (varTok->type() == Token::eString) if (var) {
std::swap(varTok, litTok); if (_tokenizer->isC() ||
(var->isPointer() && varTok->strAt(-1) != "*" && !Token::Match(varTok->next(), "[.([]")))
const Variable* var = symbolDatabase->getVariableFromVarId(varTok->varId()); suspiciousStringCompareError(tok, var->name());
if (var) { }
if (_tokenizer->isC() ||
(var->isPointer() && varTok->strAt(-1) != "*" && !Token::Match(varTok->next(), "[.([]")))
suspiciousStringCompareError(tok, var->name());
} }
} }
} }
@ -3568,15 +3571,20 @@ void CheckOther::checkNegativeBitwiseShift()
{ {
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (const Token *tok = _tokenizer->tokens(); tok ; tok = tok->next()) { const std::size_t functions = symbolDatabase->functionScopes.size();
if ((Token::Match(tok,"%var% >>|<< %num%") || Token::Match(tok,"%num% >>|<< %num%")) && !Token::Match(tok->previous(),">>|<<")) { for (std::size_t i = 0; i < functions; ++i) {
if (tok->isName()) { const Scope * scope = symbolDatabase->functionScopes[i];
const Variable* var = symbolDatabase->getVariableFromVarId(tok->varId()); for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (var && var->typeStartToken()->isStandardType() && (tok->strAt(2))[0] == '-')
negativeBitwiseShiftError(tok); if ((Token::Match(tok,"%var% >>|<< %num%") || Token::Match(tok,"%num% >>|<< %num%")) && !Token::Match(tok->previous(),">>|<<")) {
} else { if (tok->isName()) {
if ((tok->strAt(2))[0] == '-') const Variable* var = symbolDatabase->getVariableFromVarId(tok->varId());
negativeBitwiseShiftError(tok); if (var && var->typeStartToken()->isStandardType() && (tok->strAt(2))[0] == '-')
negativeBitwiseShiftError(tok);
} else {
if ((tok->strAt(2))[0] == '-')
negativeBitwiseShiftError(tok);
}
} }
} }
} }
@ -3599,18 +3607,22 @@ void CheckOther::checkIncompleteArrayFill()
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (const Token* tok = _tokenizer->list.front(); tok; tok = tok->next()) { const std::size_t functions = symbolDatabase->functionScopes.size();
if (Token::Match(tok, "memset|memcpy|memmove ( %var% ,") && Token::Match(tok->linkAt(1)->tokAt(-2), ", %num% )")) { for (std::size_t i = 0; i < functions; ++i) {
const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(2)->varId()); const Scope * scope = symbolDatabase->functionScopes[i];
if (!var || !var->isArray() || var->dimensions().empty() || !var->dimension(0)) for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
continue; if (Token::Match(tok, "memset|memcpy|memmove ( %var% ,") && Token::Match(tok->linkAt(1)->tokAt(-2), ", %num% )")) {
const Variable* var = symbolDatabase->getVariableFromVarId(tok->tokAt(2)->varId());
if (!var || !var->isArray() || var->dimensions().empty() || !var->dimension(0))
continue;
if (MathLib::toLongNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) { if (MathLib::toLongNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) {
unsigned int size = _tokenizer->sizeOfType(var->typeStartToken()); unsigned int size = _tokenizer->sizeOfType(var->typeStartToken());
if ((size != 1 && size != 100 && size != 0) || var->typeEndToken()->str() == "*") if ((size != 1 && size != 100 && size != 0) || var->typeEndToken()->str() == "*")
incompleteArrayFillError(tok, var->name(), tok->str(), false); incompleteArrayFillError(tok, var->name(), tok->str(), false);
else if (var->typeStartToken()->str() == "bool" && _settings->isEnabled("portability")) // sizeof(bool) is not 1 on all platforms else if (var->typeStartToken()->str() == "bool" && _settings->isEnabled("portability")) // sizeof(bool) is not 1 on all platforms
incompleteArrayFillError(tok, var->name(), tok->str(), true); incompleteArrayFillError(tok, var->name(), tok->str(), true);
}
} }
} }
} }

View File

@ -238,35 +238,40 @@ void CheckStl::mismatchingContainers()
static const std::string pattern2 = pattern1x1_1 + pattern1x1_2; static const std::string pattern2 = pattern1x1_1 + pattern1x1_2;
// Check if different containers are used in various calls of standard functions // Check if different containers are used in various calls of standard functions
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
if (!Token::Match(tok, "std :: %type% ( !!)")) const std::size_t functions = symbolDatabase->functionScopes.size();
continue; for (std::size_t ii = 0; ii < functions; ++ii) {
const Token* arg1 = tok->tokAt(4); const Scope * scope = symbolDatabase->functionScopes[ii];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (!Token::Match(tok, "std :: %type% ( !!)"))
continue;
const Token* arg1 = tok->tokAt(4);
// TODO: If iterator variables are used instead then there are false negatives. // TODO: If iterator variables are used instead then there are false negatives.
if (Token::Match(arg1, pattern2.c_str()) && algorithm2.find(tok->strAt(2)) != algorithm2.end()) { if (Token::Match(arg1, pattern2.c_str()) && algorithm2.find(tok->strAt(2)) != algorithm2.end()) {
if (arg1->str() != arg1->strAt(6)) { if (arg1->str() != arg1->strAt(6)) {
mismatchingContainersError(arg1);
}
} else if (algorithm22.find(tok->strAt(2)) != algorithm22.end()) {
if (Token::Match(arg1, pattern2.c_str()) && arg1->str() != arg1->strAt(6))
mismatchingContainersError(arg1);
// Find third parameter
const Token* arg3 = arg1;
for (unsigned int i = 0; i < 2 && arg3; i++)
arg3 = arg3->nextArgument();
if (Token::Match(arg3, pattern2.c_str()) && arg3->str() != arg3->strAt(6))
mismatchingContainersError(arg3);
} else if (Token::Match(arg1, pattern1x1_1.c_str()) && algorithm1x1.find(tok->strAt(2)) != algorithm1x1.end()) {
// Find third parameter
const Token *arg3 = arg1->tokAt(6)->nextArgument();
if (Token::Match(arg3, pattern1x1_2.c_str())) {
if (arg1->str() != arg3->str()) {
mismatchingContainersError(arg1); mismatchingContainersError(arg1);
} }
} else if (algorithm22.find(tok->strAt(2)) != algorithm22.end()) {
if (Token::Match(arg1, pattern2.c_str()) && arg1->str() != arg1->strAt(6))
mismatchingContainersError(arg1);
// Find third parameter
const Token* arg3 = arg1;
for (unsigned int i = 0; i < 2 && arg3; i++)
arg3 = arg3->nextArgument();
if (Token::Match(arg3, pattern2.c_str()) && arg3->str() != arg3->strAt(6))
mismatchingContainersError(arg3);
} else if (Token::Match(arg1, pattern1x1_1.c_str()) && algorithm1x1.find(tok->strAt(2)) != algorithm1x1.end()) {
// Find third parameter
const Token *arg3 = arg1->tokAt(6)->nextArgument();
if (Token::Match(arg3, pattern1x1_2.c_str())) {
if (arg1->str() != arg3->str()) {
mismatchingContainersError(arg1);
}
}
} }
tok = arg1->linkAt(-1);
} }
tok = arg1->linkAt(-1);
} }
} }
@ -275,7 +280,7 @@ void CheckStl::stlOutOfBounds()
{ {
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
// Scan through all tokens.. // Scan through all scopes..
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) { for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
const Token* const tok = i->classDef; const Token* const tok = i->classDef;
// only interested in "for" loops // only interested in "for" loops
@ -511,21 +516,93 @@ void CheckStl::erase()
void CheckStl::pushback() void CheckStl::pushback()
{ {
// Pointer can become invalid after push_back, push_front, reserve or resize.. // Pointer can become invalid after push_back, push_front, reserve or resize..
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
if (Token::Match(tok, "%var% = & %var% [")) { const std::size_t functions = symbolDatabase->functionScopes.size();
// Variable id for pointer for (std::size_t i = 0; i < functions; ++i) {
const unsigned int pointerId(tok->varId()); const Scope * scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (Token::Match(tok, "%var% = & %var% [")) {
// Variable id for pointer
const unsigned int pointerId(tok->varId());
// Variable id for the container variable // Variable id for the container variable
const unsigned int containerId(tok->tokAt(3)->varId()); const unsigned int containerId(tok->tokAt(3)->varId());
if (pointerId == 0 || containerId == 0) if (pointerId == 0 || containerId == 0)
continue;
// Count { , } and parentheses for tok2
int indent = 0;
bool invalidPointer = false;
std::string function;
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|insert|reserve|resize|clear", containerId)) {
invalidPointer = true;
function = tok2->strAt(2);
}
// Using invalid pointer..
if (invalidPointer && tok2->varId() == pointerId) {
if (tok2->previous()->str() == "*")
invalidPointerError(tok2, function, tok2->str());
else if (tok2->next()->str() == ".")
invalidPointerError(tok2, function, tok2->str());
break;
}
}
}
}
}
// Iterator becomes invalid after reserve, resize, insert, push_back or push_front..
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (!Token::simpleMatch(tok, "vector <"))
continue; continue;
// Count { , } and parentheses for tok2 // 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->strAt(4) == "=") {
// skip "> :: iterator|const_iterator"
tok = tok->tokAt(3);
}
// the variable id for the vector
unsigned int vectorid = 0;
// count { , } and parentheses for tok2
int indent = 0; int indent = 0;
bool invalidPointer = false;
std::string function; const Token* validatingToken = 0;
std::string invalidIterator;
for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) { for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) {
if (tok2->str() == "{" || tok2->str() == "(") if (tok2->str() == "{" || tok2->str() == "(")
++indent; ++indent;
@ -536,140 +613,76 @@ void CheckStl::pushback()
--indent; --indent;
} }
// push_back on vector.. if (validatingToken == tok2) {
if (Token::Match(tok2, "%varid% . push_front|push_back|insert|reserve|resize|clear", containerId)) { invalidIterator.clear();
invalidPointer = true; validatingToken = 0;
function = tok2->strAt(2);
} }
// Using invalid pointer.. // Using push_back or push_front inside a loop..
if (invalidPointer && tok2->varId() == pointerId) { if (Token::simpleMatch(tok2, "for (")) {
if (tok2->previous()->str() == "*") tok2 = tok2->tokAt(2);
invalidPointerError(tok2, function, tok2->str()); ++indent;
else if (tok2->next()->str() == ".")
invalidPointerError(tok2, function, tok2->str());
break;
} }
}
}
}
// Iterator becomes invalid after reserve, resize, insert, push_back or push_front.. if (Token::Match(tok2, "%varid% = %var% . begin|rbegin|cbegin|crbegin ( ) ; %varid% != %var% . end|rend|cend|crend ( ) ; ++| %varid% ++| ) {", iteratorid)) {
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { // variable id for the loop iterator
if (!Token::simpleMatch(tok, "vector <")) const unsigned int varId(tok2->tokAt(2)->varId());
continue; if (varId == 0)
continue;
// if iterator declaration inside for() loop const Token *pushbackTok = 0;
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() != ">") // Count { and } for tok3
tok = tok->next(); const Token *tok3 = tok2->tokAt(20);
if (!tok) for (const Token* const end3 = tok3->linkAt(-1); tok3 != end3; tok3 = tok3->next()) {
break; if (tok3->str() == "break" || tok3->str() == "return") {
if (!Token::Match(tok, "> :: iterator|const_iterator %var% =|;")) pushbackTok = 0;
continue; break;
} else if (Token::Match(tok3, "%varid% . push_front|push_back|insert|reserve|resize|clear (", varId)) {
const unsigned int iteratorid(tok->tokAt(3)->varId()); pushbackTok = tok3->tokAt(2);
if (iteratorid == 0) }
continue;
if (iteratorDeclaredInsideLoop && tok->strAt(4) == "=") {
// skip "> :: iterator|const_iterator"
tok = tok->tokAt(3);
}
// the variable id for the vector
unsigned int vectorid = 0;
// count { , } and parentheses for tok2
int indent = 0;
const Token* validatingToken = 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;
}
if (validatingToken == tok2) {
invalidIterator.clear();
validatingToken = 0;
}
// Using push_back or push_front inside a loop..
if (Token::simpleMatch(tok2, "for (")) {
tok2 = tok2->tokAt(2);
++indent;
}
if (Token::Match(tok2, "%varid% = %var% . begin|rbegin|cbegin|crbegin ( ) ; %varid% != %var% . end|rend|cend|crend ( ) ; ++| %varid% ++| ) {", iteratorid)) {
// variable id for the loop iterator
const unsigned int varId(tok2->tokAt(2)->varId());
if (varId == 0)
continue;
const Token *pushbackTok = 0;
// Count { and } for tok3
const Token *tok3 = tok2->tokAt(20);
for (const Token* const end3 = tok3->linkAt(-1); tok3 != end3; tok3 = tok3->next()) {
if (tok3->str() == "break" || tok3->str() == "return") {
pushbackTok = 0;
break;
} else if (Token::Match(tok3, "%varid% . push_front|push_back|insert|reserve|resize|clear (", varId)) {
pushbackTok = tok3->tokAt(2);
} }
if (pushbackTok)
invalidIteratorError(pushbackTok, pushbackTok->str(), tok2->str());
} }
if (pushbackTok) // Assigning iterator..
invalidIteratorError(pushbackTok, pushbackTok->str(), tok2->str()); if (Token::Match(tok2, "%varid% =", iteratorid)) {
} if (Token::Match(tok2->tokAt(2), "%var% . begin|end|rbegin|rend|cbegin|cend|crbegin|crend ( )")) {
vectorid = tok2->tokAt(2)->varId();
// Assigning iterator.. tok2 = tok2->tokAt(6);
if (Token::Match(tok2, "%varid% =", iteratorid)) { } else {
if (Token::Match(tok2->tokAt(2), "%var% . begin|end|rbegin|rend|cbegin|cend|crbegin|crend ( )")) { vectorid = 0;
vectorid = tok2->tokAt(2)->varId(); }
tok2 = tok2->tokAt(6); invalidIterator = "";
} else {
vectorid = 0;
}
invalidIterator = "";
}
// push_back on vector..
if (vectorid > 0 && Token::Match(tok2, "%varid% . push_front|push_back|insert|reserve|resize|clear (", vectorid)) {
if (!invalidIterator.empty() && Token::Match(tok2->tokAt(2), "insert ( %varid% ,", iteratorid)) {
invalidIteratorError(tok2, invalidIterator, tok2->strAt(4));
break;
} }
invalidIterator = tok2->strAt(2); // push_back on vector..
tok2 = tok2->linkAt(3); if (vectorid > 0 && Token::Match(tok2, "%varid% . push_front|push_back|insert|reserve|resize|clear (", vectorid)) {
} if (!invalidIterator.empty() && Token::Match(tok2->tokAt(2), "insert ( %varid% ,", iteratorid)) {
invalidIteratorError(tok2, invalidIterator, tok2->strAt(4));
break;
}
else if (tok2->str() == "return" || tok2->str() == "throw") invalidIterator = tok2->strAt(2);
validatingToken = Token::findsimplematch(tok2->next(), ";"); tok2 = tok2->linkAt(3);
}
// TODO: instead of bail out for 'else' try to check all execution paths. else if (tok2->str() == "return" || tok2->str() == "throw")
else if (tok2->str() == "break" || tok2->str() == "else") validatingToken = Token::findsimplematch(tok2->next(), ";");
invalidIterator.clear();
// Using invalid iterator.. // TODO: instead of bail out for 'else' try to check all execution paths.
if (!invalidIterator.empty()) { else if (tok2->str() == "break" || tok2->str() == "else")
if (Token::Match(tok2, "++|--|*|+|-|(|,|=|!= %varid%", iteratorid)) invalidIterator.clear();
invalidIteratorError(tok2, invalidIterator, tok2->strAt(1));
if (Token::Match(tok2, "%varid% ++|--|+|-|.", iteratorid)) // Using invalid iterator..
invalidIteratorError(tok2, invalidIterator, tok2->str()); 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());
}
} }
} }
} }
@ -697,30 +710,35 @@ void CheckStl::stlBoundries()
// containers (not the vector).. // containers (not the vector)..
static const char STL_CONTAINER_LIST[] = "bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset"; static const char STL_CONTAINER_LIST[] = "bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset";
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
// Declaring iterator.. const std::size_t functions = symbolDatabase->functionScopes.size();
if (tok->str() == "<" && Token::Match(tok->previous(), STL_CONTAINER_LIST)) { for (std::size_t i = 0; i < functions; ++i) {
const std::string& container_name(tok->strAt(-1)); const Scope * scope = symbolDatabase->functionScopes[i];
if (tok->link()) for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
tok = tok->link(); // Declaring iterator..
else if (tok->str() == "<" && Token::Match(tok->previous(), STL_CONTAINER_LIST)) {
while (tok && tok->str() != ">") const std::string& container_name(tok->strAt(-1));
tok = tok->next(); if (tok->link())
if (!tok) tok = tok->link();
break; else
while (tok && tok->str() != ">")
tok = tok->next();
if (!tok)
break;
if (Token::Match(tok, "> :: iterator|const_iterator %var% =|;")) { if (Token::Match(tok, "> :: iterator|const_iterator %var% =|;")) {
const unsigned int iteratorid(tok->tokAt(3)->varId()); const unsigned int iteratorid(tok->tokAt(3)->varId());
if (iteratorid == 0) if (iteratorid == 0)
continue; continue;
// Using "iterator < ..." is not allowed // Using "iterator < ..." is not allowed
const Token* const end = tok->scope()->classEnd; const Token* const end = tok->scope()->classEnd;
for (const Token *tok2 = tok; tok2 != end; tok2 = tok2->next()) { for (const Token *tok2 = tok; tok2 != end; tok2 = tok2->next()) {
if (Token::Match(tok2, "!!* %varid% <", iteratorid)) { if (Token::Match(tok2, "!!* %varid% <", iteratorid)) {
stlBoundriesError(tok2, container_name); stlBoundriesError(tok2, container_name);
} else if (Token::Match(tok2, "> %varid% !!.", iteratorid)) { } else if (Token::Match(tok2, "> %varid% !!.", iteratorid)) {
stlBoundriesError(tok2, container_name); stlBoundriesError(tok2, container_name);
}
} }
} }
} }
@ -916,57 +934,62 @@ void CheckStl::size()
if (!_settings->isEnabled("performance")) if (!_settings->isEnabled("performance"))
return; return;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
if (Token::Match(tok, "%var% . size ( )") || const std::size_t functions = symbolDatabase->functionScopes.size();
Token::Match(tok, "%var% . %var% . size ( )")) { for (std::size_t i = 0; i < functions; ++i) {
const Token *tok1 = tok; const Scope * scope = symbolDatabase->functionScopes[i];
unsigned int varid = 0; for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (Token::Match(tok, "%var% . size ( )") ||
Token::Match(tok, "%var% . %var% . size ( )")) {
const Token *tok1 = tok;
unsigned int varid = 0;
// get the variable id // get the variable id
if (tok->strAt(2) != "size") { if (tok->strAt(2) != "size") {
tok1 = tok1->tokAt(2); tok1 = tok1->tokAt(2);
// found a.b.size(), lookup class/struct variable // found a.b.size(), lookup class/struct variable
const Variable *var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok->varId()); const Variable *var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok->varId());
if (var && var->type()) { if (var && var->type()) {
// get class/struct variable type // get class/struct variable type
const Scope *type = var->type(); const Scope *type = var->type();
// lookup variable member // lookup variable member
std::list<Variable>::const_iterator it; std::list<Variable>::const_iterator it;
for (it = type->varlist.begin(); it != type->varlist.end(); ++it) { for (it = type->varlist.begin(); it != type->varlist.end(); ++it) {
if (it->name() == tok1->str()) { if (it->name() == tok1->str()) {
// found member variable, save varid // found member variable, save varid
varid = it->varId(); varid = it->varId();
break; break;
}
} }
} }
} } else
} else varid = tok1->varId();
varid = tok1->varId();
const Token* const end = tok1->tokAt(5); const Token* const end = tok1->tokAt(5);
if (varid) { if (varid) {
// check for comparison to zero // check for comparison to zero
if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, "==|<=|!=|> 0")) || if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, "==|<=|!=|> 0")) ||
(end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "0 ==|>=|!=|<"))) { (end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "0 ==|>=|!=|<"))) {
if (isStlContainer(varid)) if (isStlContainer(varid))
sizeError(tok1); sizeError(tok1);
} }
// check for comparison to one // check for comparison to one
if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, ">=|< 1")) || if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, ">=|< 1")) ||
(end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "1 <=|>"))) { (end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "1 <=|>"))) {
if (isStlContainer(varid)) if (isStlContainer(varid))
sizeError(tok1); sizeError(tok1);
} }
// check for using as boolean expression // check for using as boolean expression
else if ((Token::Match(tok->tokAt(-2), "if|while (") && end->str() == ")") || else if ((Token::Match(tok->tokAt(-2), "if|while (") && end->str() == ")") ||
(tok->previous()->type() == Token::eLogicalOp && Token::Match(end, "&&|)|,|;|%oror%"))) { (tok->previous()->type() == Token::eLogicalOp && Token::Match(end, "&&|)|,|;|%oror%"))) {
if (isStlContainer(varid)) if (isStlContainer(varid))
sizeError(tok1); sizeError(tok1);
}
} }
} }
} }
@ -1358,26 +1381,29 @@ void CheckStl::uselessCalls()
return; return;
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
const std::size_t functions = symbolDatabase->functionScopes.size();
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { for (std::size_t i = 0; i < functions; ++i) {
if (tok->varId() && Token::Match(tok, "%var% . compare|find|rfind|find_first_not_of|find_first_of|find_last_not_of|find_last_of ( %var% [,)]") && const Scope * scope = symbolDatabase->functionScopes[i];
tok->varId() == tok->tokAt(4)->varId() && style) { for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
uselessCallsReturnValueError(tok->tokAt(4), tok->str(), tok->strAt(2)); if (tok->varId() && Token::Match(tok, "%var% . compare|find|rfind|find_first_not_of|find_first_of|find_last_not_of|find_last_of ( %var% [,)]") &&
} else if (tok->varId() && Token::Match(tok, "%var% . swap ( %var% )") && tok->varId() == tok->tokAt(4)->varId() && style) {
tok->varId() == tok->tokAt(4)->varId() && performance) { uselessCallsReturnValueError(tok->tokAt(4), tok->str(), tok->strAt(2));
uselessCallsSwapError(tok, tok->str()); } else if (tok->varId() && Token::Match(tok, "%var% . swap ( %var% )") &&
} else if (Token::simpleMatch(tok, ". substr (") && performance) { tok->varId() == tok->tokAt(4)->varId() && performance) {
if (Token::Match(tok->tokAt(3), "0| )")) uselessCallsSwapError(tok, tok->str());
uselessCallsSubstrError(tok, false); } else if (Token::simpleMatch(tok, ". substr (") && performance) {
else if (tok->strAt(3) == "0" && tok->linkAt(2)->strAt(-1) == "npos") { if (Token::Match(tok->tokAt(3), "0| )"))
if (!symbolDatabase->getVariableFromVarId(tok->linkAt(2)->previous()->varId())) // Make sure that its no variable
uselessCallsSubstrError(tok, false); uselessCallsSubstrError(tok, false);
} else if (Token::simpleMatch(tok->linkAt(2)->tokAt(-2), ", 0 )")) else if (tok->strAt(3) == "0" && tok->linkAt(2)->strAt(-1) == "npos") {
uselessCallsSubstrError(tok, true); if (!symbolDatabase->getVariableFromVarId(tok->linkAt(2)->previous()->varId())) // Make sure that its no variable
} else if (Token::Match(tok, "[{}:;] %var% . empty ( ) ;") && style) uselessCallsSubstrError(tok, false);
uselessCallsEmptyError(tok->next()); } else if (Token::simpleMatch(tok->linkAt(2)->tokAt(-2), ", 0 )"))
else if (Token::Match(tok, "[{};] std :: remove|remove_if|unique (") && tok->tokAt(5)->nextArgument()) uselessCallsSubstrError(tok, true);
uselessCallsRemoveError(tok->next(), tok->strAt(3)); } else if (Token::Match(tok, "[{}:;] %var% . empty ( ) ;") && style)
uselessCallsEmptyError(tok->next());
else if (Token::Match(tok, "[{};] std :: remove|remove_if|unique (") && tok->tokAt(5)->nextArgument())
uselessCallsRemoveError(tok->next(), tok->strAt(3));
}
} }
} }

View File

@ -968,10 +968,10 @@ void CheckUnusedVar::checkFunctionVariableUsage()
// Parse all executing scopes.. // Parse all executing scopes..
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { // only check functions
// only check functions const std::size_t functions = symbolDatabase->functionScopes.size();
if (scope->type != Scope::eFunction) for (std::size_t i = 0; i < functions; ++i) {
continue; const Scope * scope = symbolDatabase->functionScopes[i];
// varId, usage {read, write, modified} // varId, usage {read, write, modified}
Variables variables; Variables variables;