speed up checks by caching commonly looked up stuff in the symbol database (checkother, checkstl, checkunusedvar). Ticket: #4266
This commit is contained in:
parent
a2febc49d6
commit
6b8e83a181
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
502
lib/checkstl.cpp
502
lib/checkstl.cpp
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue