Fixed #4352: Ensure that class provides an iterator interface.

This commit is contained in:
PKEuS 2013-03-14 09:00:22 -07:00
parent 0b22cb932e
commit 641ac5c02a
5 changed files with 61 additions and 1 deletions

View File

@ -67,9 +67,17 @@ void CheckStl::iterators()
const Variable* var = symbolDatabase->getVariableFromVarId(iteratorId);
// Check that its an iterator
if (!var || !var->isLocal() || !Token::Match(var->nameToken()->previous(), "iterator|const_iterator|reverse_iterator|const_reverse_iterator"))
if (!var || !var->isLocal() || !Token::Match(var->typeEndToken(), "iterator|const_iterator|reverse_iterator|const_reverse_iterator"))
continue;
if (var->type()) { // If it is defined, ensure that it is defined like an iterator
// look for operator* and operator++
const Function* end = var->type()->getFunction("operator*");
const Function* incOperator = var->type()->getFunction("operator++");
if (!end || end->argCount() > 0 || !incOperator)
continue;
}
// the validIterator flag says if the iterator has a valid value or not
bool validIterator = Token::Match(var->nameToken()->next(), "[(=]");
const Scope* invalidationScope = 0;

View File

@ -1456,6 +1456,24 @@ void SymbolDatabase::debugMessage(const Token *tok, const std::string &msg) cons
}
}
const Function* Type::getFunction(const std::string& funcName) const
{
if (classScope) {
for (std::list<Function>::const_iterator i = classScope->functionList.begin(); i != classScope->functionList.end(); ++i)
if (i->name() == funcName)
return &*i;
}
for (std::size_t i = 0; i < derivedFrom.size(); i++) {
if (derivedFrom[i].type) {
const Function* func = derivedFrom[i].type->getFunction(funcName);
if (func)
return func;
}
}
return 0;
}
bool Variable::arrayDimensions(std::vector<Dimension> &dimensions, const Token *tok)
{
bool isArray = false;

View File

@ -95,6 +95,8 @@ public:
}
const Token *initBaseInfo(const Token *tok, const Token *tok1);
const Function* getFunction(const std::string& funcName) const;
};
/** @brief Information about a member variable. */

View File

@ -93,6 +93,7 @@ private:
TEST_CASE(stlBoundaries2);
TEST_CASE(stlBoundaries3);
TEST_CASE(stlBoundaries4); // #4364
TEST_CASE(stlBoundaries5); // #4352
// if (str.find("ab"))
TEST_CASE(if_find);
@ -1329,6 +1330,26 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (error) Dangerous iterator comparison using operator< on 'std::forward_list'.\n", errout.str());
}
void stlBoundaries5() {
check("class iterator { int foo(); };\n"
"int foo() {\n"
" iterator i;\n"
" return i.foo();;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("class iterator {\n"
" Class operator*();\n"
" iterator& operator++();\n"
" int foo();\n"
"};\n"
"int foo() {\n"
" iterator i;\n"
" return i.foo();;\n"
"}");
ASSERT_EQUALS("[test.cpp:8]: (error) Invalid iterator 'i' used.\n", errout.str());
}
void if_find() {
// ---------------------------

View File

@ -576,6 +576,8 @@ private:
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
ASSERT(function && function->hasBody && function->isInline);
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("func") == function);
}
}
@ -1434,6 +1436,15 @@ private:
ASSERT(Bar_Sub && Bar_Sub->classScope && Bar_Sub->classScope->numConstructors == 2 && Bar_Sub->classScope->className == "Sub");
}
void symboldatabase32() {
GET_SYMBOL_DB("struct Base {\n"
" void foo() {}\n"
"};\n"
"class Deri : Base {\n"
"};");
ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->definedType->getFunction("foo"));
}
void isImplicitlyVirtual() {
{
GET_SYMBOL_DB("class Base {\n"