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:
parent
d04698df13
commit
e938235385
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
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<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?
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue