Fixed #6217, refactorized CheckStl::if_find(): allow all comparison operators, use AST, fixed wrong unit tests

This commit is contained in:
PKEuS 2015-01-03 11:06:44 +01:00
parent c8bb19567b
commit 8885ac3eba
2 changed files with 40 additions and 49 deletions

View File

@ -739,27 +739,15 @@ void CheckStl::stlBoundariesError(const Token *tok, const std::string &container
"One should use operator!= instead to compare iterators.");
}
static bool if_findCompare(const Token * const tokBack, bool str)
static bool if_findCompare(const Token * const tokBack)
{
const Token *tok = tokBack;
while (tok && tok->str() == ")") {
tok = tok->next();
if (Token::Match(tok, ") !!{") &&
tok->link()->previous() &&
(Token::Match(tok->link()->previous(),",|==|!=") ||
tok->link()->previous()->isName()))
return true;
}
if (Token::Match(tok,",|==|!="))
const Token *tok = tokBack->astParent();
if (!tok)
return false;
if (tok->isComparisonOp())
return true;
if (tok) {
if (str && tok->isComparisonOp())
return true;
if (tok->isArithmeticalOp()) // result is used in some calculation
return true; // TODO: check if there is a comparison of the result somewhere
}
if (tok->isArithmeticalOp()) // result is used in some calculation
return true; // TODO: check if there is a comparison of the result somewhere
return false;
}
@ -781,48 +769,30 @@ void CheckStl::if_find()
tok = tok->next();
for (const Token* const end = tok->link(); tok != end; tok = (tok == end) ? end : tok->next()) {
if (Token::Match(tok, "&&|(|%oror%"))
tok = tok->next();
else
continue;
while (tok->str() == "(")
tok = tok->next();
if (tok->str() == "!")
tok = tok->next();
if (Token::Match(tok, "%var% . find (")) {
const Variable *var = tok->variable();
if (var) {
const bool isString = var->isStlStringType() && !var->isArrayOrPointer();
if (if_findCompare(tok->linkAt(3), isString))
if (if_findCompare(tok->tokAt(3)))
continue;
// Is the variable a std::string or STL container?
const Token * decl = var->typeStartToken();
const unsigned int varid = tok->varId();
// stl container
if (warning && Token::Match(decl, "std :: %var% < %type% > &| %varid%", varid))
if (warning && Token::Match(decl, "std :: %var% <") && Token::Match(decl->linkAt(3), "> !!::"))
if_findError(tok, false);
else if (performance && isString)
else if (performance && var->isStlStringType())
if_findError(tok, true);
}
}
//check also for vector-like or pointer containers
else if (Token::Match(tok, "* %var%") || Token::Match(tok, "%var% [")) {
// goto %var%
if (tok->str() == "*")
tok = tok->next();
else if (tok->variable() && tok->astParent() && (tok->astParent()->str() == "*" || tok->astParent()->str() == "[")) {
const Token *tok2 = tok->astParent();
const Token *tok2 = tok->next();
if (tok2->str() == "[")
tok2 = tok2->link()->next();
if (!Token::simpleMatch(tok2, ". find ("))
if (!Token::simpleMatch(tok2->astParent(), ". find ("))
continue;
if (if_findCompare(tok2->linkAt(2), false))
if (if_findCompare(tok2->astParent()->tokAt(2)))
continue;
const Variable *var = tok->variable();
@ -866,7 +836,7 @@ void CheckStl::if_find()
else if (warning && Token::Match(tok, "std :: find|find_if (")) {
// check that result is checked properly
if (!if_findCompare(tok->linkAt(3), false)) {
if (!if_findCompare(tok->tokAt(3))) {
if_findError(tok, false);
}
}

View File

@ -1458,7 +1458,14 @@ private:
// error (pointer)
check("void f(std::set<int> *s)\n"
"{\n"
" if (*s.find(12)) { }\n"
" if ((*s).find(12)) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Suspicious condition. The result of find() is an iterator, but it is not properly checked.\n", errout.str());
// error (pointer)
check("void f(std::set<int> *s)\n"
"{\n"
" if (s->find(12)) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Suspicious condition. The result of find() is an iterator, but it is not properly checked.\n", errout.str());
@ -1500,7 +1507,7 @@ private:
// ok (pointer)
check("void f(std::set<int> *s)\n"
"{\n"
" if (*s.find(12) != s.end()) { }\n"
" if ((*s).find(12) != s.end()) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
@ -1551,6 +1558,13 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
// ok (less than comparison, #6217)
check("void f(std::vector<int> s)\n"
"{\n"
" if (std::find(a, b, c) < d) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
// #3714 - segmentation fault for syntax error
check("void f() {\n"
" if (()) { }\n"
@ -1574,7 +1588,14 @@ private:
// error (pointer)
check("void f(const std::string *s)\n"
"{\n"
" if (*s.find(\"abc\")) { }\n"
" if ((*s).find(\"abc\")) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::compare() would be faster.\n", errout.str());
// error (pointer)
check("void f(const std::string *s)\n"
"{\n"
" if (s->find(\"abc\")) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::compare() would be faster.\n", errout.str());