Replaced Tokenizer::getFunctionTokenByName() by SymbolDatabase::findFunctionByName(), which handles scopes slightly better.
This commit is contained in:
parent
64faa780fe
commit
22a8e3f4e6
|
@ -596,44 +596,20 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int p
|
||||||
// Calling a user function?
|
// Calling a user function?
|
||||||
// only 1-dimensional arrays can be checked currently
|
// only 1-dimensional arrays can be checked currently
|
||||||
else if (arrayInfo.num().size() == 1) {
|
else if (arrayInfo.num().size() == 1) {
|
||||||
const Token *ftok = _tokenizer->getFunctionTokenByName(tok.str().c_str());
|
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(tok.str(), tok.scope());;
|
||||||
if (Token::Match(ftok, "%var% (") && Token::Match(ftok->next()->link(), ") const| {")) {
|
if (func && func->hasBody) {
|
||||||
// Get varid for the corresponding parameter..
|
// Get corresponding parameter..
|
||||||
const Token *ftok2 = ftok->tokAt(2);
|
const Variable* parameter = func->getArgumentVar(par-1);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No parameterVarId => bail out
|
// Ensure that it has a compatible size..
|
||||||
if (parameterVarId == 0)
|
if (!parameter || _tokenizer->sizeOfType(parameter->typeStartToken()) != arrayInfo.element_size())
|
||||||
return;
|
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..
|
// 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 (")) {
|
if (Token::Match(ftok, "if|for|while (")) {
|
||||||
// bailout if there is buffer usage..
|
// bailout if there is buffer usage..
|
||||||
if (bailoutIfSwitch(ftok, parameterVarId)) {
|
if (bailoutIfSwitch(ftok, parameter->varId())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,7 +628,7 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int p
|
||||||
if (ftok->str() == "}")
|
if (ftok->str() == "}")
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ftok->varId() == parameterVarId) {
|
if (ftok->varId() == parameter->varId()) {
|
||||||
if (Token::Match(ftok->previous(), "-- %var%") ||
|
if (Token::Match(ftok->previous(), "-- %var%") ||
|
||||||
Token::Match(ftok, "%var% --"))
|
Token::Match(ftok, "%var% --"))
|
||||||
break;
|
break;
|
||||||
|
@ -674,7 +650,7 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int p
|
||||||
// Calling function..
|
// Calling function..
|
||||||
if (Token::Match(ftok, "%var% (")) {
|
if (Token::Match(ftok, "%var% (")) {
|
||||||
ArrayInfo ai(arrayInfo);
|
ArrayInfo ai(arrayInfo);
|
||||||
ai.varid(parameterVarId);
|
ai.varid(parameter->varId());
|
||||||
checkFunctionCall(ftok, ai, callstack);
|
checkFunctionCall(ftok, ai, callstack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...
|
// What we may have...
|
||||||
// * var = (char *)malloc(10);
|
// * var = (char *)malloc(10);
|
||||||
|
@ -208,20 +208,20 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
|
||||||
}
|
}
|
||||||
|
|
||||||
// User function
|
// User function
|
||||||
const Token *ftok = tokenizer->getFunctionTokenByName(tok2->str().c_str());
|
const Function* func = tokenizer->getSymbolDatabase()->findFunctionByName(tok2->str(), tok2->scope());
|
||||||
if (ftok == NULL)
|
if (func == NULL)
|
||||||
return No;
|
return No;
|
||||||
|
|
||||||
// Prevent recursion
|
// 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;
|
return No;
|
||||||
|
|
||||||
std::list<const Token *> cs;
|
std::list<const Function*> cs;
|
||||||
if (!callstack)
|
if (!callstack)
|
||||||
callstack = &cs;
|
callstack = &cs;
|
||||||
|
|
||||||
callstack->push_back(ftok);
|
callstack->push_back(func);
|
||||||
return functionReturnType(ftok, callstack);
|
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);
|
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;
|
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..
|
// Get return pointer..
|
||||||
unsigned int varid = 0;
|
unsigned int varid = 0;
|
||||||
unsigned int indentlevel = 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() == "{")
|
if (tok2->str() == "{")
|
||||||
++indentlevel;
|
++indentlevel;
|
||||||
else if (tok2->str() == "}") {
|
else if (tok2->str() == "}") {
|
||||||
|
@ -471,7 +451,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok,
|
||||||
|
|
||||||
// Check if return pointer is allocated..
|
// Check if return pointer is allocated..
|
||||||
AllocType allocType = No;
|
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)) {
|
if (Token::Match(tok, "%varid% =", varid)) {
|
||||||
allocType = getAllocationType(tok->tokAt(2), varid, callstack);
|
allocType = getAllocationType(tok->tokAt(2), varid, callstack);
|
||||||
}
|
}
|
||||||
|
@ -656,20 +636,18 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
|
|
||||||
// lock/unlock..
|
// lock/unlock..
|
||||||
if (varid == 0) {
|
if (varid == 0) {
|
||||||
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
|
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(funcname, tok->scope());;
|
||||||
while (ftok && (ftok->str() != "{"))
|
if (!func || !func->hasBody)
|
||||||
ftok = ftok->next();
|
|
||||||
if (!ftok)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Token *func = getcode(ftok->next(), callstack, 0, alloctype, dealloctype, false, 1);
|
Token *ftok = getcode(func->functionScope->classStart->next(), callstack, 0, alloctype, dealloctype, false, 1);
|
||||||
simplifycode(func);
|
simplifycode(ftok);
|
||||||
const char *ret = 0;
|
const char *ret = 0;
|
||||||
if (Token::simpleMatch(func, "; alloc ; }"))
|
if (Token::simpleMatch(ftok, "; alloc ; }"))
|
||||||
ret = "alloc";
|
ret = "alloc";
|
||||||
else if (Token::simpleMatch(func, "; dealloc ; }"))
|
else if (Token::simpleMatch(ftok, "; dealloc ; }"))
|
||||||
ret = "dealloc";
|
ret = "dealloc";
|
||||||
TokenList::deleteTokens(func);
|
TokenList::deleteTokens(ftok);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,16 +680,12 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
if (dot)
|
if (dot)
|
||||||
return "use";
|
return "use";
|
||||||
|
|
||||||
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
|
const Function* function = _tokenizer->getSymbolDatabase()->findFunctionByName(funcname, tok->scope());;
|
||||||
if (!ftok)
|
if (!function)
|
||||||
return "use";
|
return "use";
|
||||||
|
|
||||||
// how many parameters does the function want?
|
// how many parameters does the function want?
|
||||||
if (numpar != countParameters(ftok))
|
if (numpar != function->argCount()) // TODO: Handle default parameters
|
||||||
return "recursive";
|
|
||||||
|
|
||||||
const Function* function = _tokenizer->getSymbolDatabase()->findFunctionByToken(ftok);
|
|
||||||
if (!function)
|
|
||||||
return "recursive";
|
return "recursive";
|
||||||
|
|
||||||
const Variable* param = function->getArgumentVar(par-1);
|
const Variable* param = function->getArgumentVar(par-1);
|
||||||
|
@ -738,10 +712,9 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (varid > 0 && Token::Match(tok, "& %varid% [,()]", varid)) {
|
if (varid > 0 && Token::Match(tok, "& %varid% [,()]", varid)) {
|
||||||
const Token *ftok = _tokenizer->getFunctionTokenByName(funcname.c_str());
|
const Function *func = _tokenizer->getSymbolDatabase()->findFunctionByName(funcname, tok->scope());;
|
||||||
if (ftok == 0)
|
if (func == 0)
|
||||||
continue;
|
continue;
|
||||||
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByToken(ftok);
|
|
||||||
AllocType a;
|
AllocType a;
|
||||||
const char *ret = functionArgAlloc(func, par, a);
|
const char *ret = functionArgAlloc(func, par, a);
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Get type of allocation at given position
|
* @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
|
* @brief Get type of reallocation at given position
|
||||||
|
@ -158,7 +158,7 @@ public:
|
||||||
void memleakUponReallocFailureError(const Token *tok, const std::string &varname) const;
|
void memleakUponReallocFailureError(const Token *tok, const std::string &varname) const;
|
||||||
|
|
||||||
/** What type of allocated memory does the given function return? */
|
/** 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)? */
|
/** Function allocates pointed-to argument (a la asprintf)? */
|
||||||
const char *functionArgAlloc(const Function *func, unsigned int targetpar, AllocType &allocType) const;
|
const char *functionArgAlloc(const Function *func, unsigned int targetpar, AllocType &allocType) const;
|
||||||
|
|
|
@ -380,8 +380,7 @@ bool CheckNullPointer::CanFunctionAssignPointer(const Token *functiontoken, unsi
|
||||||
int argumentNumber = 0;
|
int argumentNumber = 0;
|
||||||
for (const Token *arg = functiontoken->tokAt(2); arg; arg = arg->nextArgument()) {
|
for (const Token *arg = functiontoken->tokAt(2); arg; arg = arg->nextArgument()) {
|
||||||
if (Token::Match(arg, "%varid% [,)]", varid)) {
|
if (Token::Match(arg, "%varid% [,)]", varid)) {
|
||||||
const Token *ftok = _tokenizer->getFunctionTokenByName(functiontoken->str().c_str());
|
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(functiontoken->str(), functiontoken->scope());
|
||||||
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByToken(ftok);
|
|
||||||
if (!func) { // Unknown function
|
if (!func) { // Unknown function
|
||||||
unknown = true;
|
unknown = true;
|
||||||
return true; // assume that the function might assign the pointer
|
return true; // assume that the function might assign the pointer
|
||||||
|
|
|
@ -713,7 +713,7 @@ void CheckOther::checkRedundantAssignment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (scope->type == Scope::eSwitch) { // Avoid false positives if noreturn function is called in switch
|
} 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) {
|
if (!func || !func->hasBody) {
|
||||||
varAssignments.clear();
|
varAssignments.clear();
|
||||||
memAssignments.clear();
|
memAssignments.clear();
|
||||||
|
@ -3306,8 +3306,8 @@ void CheckOther::checkRedundantCopy()
|
||||||
const Token *match_end = (tok->next()->link()!=NULL)?tok->next()->link()->next():NULL;
|
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"
|
if (match_end==NULL || !Token::Match(match_end,expect_end_token)) //avoid usage like "const A a = getA()+3"
|
||||||
break;
|
break;
|
||||||
const Token *fToken = _tokenizer->getFunctionTokenByName(tok->str().c_str());
|
const Function* func = _tokenizer->getSymbolDatabase()->findFunctionByName(tok->str(), tok->scope());;
|
||||||
if (fToken &&fToken->previous() && fToken->previous()->str() == "&") {
|
if (func && func->tokenDef->previous() && func->tokenDef->previous()->str() == "&") {
|
||||||
redundantCopyError(var_tok,var_tok->str());
|
redundantCopyError(var_tok,var_tok->str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1156,8 +1156,7 @@ void CheckStl::string_c_str()
|
||||||
Token::simpleMatch(tok->linkAt(4), ") . c_str ( ) ;")) {
|
Token::simpleMatch(tok->linkAt(4), ") . c_str ( ) ;")) {
|
||||||
string_c_strError(tok);
|
string_c_strError(tok);
|
||||||
} else if (Token::Match(tok, "return %var% (") && Token::simpleMatch(tok->linkAt(2), ") . c_str ( ) ;")) {
|
} 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 =_tokenizer->getSymbolDatabase()->findFunctionByName(tok->strAt(1), tok->scope());;
|
||||||
const Function* func = symbolDatabase->findFunctionByToken(fTok);
|
|
||||||
if (func && Token::simpleMatch(func->tokenDef->tokAt(-3), "std :: string"))
|
if (func && Token::simpleMatch(func->tokenDef->tokAt(-3), "std :: string"))
|
||||||
string_c_strError(tok);
|
string_c_strError(tok);
|
||||||
} else if (Token::simpleMatch(tok, "return (") &&
|
} else if (Token::simpleMatch(tok, "return (") &&
|
||||||
|
|
|
@ -480,7 +480,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (scope->type == Scope::eFunction || scope->isLocal()) {
|
} else if (scope->isExecutable()) {
|
||||||
if (Token::simpleMatch(tok, "if (") &&
|
if (Token::simpleMatch(tok, "if (") &&
|
||||||
Token::simpleMatch(tok->next()->link(), ") {")) {
|
Token::simpleMatch(tok->next()->link(), ") {")) {
|
||||||
const Token *tok1 = tok->next()->link()->next();
|
const Token *tok1 = tok->next()->link()->next();
|
||||||
|
@ -2124,6 +2124,25 @@ const Function *SymbolDatabase::findFunctionByToken(const Token *tok) const
|
||||||
return 0;
|
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
|
const Scope* SymbolDatabase::findScopeByName(const std::string& name) const
|
||||||
|
|
|
@ -572,6 +572,8 @@ public:
|
||||||
|
|
||||||
const Function *findFunctionByToken(const Token *tok) const;
|
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;
|
const Scope* findScopeByName(const std::string& name) const;
|
||||||
|
|
||||||
bool isClassOrStruct(const std::string &type) const {
|
bool isClassOrStruct(const std::string &type) const {
|
||||||
|
|
|
@ -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
|
bool Tokenizer::isFunctionParameterPassedByValue(const Token *fpar) const
|
||||||
{
|
{
|
||||||
// TODO: If symbol database is available, use it.
|
// TODO: If symbol database is available, use it.
|
||||||
|
|
|
@ -142,14 +142,6 @@ public:
|
||||||
*/
|
*/
|
||||||
unsigned int sizeOfType(const Token *type) const;
|
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
|
* Try to determine if function parameter is passed by value by looking
|
||||||
* at the function declaration.
|
* at the function declaration.
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include "checkmemoryleak.h"
|
#include "checkmemoryleak.h"
|
||||||
#include "testsuite.h"
|
#include "testsuite.h"
|
||||||
|
#include "symboldatabase.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
extern std::ostringstream errout;
|
extern std::ostringstream errout;
|
||||||
|
@ -49,7 +49,7 @@ private:
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
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() {
|
void testFunctionReturnType() {
|
||||||
|
@ -2421,7 +2421,7 @@ private:
|
||||||
|
|
||||||
check("void foo(char **str)\n"
|
check("void foo(char **str)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *a = malloc(20)\n"
|
" char *a = malloc(20);\n"
|
||||||
" *str = a;\n"
|
" *str = a;\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
@ -501,7 +501,7 @@ private:
|
||||||
GET_SYMBOL_DB("void func() { }\n")
|
GET_SYMBOL_DB("void func() { }\n")
|
||||||
|
|
||||||
// 2 scopes: Global and Function
|
// 2 scopes: Global and Function
|
||||||
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func"));
|
ASSERT(db && db->scopeList.size() == 2);
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->next());
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->next());
|
||||||
|
@ -509,7 +509,7 @@ private:
|
||||||
ASSERT(scope && scope->className == "func");
|
ASSERT(scope && scope->className == "func");
|
||||||
ASSERT(scope && scope->functionOf == 0);
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->next());
|
ASSERT(function && function->token == tokenizer.tokens()->next());
|
||||||
|
@ -522,7 +522,7 @@ private:
|
||||||
GET_SYMBOL_DB("class Fred { void func() { } };\n")
|
GET_SYMBOL_DB("class Fred { void func() { } };\n")
|
||||||
|
|
||||||
// 3 scopes: Global, Class, and Function
|
// 3 scopes: Global, Class, and Function
|
||||||
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
|
ASSERT(db && db->scopeList.size() == 3);
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
|
||||||
|
@ -530,7 +530,7 @@ private:
|
||||||
ASSERT(scope && scope->className == "func");
|
ASSERT(scope && scope->className == "func");
|
||||||
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
|
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
|
||||||
|
@ -543,14 +543,14 @@ private:
|
||||||
GET_SYMBOL_DB("class Fred { void func(); };\n")
|
GET_SYMBOL_DB("class Fred { void func(); };\n")
|
||||||
|
|
||||||
// 2 scopes: Global and Class (no Function scope because there is no function implementation)
|
// 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) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
|
||||||
|
|
||||||
ASSERT(scope == NULL);
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
|
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
|
||||||
|
@ -562,7 +562,7 @@ private:
|
||||||
GET_SYMBOL_DB("class Fred { void func(); }; Fred::func() { }\n")
|
GET_SYMBOL_DB("class Fred { void func(); }; Fred::func() { }\n")
|
||||||
|
|
||||||
// 3 scopes: Global, Class, and Function
|
// 3 scopes: Global, Class, and Function
|
||||||
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
|
ASSERT(db && db->scopeList.size() == 3);
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(12));
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(12));
|
||||||
|
@ -570,7 +570,7 @@ private:
|
||||||
ASSERT(scope && scope->className == "func");
|
ASSERT(scope && scope->className == "func");
|
||||||
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->tokAt(12));
|
ASSERT(function && function->token == tokenizer.tokens()->tokAt(12));
|
||||||
|
@ -583,14 +583,14 @@ private:
|
||||||
GET_SYMBOL_DB("void (*func(int f))(char) { }\n")
|
GET_SYMBOL_DB("void (*func(int f))(char) { }\n")
|
||||||
|
|
||||||
// 2 scopes: Global and Function
|
// 2 scopes: Global and Function
|
||||||
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func"));
|
ASSERT(db && db->scopeList.size() == 2);
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(3));
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(3));
|
||||||
|
|
||||||
ASSERT(scope && scope->className == "func");
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->tokAt(3));
|
ASSERT(function && function->token == tokenizer.tokens()->tokAt(3));
|
||||||
|
@ -602,14 +602,14 @@ private:
|
||||||
GET_SYMBOL_DB("class Fred { void (*func(int f))(char) { } };\n")
|
GET_SYMBOL_DB("class Fred { void (*func(int f))(char) { } };\n")
|
||||||
|
|
||||||
// 3 scopes: Global, Class, and Function
|
// 3 scopes: Global, Class, and Function
|
||||||
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
|
ASSERT(db && db->scopeList.size() == 3);
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
|
||||||
|
|
||||||
ASSERT(scope && scope->className == "func");
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
|
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
|
||||||
|
@ -621,14 +621,14 @@ private:
|
||||||
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); };\n")
|
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)
|
// 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) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
|
||||||
|
|
||||||
ASSERT(scope == NULL);
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
|
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")
|
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); }; void (*Fred::func(int f))(char) { }\n")
|
||||||
|
|
||||||
// 3 scopes: Global, Class, and Function
|
// 3 scopes: Global, Class, and Function
|
||||||
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
|
ASSERT(db && db->scopeList.size() == 3);
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(23));
|
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(23));
|
||||||
|
|
||||||
ASSERT(scope && scope->className == "func");
|
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->str() == "func");
|
||||||
ASSERT(function && function->token == tokenizer.tokens()->tokAt(23));
|
ASSERT(function && function->token == tokenizer.tokens()->tokAt(23));
|
||||||
|
@ -659,7 +659,7 @@ private:
|
||||||
GET_SYMBOL_DB("std::map<int, string> foo() {}")
|
GET_SYMBOL_DB("std::map<int, string> foo() {}")
|
||||||
|
|
||||||
// 2 scopes: Global and Function
|
// 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) {
|
if (db) {
|
||||||
const Scope *scope = &db->scopeList.front();
|
const Scope *scope = &db->scopeList.front();
|
||||||
|
@ -677,7 +677,7 @@ private:
|
||||||
GET_SYMBOL_DB("void foo();\nvoid foo();\nint foo(int i);\nvoid foo() {}")
|
GET_SYMBOL_DB("void foo();\nvoid foo();\nint foo(int i);\nvoid foo() {}")
|
||||||
|
|
||||||
// 2 scopes: Global and Function
|
// 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) {
|
if (db) {
|
||||||
const Scope *scope = &db->scopeList.front();
|
const Scope *scope = &db->scopeList.front();
|
||||||
|
@ -725,8 +725,8 @@ private:
|
||||||
// 3 scopes: Global, function, if
|
// 3 scopes: Global, function, if
|
||||||
ASSERT_EQUALS(3, db->scopeList.size());
|
ASSERT_EQUALS(3, db->scopeList.size());
|
||||||
|
|
||||||
ASSERT(tokenizer.getFunctionTokenByName("func") != NULL);
|
ASSERT(db->findFunctionByName("func", &db->scopeList.back()) != NULL);
|
||||||
ASSERT(tokenizer.getFunctionTokenByName("if") == NULL);
|
ASSERT(db->findFunctionByName("if", &db->scopeList.back()) == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseFunctionDeclarationCorrect() {
|
void parseFunctionDeclarationCorrect() {
|
||||||
|
|
Loading…
Reference in New Issue