Replaced Tokenizer::getFunctionTokenByName() by SymbolDatabase::findFunctionByName(), which handles scopes slightly better.

This commit is contained in:
PKEuS 2012-09-11 18:03:47 +02:00
parent 64faa780fe
commit 22a8e3f4e6
12 changed files with 85 additions and 138 deletions

View File

@ -596,44 +596,20 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int p
// Calling a user function?
// only 1-dimensional arrays can be checked currently
else if (arrayInfo.num().size() == 1) {
const Token *ftok = _tokenizer->getFunctionTokenByName(tok.str().c_str());
if (Token::Match(ftok, "%var% (") && Token::Match(ftok->next()->link(), ") const| {")) {
// Get varid for the corresponding parameter..
const Token *ftok2 = ftok->tokAt(2);
for (unsigned int i = 1; i < par; i++)
ftok2 = ftok2->nextArgument();
unsigned int parameterVarId = 0;
for (; ftok2; ftok2 = ftok2->next()) {
if (ftok2->str() == "(")
ftok2 = ftok2->link();
else if (ftok2->str() == "," || ftok2->str() == ")")
break;
else if (Token::Match(ftok2, "%var% ,|)|[")) {
// check type..
const Token *type = ftok2->previous();
while (Token::Match(type, "*|const"))
type = type->previous();
if (type && _tokenizer->sizeOfType(type) == arrayInfo.element_size())
parameterVarId = ftok2->varId();
}
}
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(tok.str(), tok.scope());;
if (func && func->hasBody) {
// Get corresponding parameter..
const Variable* parameter = func->getArgumentVar(par-1);
// No parameterVarId => bail out
if (parameterVarId == 0)
// Ensure that it has a compatible size..
if (!parameter || _tokenizer->sizeOfType(parameter->typeStartToken()) != arrayInfo.element_size())
return;
// Step into the function scope..
ftok = ftok->next()->link();
if (!Token::Match(ftok, ") const| {"))
return;
ftok = Token::findsimplematch(ftok, "{");
ftok = ftok->next();
// Check the parameter usage in the function scope..
for (; ftok; ftok = ftok->next()) {
for (const Token* ftok = func->functionScope->classStart; ftok != func->functionScope->classEnd; ftok = ftok->next()) {
if (Token::Match(ftok, "if|for|while (")) {
// bailout if there is buffer usage..
if (bailoutIfSwitch(ftok, parameterVarId)) {
if (bailoutIfSwitch(ftok, parameter->varId())) {
break;
}
@ -652,7 +628,7 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int p
if (ftok->str() == "}")
break;
if (ftok->varId() == parameterVarId) {
if (ftok->varId() == parameter->varId()) {
if (Token::Match(ftok->previous(), "-- %var%") ||
Token::Match(ftok, "%var% --"))
break;
@ -674,7 +650,7 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int p
// Calling function..
if (Token::Match(ftok, "%var% (")) {
ArrayInfo ai(arrayInfo);
ai.varid(parameterVarId);
ai.varid(parameter->varId());
checkFunctionCall(ftok, ai, callstack);
}
}

View File

@ -119,7 +119,7 @@ bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok, uns
}
//---------------------------------------------------------------------------
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, unsigned int varid, std::list<const Token *> *callstack) const
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, unsigned int varid, std::list<const Function*> *callstack) const
{
// What we may have...
// * var = (char *)malloc(10);
@ -208,20 +208,20 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
}
// User function
const Token *ftok = tokenizer->getFunctionTokenByName(tok2->str().c_str());
if (ftok == NULL)
const Function* func = tokenizer->getSymbolDatabase()->findFunctionByName(tok2->str(), tok2->scope());
if (func == NULL)
return No;
// Prevent recursion
if (callstack && std::find(callstack->begin(), callstack->end(), ftok) != callstack->end())
if (callstack && std::find(callstack->begin(), callstack->end(), func) != callstack->end())
return No;
std::list<const Token *> cs;
std::list<const Function*> cs;
if (!callstack)
callstack = &cs;
callstack->push_back(ftok);
return functionReturnType(ftok, callstack);
callstack->push_back(func);
return functionReturnType(func, callstack);
}
@ -408,35 +408,15 @@ void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &calls
reportErr(callstack, Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
}
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok, std::list<const Token *> *callstack) const
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Function* func, std::list<const Function*> *callstack) const
{
if (!tok)
if (!func || !func->hasBody)
return No;
// Locate start of function
while (tok) {
if (tok->str() == "{" || tok->str() == "}")
return No;
if (tok->str() == "(") {
tok = tok->link();
break;
}
tok = tok->next();
}
// Is this the start of a function?
if (!Token::Match(tok, ") const| {"))
return No;
while (tok->str() != "{")
tok = tok->next();
// Get return pointer..
unsigned int varid = 0;
unsigned int indentlevel = 0;
for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
for (const Token *tok2 = func->functionScope->classStart; tok2 != func->functionScope->classEnd; tok2 = tok2->next()) {
if (tok2->str() == "{")
++indentlevel;
else if (tok2->str() == "}") {
@ -471,7 +451,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok,
// Check if return pointer is allocated..
AllocType allocType = No;
while (NULL != (tok = tok->next())) {
for (const Token* tok = func->functionScope->classStart; tok != func->functionScope->classEnd; tok = tok->next()) {
if (Token::Match(tok, "%varid% =", varid)) {
allocType = getAllocationType(tok->tokAt(2), varid, callstack);
}
@ -656,20 +636,18 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
// lock/unlock..
if (varid == 0) {
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
while (ftok && (ftok->str() != "{"))
ftok = ftok->next();
if (!ftok)
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(funcname, tok->scope());;
if (!func || !func->hasBody)
return 0;
Token *func = getcode(ftok->next(), callstack, 0, alloctype, dealloctype, false, 1);
simplifycode(func);
Token *ftok = getcode(func->functionScope->classStart->next(), callstack, 0, alloctype, dealloctype, false, 1);
simplifycode(ftok);
const char *ret = 0;
if (Token::simpleMatch(func, "; alloc ; }"))
if (Token::simpleMatch(ftok, "; alloc ; }"))
ret = "alloc";
else if (Token::simpleMatch(func, "; dealloc ; }"))
else if (Token::simpleMatch(ftok, "; dealloc ; }"))
ret = "dealloc";
TokenList::deleteTokens(func);
TokenList::deleteTokens(ftok);
return ret;
}
@ -702,16 +680,12 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
if (dot)
return "use";
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
if (!ftok)
const Function* function = _tokenizer->getSymbolDatabase()->findFunctionByName(funcname, tok->scope());;
if (!function)
return "use";
// how many parameters does the function want?
if (numpar != countParameters(ftok))
return "recursive";
const Function* function = _tokenizer->getSymbolDatabase()->findFunctionByToken(ftok);
if (!function)
if (numpar != function->argCount()) // TODO: Handle default parameters
return "recursive";
const Variable* param = function->getArgumentVar(par-1);
@ -738,10 +712,9 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
return ret;
}
if (varid > 0 && Token::Match(tok, "& %varid% [,()]", varid)) {
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
if (ftok == 0)
const Function *func = _tokenizer->getSymbolDatabase()->findFunctionByName(funcname, tok->scope());;
if (func == 0)
continue;
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByToken(ftok);
AllocType a;
const char *ret = functionArgAlloc(func, par, a);

View File

@ -116,7 +116,7 @@ public:
/**
* @brief Get type of allocation at given position
*/
AllocType getAllocationType(const Token *tok2, unsigned int varid, std::list<const Token *> *callstack = NULL) const;
AllocType getAllocationType(const Token *tok2, unsigned int varid, std::list<const Function*> *callstack = NULL) const;
/**
* @brief Get type of reallocation at given position
@ -158,7 +158,7 @@ public:
void memleakUponReallocFailureError(const Token *tok, const std::string &varname) const;
/** What type of allocated memory does the given function return? */
AllocType functionReturnType(const Token *tok, std::list<const Token *> *callstack = NULL) const;
AllocType functionReturnType(const Function* func, std::list<const Function*> *callstack = NULL) const;
/** Function allocates pointed-to argument (a la asprintf)? */
const char *functionArgAlloc(const Function *func, unsigned int targetpar, AllocType &allocType) const;

View File

@ -380,8 +380,7 @@ bool CheckNullPointer::CanFunctionAssignPointer(const Token *functiontoken, unsi
int argumentNumber = 0;
for (const Token *arg = functiontoken->tokAt(2); arg; arg = arg->nextArgument()) {
if (Token::Match(arg, "%varid% [,)]", varid)) {
const Token *ftok = _tokenizer->getFunctionTokenByName(functiontoken->str().c_str());
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByToken(ftok);
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(functiontoken->str(), functiontoken->scope());
if (!func) { // Unknown function
unknown = true;
return true; // assume that the function might assign the pointer

View File

@ -713,7 +713,7 @@ void CheckOther::checkRedundantAssignment()
}
}
} else if (scope->type == Scope::eSwitch) { // Avoid false positives if noreturn function is called in switch
const Function* func = symbolDatabase->findFunctionByToken(_tokenizer->getFunctionTokenByName(tok->str().c_str()));
const Function* func = symbolDatabase->findFunctionByName(tok->str(), tok->scope());;
if (!func || !func->hasBody) {
varAssignments.clear();
memAssignments.clear();
@ -3306,8 +3306,8 @@ void CheckOther::checkRedundantCopy()
const Token *match_end = (tok->next()->link()!=NULL)?tok->next()->link()->next():NULL;
if (match_end==NULL || !Token::Match(match_end,expect_end_token)) //avoid usage like "const A a = getA()+3"
break;
const Token *fToken = _tokenizer->getFunctionTokenByName(tok->str().c_str());
if (fToken &&fToken->previous() && fToken->previous()->str() == "&") {
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(tok->str(), tok->scope());;
if (func && func->tokenDef->previous() && func->tokenDef->previous()->str() == "&") {
redundantCopyError(var_tok,var_tok->str());
}
}

View File

@ -1156,8 +1156,7 @@ void CheckStl::string_c_str()
Token::simpleMatch(tok->linkAt(4), ") . c_str ( ) ;")) {
string_c_strError(tok);
} else if (Token::Match(tok, "return %var% (") && Token::simpleMatch(tok->linkAt(2), ") . c_str ( ) ;")) {
const Token* fTok = _tokenizer->getFunctionTokenByName(tok->strAt(1).c_str());
const Function* func = symbolDatabase->findFunctionByToken(fTok);
const Function* func =_tokenizer->getSymbolDatabase()->findFunctionByName(tok->strAt(1), tok->scope());;
if (func && Token::simpleMatch(func->tokenDef->tokAt(-3), "std :: string"))
string_c_strError(tok);
} else if (Token::simpleMatch(tok, "return (") &&

View File

@ -480,7 +480,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
continue;
}
}
} else if (scope->type == Scope::eFunction || scope->isLocal()) {
} else if (scope->isExecutable()) {
if (Token::simpleMatch(tok, "if (") &&
Token::simpleMatch(tok->next()->link(), ") {")) {
const Token *tok1 = tok->next()->link()->next();
@ -2124,6 +2124,25 @@ const Function *SymbolDatabase::findFunctionByToken(const Token *tok) const
return 0;
}
const Function* SymbolDatabase::findFunctionByName(const std::string& str, const Scope* startScope) const
{
const Scope* currScope = startScope;
while (currScope && currScope->isExecutable()) {
if (currScope->functionOf)
currScope = currScope->functionOf;
else
currScope = currScope->nestedIn;
}
while (currScope) {
for (std::list<Function>::const_iterator i = currScope->functionList.begin(); i != currScope->functionList.end(); ++i) {
if (i->tokenDef->str() == str)
return &*i;
}
currScope = currScope->nestedIn;
}
return 0;
}
//---------------------------------------------------------------------------
const Scope* SymbolDatabase::findScopeByName(const std::string& name) const

View File

@ -572,6 +572,8 @@ public:
const Function *findFunctionByToken(const Token *tok) const;
const Function* findFunctionByName(const std::string& str, const Scope* startScope) const;
const Scope* findScopeByName(const std::string& name) const;
bool isClassOrStruct(const std::string &type) const {

View File

@ -7507,19 +7507,6 @@ bool Tokenizer::IsScopeNoReturn(const Token *endScopeToken, bool *unknown)
//---------------------------------------------------------------------------
const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const
{
std::list<Scope>::const_iterator scope;
for (scope = _symbolDatabase->scopeList.begin(); scope != _symbolDatabase->scopeList.end(); ++scope) {
if (scope->type == Scope::eFunction) {
if (scope->classDef->str() == funcname)
return scope->classDef;
}
}
return NULL;
}
bool Tokenizer::isFunctionParameterPassedByValue(const Token *fpar) const
{
// TODO: If symbol database is available, use it.

View File

@ -142,14 +142,6 @@ public:
*/
unsigned int sizeOfType(const Token *type) const;
/**
* Get function token by function name
* @todo better handling of overloaded functions
* @todo only scan parent scopes
* @param funcname function name
*/
const Token *getFunctionTokenByName(const char funcname[]) const;
/**
* Try to determine if function parameter is passed by value by looking
* at the function declaration.

View File

@ -21,7 +21,7 @@
#include "tokenize.h"
#include "checkmemoryleak.h"
#include "testsuite.h"
#include "symboldatabase.h"
#include <sstream>
extern std::ostringstream errout;
@ -49,7 +49,7 @@ private:
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
return ((const CheckMemoryLeak *)0)->functionReturnType(tokenizer.tokens());
return ((const CheckMemoryLeak *)0)->functionReturnType(&tokenizer.getSymbolDatabase()->scopeList.front().functionList.front());
}
void testFunctionReturnType() {
@ -2421,7 +2421,7 @@ private:
check("void foo(char **str)\n"
"{\n"
" char *a = malloc(20)\n"
" char *a = malloc(20);\n"
" *str = a;\n"
"}\n"
"\n"

View File

@ -501,7 +501,7 @@ private:
GET_SYMBOL_DB("void func() { }\n")
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 2);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->next());
@ -509,7 +509,7 @@ private:
ASSERT(scope && scope->className == "func");
ASSERT(scope && scope->functionOf == 0);
const Function *function = db->findFunctionByToken(tokenizer.tokens()->next());
const Function *function = db->findFunctionByName("func", &db->scopeList.front());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->next());
@ -522,7 +522,7 @@ private:
GET_SYMBOL_DB("class Fred { void func() { } };\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
@ -530,7 +530,7 @@ private:
ASSERT(scope && scope->className == "func");
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(4));
const Function *function = db->findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
@ -543,14 +543,14 @@ private:
GET_SYMBOL_DB("class Fred { void func(); };\n")
// 2 scopes: Global and Class (no Function scope because there is no function implementation)
ASSERT(db && db->scopeList.size() == 2 && !tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 2);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
ASSERT(scope == NULL);
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(4));
const Function *function = db->findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
@ -562,7 +562,7 @@ private:
GET_SYMBOL_DB("class Fred { void func(); }; Fred::func() { }\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(12));
@ -570,7 +570,7 @@ private:
ASSERT(scope && scope->className == "func");
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(12));
const Function *function = db->findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(12));
@ -583,14 +583,14 @@ private:
GET_SYMBOL_DB("void (*func(int f))(char) { }\n")
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 2);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(3));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(3));
const Function *function = db->findFunctionByName("func", &db->scopeList.front());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(3));
@ -602,14 +602,14 @@ private:
GET_SYMBOL_DB("class Fred { void (*func(int f))(char) { } };\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(6));
const Function *function = db->findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
@ -621,14 +621,14 @@ private:
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); };\n")
// 2 scopes: Global and Class (no Function scope because there is no function implementation)
ASSERT(db && db->scopeList.size() == 2 && !tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 2);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
ASSERT(scope == NULL);
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(6));
const Function *function = db->findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
@ -640,14 +640,14 @@ private:
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); }; void (*Fred::func(int f))(char) { }\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(23));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(23));
const Function *function = db->findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(23));
@ -659,7 +659,7 @@ private:
GET_SYMBOL_DB("std::map<int, string> foo() {}")
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("foo"));
ASSERT(db && db->scopeList.size() == 2 && db->findFunctionByName("foo", &db->scopeList.back()));
if (db) {
const Scope *scope = &db->scopeList.front();
@ -677,7 +677,7 @@ private:
GET_SYMBOL_DB("void foo();\nvoid foo();\nint foo(int i);\nvoid foo() {}")
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("foo"));
ASSERT(db && db->scopeList.size() == 2 && db->findFunctionByName("foo", &db->scopeList.back()));
if (db) {
const Scope *scope = &db->scopeList.front();
@ -725,8 +725,8 @@ private:
// 3 scopes: Global, function, if
ASSERT_EQUALS(3, db->scopeList.size());
ASSERT(tokenizer.getFunctionTokenByName("func") != NULL);
ASSERT(tokenizer.getFunctionTokenByName("if") == NULL);
ASSERT(db->findFunctionByName("func", &db->scopeList.back()) != NULL);
ASSERT(db->findFunctionByName("if", &db->scopeList.back()) == NULL);
}
void parseFunctionDeclarationCorrect() {