Store functions which are declared but not implemented in the function list of the containing scope -> Fixed #3679

Refactorizations:
- Simplified some code
- Improved condition in findVariableType to reduce unnecessary comparisions of empty strings.
This commit is contained in:
PKEuS 2012-03-23 17:59:51 +01:00
parent d04698df13
commit e938235385
5 changed files with 96 additions and 39 deletions

View File

@ -2074,7 +2074,7 @@ void CheckOther::checkConstantFunctionParameter()
const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
if (i->type == Scope::eFunction && i->function) {
if (i->type == Scope::eFunction && i->function && i->function->arg) {
for (const Token* tok = i->function->arg->next(); tok; tok = tok->nextArgument()) {
// TODO: False negatives. This pattern only checks for string.
// Investigate if there are other classes in the std
@ -2850,13 +2850,13 @@ namespace {
typedef std::map<std::string, std::list<Function> > StringFunctionMap;
StringFunctionMap functionsByName;
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
StringFunctionMap::iterator it = functionsByName.find(func->token->str());
StringFunctionMap::iterator it = functionsByName.find(func->tokenDef->str());
Scope *currScope = const_cast<Scope*>(&*scope);
if (it == functionsByName.end()) {
std::list<Function> tmp;
tmp.push_back(*func);
tmp.back().functionScope = currScope;
functionsByName[func->token->str()] = tmp;
functionsByName[func->tokenDef->str()] = tmp;
} else {
it->second.push_back(*func);
it->second.back().functionScope = currScope;

View File

@ -1080,18 +1080,18 @@ void CheckStl::string_c_str()
std::multimap<std::string, unsigned int> c_strFuncParam;
if (_settings->isEnabled("performance")) {
for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
if (scope->type == Scope::eFunction && scope->function) {
if (c_strFuncParam.erase(scope->className) != 0) { // Check if function with this name was already found
c_strFuncParam.insert(std::make_pair(scope->className, 0)); // Disable, because there are overloads. TODO: Handle overloads
for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
if (c_strFuncParam.erase(func->tokenDef->str()) != 0) { // Check if function with this name was already found
c_strFuncParam.insert(std::make_pair(func->tokenDef->str(), 0)); // Disable, because there are overloads. TODO: Handle overloads
continue;
}
unsigned int numpar = 0;
c_strFuncParam.insert(std::make_pair(scope->className, numpar)); // Insert function as dummy, to indicate that there is at least one function with that name
for (const Token* tok = scope->function->arg->next(); tok != 0; tok = tok->nextArgument()) {
c_strFuncParam.insert(std::make_pair(func->tokenDef->str(), numpar)); // Insert function as dummy, to indicate that there is at least one function with that name
for (const Token* tok = func->argDef->next(); tok != 0; tok = tok->nextArgument()) {
numpar++;
if (Token::Match(tok, "std :: string !!&") || Token::simpleMatch(tok, "const std :: string"))
c_strFuncParam.insert(std::make_pair(scope->className, numpar));
c_strFuncParam.insert(std::make_pair(func->tokenDef->str(), numpar));
}
}
}

View File

@ -423,7 +423,15 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// function prototype
else if (Token::simpleMatch(argStart->link(), ") ;")) {
/** @todo save function prototypes in database someday */
bool newFunc = true; // Is this function already in the database?
for (std::list<Function>::const_iterator i = scope->functionList.begin(); i != scope->functionList.end(); ++i) {
if (i->tokenDef->str() == tok->str() && argsMatch(scope, i->argDef, argStart, "", 0))
newFunc = false;
}
// save function prototype in database
if (newFunc)
addGlobalFunctionDecl(scope, tok, argStart, funcStart);
tok = argStart->link()->next();
continue;
}
@ -431,7 +439,17 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// function returning function pointer prototype
else if (Token::simpleMatch(argStart->link(), ") ) (") &&
Token::simpleMatch(argStart->link()->linkAt(2), ") ;")) {
/** @todo save function prototypes in database someday */
bool newFunc = true; // Is this function already in the database?
for (std::list<Function>::const_iterator i = scope->functionList.begin(); i != scope->functionList.end(); ++i) {
if (i->tokenDef->str() == tok->str() && argsMatch(scope, i->argDef, argStart, "", 0))
newFunc = false;
}
// save function prototype in database
if (newFunc) {
Function* func = addGlobalFunctionDecl(scope, tok, argStart, funcStart);
func->retFuncPtr = true;
}
tok = argStart->link()->linkAt(2)->next();
continue;
}
@ -565,19 +583,15 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// fill in variable info
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
scope = &(*it);
// find variables
scope->getVariableList();
it->getVariableList();
}
// fill in function arguments
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
scope = &(*it);
std::list<Function>::iterator func;
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
for (func = it->functionList.begin(); func != it->functionList.end(); ++func) {
// add arguments
func->addArguments(this, &*func, scope);
}
@ -882,6 +896,30 @@ bool SymbolDatabase::argsMatch(const Scope *scope, const Token *first, const Tok
}
Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart)
{
Function* function = 0;
for (std::list<Function>::iterator i = scope->functionList.begin(); i != scope->functionList.end(); ++i) {
if (i->tokenDef->str() == tok->str() && argsMatch(scope, i->argDef, argStart, "", 0))
function = &*i;
}
if (!function)
function = addGlobalFunctionDecl(scope, tok, argStart, funcStart);
function->arg = argStart;
function->token = funcStart;
function->hasBody = true;
Scope* old_scope = scope;
addNewFunction(&scope, &tok);
if (scope) {
scope->function = &old_scope->functionList.back();
return function;
}
return 0;
}
Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart)
{
Function function;
@ -893,11 +931,9 @@ Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, co
// save the function name location
function.tokenDef = funcStart;
function.token = funcStart;
function.isInline = false;
function.hasBody = true;
function.arg = function.argDef;
function.hasBody = false;
function.type = Function::eFunction;
// find start of function '{'
@ -908,15 +944,8 @@ Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, co
// save start of function
function.start = start;
Scope* old_scope = scope;
addNewFunction(&scope, &tok);
if (scope) {
old_scope->functionList.push_back(function);
scope->function = &old_scope->functionList.back();
return scope->function;
}
return 0;
scope->functionList.push_back(function);
return &scope->functionList.back();
}
void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart)
@ -1370,8 +1399,10 @@ void SymbolDatabase::printOut(const char *title) const
std::cout << " retFuncPtr: " << (func->retFuncPtr ? "true" : "false") << std::endl;
std::cout << " tokenDef: " << _tokenizer->fileLine(func->tokenDef) << std::endl;
std::cout << " argDef: " << _tokenizer->fileLine(func->argDef) << std::endl;
if (func->hasBody) {
std::cout << " token: " << _tokenizer->fileLine(func->token) << std::endl;
std::cout << " arg: " << _tokenizer->fileLine(func->arg) << std::endl;
}
std::cout << " functionScope: ";
if (func->functionScope) {
std::cout << func->functionScope->className << " "
@ -1494,7 +1525,7 @@ unsigned int Function::initializedArgCount() const
void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function *func, const Scope *scope)
{
// check for non-empty argument list "( ... )"
if (arg->link() != arg->next() && !Token::simpleMatch(arg, "( void )")) {
if (arg && arg->link() != arg->next() && !Token::simpleMatch(arg, "( void )")) {
unsigned int count = 0;
for (const Token* tok = arg->next(); tok; tok = tok->next()) {
@ -1800,20 +1831,19 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
}
// Is it const..?
bool isConst = false;
if (tok->str() == "const") {
bool isConst(tok->str() == "const");
if (isConst) {
tok = tok->next();
isConst = true;
}
// Is it a static variable?
const bool isStatic(Token::simpleMatch(tok, "static"));
const bool isStatic(tok->str() == "static");
if (isStatic) {
tok = tok->next();
}
// Is it a mutable variable?
const bool isMutable(Token::simpleMatch(tok, "mutable"));
const bool isMutable(tok->str() == "mutable");
if (isMutable) {
tok = tok->next();
}
@ -1977,8 +2007,8 @@ const Scope *SymbolDatabase::findVariableType(const Scope *start, const Token *t
std::list<Scope>::const_iterator scope;
for (scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
// skip namespaces and functions
if (scope->type == Scope::eNamespace || scope->type == Scope::eFunction || scope->type == Scope::eGlobal)
// skip namespaces, functions, ...
if (scope->type != Scope::eClass && scope->type != Scope::eStruct && scope->type != Scope::eUnion)
continue;
// do the names match?

View File

@ -590,6 +590,7 @@ private:
friend class Scope;
void addClassFunction(Scope **info, const Token **tok, const Token *argStart);
Function* addGlobalFunctionDecl(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart);
Function* addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart);
void addNewFunction(Scope **info, const Token **tok);
const Token *initBaseInfo(Scope *info, const Token *tok);

View File

@ -112,6 +112,7 @@ private:
TEST_CASE(hasInlineClassFunctionReturningFunctionPointer);
TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer);
TEST_CASE(hasClassFunctionReturningFunctionPointer);
TEST_CASE(functionDeclarations);
TEST_CASE(classWithFriend);
@ -633,6 +634,31 @@ private:
}
}
void functionDeclarations() {
GET_SYMBOL_DB("void foo();\nvoid foo();\nint foo(int i);\nvoid foo() {}")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("foo"));
if (db) {
const Scope *scope = &db->scopeList.front();
ASSERT(scope && scope->functionList.size() == 2);
const Function *foo = &scope->functionList.front();
const Function *foo_int = &scope->functionList.back();
ASSERT(foo && foo->token->str() == "foo");
ASSERT(foo && foo->hasBody);
ASSERT(foo && foo->token->strAt(2) == ")");
ASSERT(foo_int && !foo_int->token);
ASSERT(foo_int && foo_int->tokenDef->str() == "foo");
ASSERT(foo_int && !foo_int->hasBody);
ASSERT(foo_int && foo_int->tokenDef->strAt(2) == "int");
}
}
void classWithFriend() {
GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };")
// 3 scopes: Global, 3 classes