From e9382353854f972d95830a74c7633f29129fb33d Mon Sep 17 00:00:00 2001 From: PKEuS Date: Fri, 23 Mar 2012 17:59:51 +0100 Subject: [PATCH] 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. --- lib/checkother.cpp | 6 +-- lib/checkstl.cpp | 12 ++--- lib/symboldatabase.cpp | 90 ++++++++++++++++++++++++------------- lib/symboldatabase.h | 1 + test/testsymboldatabase.cpp | 26 +++++++++++ 5 files changed, 96 insertions(+), 39 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 7455a90ef..9889d8688 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2074,7 +2074,7 @@ void CheckOther::checkConstantFunctionParameter() const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase(); for (std::list::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 > 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); if (it == functionsByName.end()) { std::list 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; diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index d1749520e..029369c11 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1080,18 +1080,18 @@ void CheckStl::string_c_str() std::multimap c_strFuncParam; if (_settings->isEnabled("performance")) { for (std::list::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::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)); } } } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 603b758fc..ce6515c53 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -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::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::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::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::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; - std::cout << " token: " << _tokenizer->fileLine(func->token) << std::endl; - std::cout << " arg: " << _tokenizer->fileLine(func->arg) << 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::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? diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 2e22942ce..f14542fbc 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -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); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 5a9c9a9a3..5f33f3f2c 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -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