reuse symbol database in checkmemoryleak.cpp. ticket: #2219
This commit is contained in:
parent
f1eef49fcb
commit
1842a122da
|
@ -43,13 +43,14 @@ CheckClass instance;
|
||||||
|
|
||||||
CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
|
CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
|
||||||
: Check(tokenizer, settings, errorLogger),
|
: Check(tokenizer, settings, errorLogger),
|
||||||
symbolDatabase(NULL)
|
symbolDatabase(NULL), ownSymbolDatabase(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckClass::~CheckClass()
|
CheckClass::~CheckClass()
|
||||||
{
|
{
|
||||||
|
if (ownSymbolDatabase)
|
||||||
delete symbolDatabase;
|
delete symbolDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +60,13 @@ void CheckClass::createSymbolDatabase()
|
||||||
if (symbolDatabase)
|
if (symbolDatabase)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (_tokenizer->_symbolDatabase)
|
||||||
|
symbolDatabase = _tokenizer->_symbolDatabase;
|
||||||
|
else
|
||||||
|
{
|
||||||
symbolDatabase = new SymbolDatabase(_tokenizer, _settings, _errorLogger);
|
symbolDatabase = new SymbolDatabase(_tokenizer, _settings, _errorLogger);
|
||||||
|
ownSymbolDatabase = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -36,7 +36,7 @@ class CheckClass : public Check
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** @brief This constructor is used when registering the CheckClass */
|
/** @brief This constructor is used when registering the CheckClass */
|
||||||
CheckClass() : Check(), symbolDatabase(NULL)
|
CheckClass() : Check(), symbolDatabase(NULL), ownSymbolDatabase(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/** @brief This constructor is used when running checks. */
|
/** @brief This constructor is used when running checks. */
|
||||||
|
@ -113,6 +113,7 @@ private:
|
||||||
void createSymbolDatabase();
|
void createSymbolDatabase();
|
||||||
|
|
||||||
SymbolDatabase *symbolDatabase;
|
SymbolDatabase *symbolDatabase;
|
||||||
|
bool ownSymbolDatabase;
|
||||||
|
|
||||||
// Reporting errors..
|
// Reporting errors..
|
||||||
void noConstructorError(const Token *tok, const std::string &classname, bool isStruct);
|
void noConstructorError(const Token *tok, const std::string &classname, bool isStruct);
|
||||||
|
|
|
@ -2573,81 +2573,49 @@ void CheckMemoryLeakInFunction::check()
|
||||||
|
|
||||||
void CheckMemoryLeakInClass::check()
|
void CheckMemoryLeakInClass::check()
|
||||||
{
|
{
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
SymbolDatabase * symbolDatabase = _tokenizer->_symbolDatabase;
|
||||||
{
|
bool ownSymbolDatabase = false;
|
||||||
if (tok->str() == "{")
|
|
||||||
tok = tok->link();
|
|
||||||
|
|
||||||
else if (Token::Match(tok, "class %var% [{:]"))
|
if (symbolDatabase == NULL)
|
||||||
{
|
{
|
||||||
std::vector<std::string> classname;
|
symbolDatabase = new SymbolDatabase(_tokenizer, _settings, _errorLogger);
|
||||||
classname.push_back(tok->strAt(1));
|
ownSymbolDatabase = true;
|
||||||
parseClass(tok, classname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<SymbolDatabase::SpaceInfo *>::iterator i;
|
||||||
|
|
||||||
void CheckMemoryLeakInClass::parseClass(const Token *tok1, std::vector<std::string> &classname)
|
for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i)
|
||||||
{
|
{
|
||||||
// Go into class.
|
const SymbolDatabase::SpaceInfo *info = *i;
|
||||||
while (tok1 && tok1->str() != "{")
|
|
||||||
tok1 = tok1->next();
|
|
||||||
tok1 = tok1 ? tok1->next() : 0;
|
|
||||||
|
|
||||||
// are we parsing the private scope of the class?
|
// only check classes and structures
|
||||||
bool privateScope = true;
|
if (info->type == SymbolDatabase::SpaceInfo::Class)
|
||||||
|
|
||||||
unsigned int indentlevel = 0;
|
|
||||||
for (const Token *tok = tok1; tok; tok = tok->next())
|
|
||||||
{
|
{
|
||||||
if (tok->str() == "{")
|
std::list<SymbolDatabase::Var>::const_iterator var;
|
||||||
++indentlevel;
|
for (var = info->varlist.begin(); var != info->varlist.end(); ++var)
|
||||||
|
|
||||||
else if (tok->str() == "}")
|
|
||||||
{
|
{
|
||||||
if (indentlevel == 0)
|
if (!var->isStatic && var->token->previous()->str() == "*")
|
||||||
return;
|
|
||||||
--indentlevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (tok->isName() && tok->str().find(":") != std::string::npos)
|
|
||||||
privateScope = bool(tok->str() == "private:");
|
|
||||||
|
|
||||||
// Only parse this particular class.. not subclasses
|
|
||||||
if (indentlevel > 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip static variables..
|
|
||||||
if (Token::Match(tok, "static %type% * %var% ;"))
|
|
||||||
{
|
|
||||||
tok = tok->tokAt(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declaring subclass.. recursive checking
|
|
||||||
if (Token::Match(tok, "class %var% [{:]"))
|
|
||||||
{
|
|
||||||
classname.push_back(tok->strAt(1));
|
|
||||||
parseClass(tok, classname);
|
|
||||||
classname.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declaring member variable.. check allocations and deallocations
|
|
||||||
if (Token::Match(tok->previous(), ";|{|}|private:|protected:|public: %type% * %var% ;"))
|
|
||||||
{
|
{
|
||||||
// allocation but no deallocation of private variables in public function..
|
// allocation but no deallocation of private variables in public function..
|
||||||
if (privateScope && tok->isStandardType())
|
if (var->access == SymbolDatabase::Private && var->token->tokAt(-2)->isStandardType())
|
||||||
checkPublicFunctions(tok1, tok->tokAt(2)->varId());
|
checkPublicFunctions(var->token, var->token->varId());
|
||||||
|
|
||||||
if (!isclass(_tokenizer, tok))
|
if (var->token->tokAt(-2)->isStandardType())
|
||||||
variable(classname.back(), tok->tokAt(2));
|
variable(info, var->token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckMemoryLeakInClass::variable(const std::string &classname, const Token *tokVarname)
|
if (ownSymbolDatabase)
|
||||||
|
delete symbolDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CheckMemoryLeakInClass::variable(const SymbolDatabase::SpaceInfo *classinfo, const Token *tokVarname)
|
||||||
{
|
{
|
||||||
const std::string varname = tokVarname->strAt(0);
|
const std::string varname = tokVarname->strAt(0);
|
||||||
|
const std::string classname = classinfo->className;
|
||||||
|
|
||||||
// Check if member variable has been allocated and deallocated..
|
// Check if member variable has been allocated and deallocated..
|
||||||
CheckMemoryLeak::AllocType Alloc = CheckMemoryLeak::No;
|
CheckMemoryLeak::AllocType Alloc = CheckMemoryLeak::No;
|
||||||
|
@ -2656,14 +2624,13 @@ void CheckMemoryLeakInClass::variable(const std::string &classname, const Token
|
||||||
bool allocInConstructor = false;
|
bool allocInConstructor = false;
|
||||||
bool deallocInDestructor = false;
|
bool deallocInDestructor = false;
|
||||||
|
|
||||||
// Loop through all tokens. Inspect member functions
|
// Inspect member functions
|
||||||
int indent_ = 0;
|
std::list<SymbolDatabase::Func>::const_iterator func;
|
||||||
const Token *functionToken = _tokenizer->findClassFunction(_tokenizer->tokens(), classname.c_str(), "~| %var%", indent_);
|
for (func = classinfo->functionList.begin(); func != classinfo->functionList.end(); ++func)
|
||||||
while (functionToken)
|
|
||||||
{
|
{
|
||||||
const bool constructor(Token::Match(functionToken, (classname + " (").c_str()) || Token::Match(functionToken, (classname + " :: " + classname + " (").c_str()));
|
const Token *functionToken = func->token;
|
||||||
const bool destructor(functionToken->str() == "~" || functionToken->tokAt(2)->str() == "~");
|
const bool constructor = func->type == SymbolDatabase::Func::Constructor;
|
||||||
|
const bool destructor = func->type == SymbolDatabase::Func::Destructor;
|
||||||
unsigned int indent = 0;
|
unsigned int indent = 0;
|
||||||
bool initlist = false;
|
bool initlist = false;
|
||||||
for (const Token *tok = functionToken; tok; tok = tok->next())
|
for (const Token *tok = functionToken; tok; tok = tok->next())
|
||||||
|
@ -2765,8 +2732,6 @@ void CheckMemoryLeakInClass::variable(const std::string &classname, const Token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
functionToken = _tokenizer->Tokenizer::findClassFunction(functionToken->next(), classname.c_str(), "~| %var%", indent_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocInConstructor && !deallocInDestructor)
|
if (allocInConstructor && !deallocInDestructor)
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "symboldatabase.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -376,8 +377,7 @@ public:
|
||||||
void check();
|
void check();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseClass(const Token *tok1, std::vector<std::string> &classname);
|
void variable(const SymbolDatabase::SpaceInfo *spaceinfo, const Token *tokVarname);
|
||||||
void variable(const std::string &classname, const Token *tokVarname);
|
|
||||||
|
|
||||||
/** Public functions: possible double-allocation */
|
/** Public functions: possible double-allocation */
|
||||||
void checkPublicFunctions(const Token *classtok, const unsigned int varid);
|
void checkPublicFunctions(const Token *classtok, const unsigned int varid);
|
||||||
|
|
|
@ -256,6 +256,11 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
if (tok->previous() && tok->previous()->str() == "::")
|
if (tok->previous() && tok->previous()->str() == "::")
|
||||||
addFunction(&info, &tok, argStart);
|
addFunction(&info, &tok, argStart);
|
||||||
|
|
||||||
|
// class destructor
|
||||||
|
else if (tok->previous() && tok->previous()->str() == "~" &&
|
||||||
|
tok->previous()->previous() && tok->previous()->previous()->str() == "::")
|
||||||
|
addFunction(&info, &tok, argStart);
|
||||||
|
|
||||||
// regular function
|
// regular function
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -493,11 +498,17 @@ bool SymbolDatabase::argsMatch(const Token *first, const Token *second, const st
|
||||||
|
|
||||||
void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Token *argStart)
|
void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Token *argStart)
|
||||||
{
|
{
|
||||||
const Token *tok1 = (*tok)->tokAt(-2); // skip class/struct name
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
bool added = false;
|
bool added = false;
|
||||||
std::string path;
|
std::string path;
|
||||||
unsigned int path_length = 0;
|
unsigned int path_length = 0;
|
||||||
|
const Token *tok1;
|
||||||
|
|
||||||
|
// skip class/struct name
|
||||||
|
if ((*tok)->previous()->str() == "~")
|
||||||
|
tok1 = (*tok)->tokAt(-3);
|
||||||
|
else
|
||||||
|
tok1 = (*tok)->tokAt(-2);
|
||||||
|
|
||||||
// back up to head of path
|
// back up to head of path
|
||||||
while (tok1 && tok1->previous() && tok1->previous()->str() == "::")
|
while (tok1 && tok1->previous() && tok1->previous()->str() == "::")
|
||||||
|
@ -565,6 +576,17 @@ void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Toke
|
||||||
func->arg = argStart;
|
func->arg = argStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (func->type == SymbolDatabase::Func::Destructor &&
|
||||||
|
(*tok)->previous()->str() == "~" &&
|
||||||
|
func->tokenDef->str() == (*tok)->str())
|
||||||
|
{
|
||||||
|
if (argsMatch(func->tokenDef->next(), (*tok)->next(), path, path_length))
|
||||||
|
{
|
||||||
|
func->hasBody = true;
|
||||||
|
func->token = *tok;
|
||||||
|
func->arg = argStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (func->tokenDef->str() == (*tok)->str())
|
else if (func->tokenDef->str() == (*tok)->str())
|
||||||
{
|
{
|
||||||
if (argsMatch(func->tokenDef->next(), (*tok)->next(), path, path_length))
|
if (argsMatch(func->tokenDef->next(), (*tok)->next(), path, path_length))
|
||||||
|
@ -576,7 +598,7 @@ void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Toke
|
||||||
(!func->isConst && (*tok)->next()->link()->next()->str() != "const"))
|
(!func->isConst && (*tok)->next()->link()->next()->str() != "const"))
|
||||||
{
|
{
|
||||||
func->hasBody = true;
|
func->hasBody = true;
|
||||||
func->token = (*tok);
|
func->token = *tok;
|
||||||
func->arg = argStart;
|
func->arg = argStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -586,7 +608,7 @@ void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Toke
|
||||||
{
|
{
|
||||||
// todo check for const
|
// todo check for const
|
||||||
func->hasBody = true;
|
func->hasBody = true;
|
||||||
func->token = (*tok);
|
func->token = *tok;
|
||||||
func->arg = argStart;
|
func->arg = argStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
196
lib/tokenize.cpp
196
lib/tokenize.cpp
|
@ -30,6 +30,7 @@
|
||||||
#include "errorlogger.h"
|
#include "errorlogger.h"
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
#include "symboldatabase.h"
|
||||||
|
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -52,6 +53,7 @@ Tokenizer::Tokenizer()
|
||||||
_tokens = 0;
|
_tokens = 0;
|
||||||
_tokensBack = 0;
|
_tokensBack = 0;
|
||||||
_codeWithTemplates = false;
|
_codeWithTemplates = false;
|
||||||
|
_symbolDatabase = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger)
|
Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger)
|
||||||
|
@ -60,11 +62,13 @@ Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger)
|
||||||
_tokens = 0;
|
_tokens = 0;
|
||||||
_tokensBack = 0;
|
_tokensBack = 0;
|
||||||
_codeWithTemplates = false;
|
_codeWithTemplates = false;
|
||||||
|
_symbolDatabase = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tokenizer::~Tokenizer()
|
Tokenizer::~Tokenizer()
|
||||||
{
|
{
|
||||||
deallocateTokens();
|
deallocateTokens();
|
||||||
|
delete _symbolDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -3737,7 +3741,8 @@ void Tokenizer::simplifySizeof()
|
||||||
bool Tokenizer::simplifyTokenList()
|
bool Tokenizer::simplifyTokenList()
|
||||||
{
|
{
|
||||||
// clear the _functionList so it can't contain dead pointers
|
// clear the _functionList so it can't contain dead pointers
|
||||||
_functionList.clear();
|
delete _symbolDatabase;
|
||||||
|
_symbolDatabase = NULL;
|
||||||
|
|
||||||
for (Token *tok = _tokens; tok; tok = tok->next())
|
for (Token *tok = _tokens; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
|
@ -7461,11 +7466,19 @@ void Tokenizer::simplifyStd()
|
||||||
|
|
||||||
const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const
|
const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < _functionList.size(); ++i)
|
if (_symbolDatabase == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
std::list<SymbolDatabase::SpaceInfo *>::iterator i;
|
||||||
|
|
||||||
|
for (i = _symbolDatabase->spaceInfoList.begin(); i != _symbolDatabase->spaceInfoList.end(); ++i)
|
||||||
{
|
{
|
||||||
if (_functionList[i]->str() == funcname)
|
SymbolDatabase::SpaceInfo *info = *i;
|
||||||
|
|
||||||
|
if (info->type == SymbolDatabase::SpaceInfo::Function)
|
||||||
{
|
{
|
||||||
return _functionList[i];
|
if (info->classDef->str() == funcname)
|
||||||
|
return info->classDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -7474,80 +7487,7 @@ const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const
|
||||||
|
|
||||||
void Tokenizer::fillFunctionList()
|
void Tokenizer::fillFunctionList()
|
||||||
{
|
{
|
||||||
_functionList.clear();
|
_symbolDatabase = new SymbolDatabase(this, _settings, _errorLogger);
|
||||||
|
|
||||||
for (const Token *tok = _tokens; tok; tok = tok->next())
|
|
||||||
{
|
|
||||||
if (tok->str() == "{")
|
|
||||||
{
|
|
||||||
tok = tok->link();
|
|
||||||
if (!tok)
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::Match(tok, "%var% ("))
|
|
||||||
{
|
|
||||||
// Check if this is the first token of a function implementation..
|
|
||||||
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next())
|
|
||||||
{
|
|
||||||
if (tok2->str() == ";")
|
|
||||||
{
|
|
||||||
tok = tok2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (tok2->str() == "{")
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (tok2->str() == ")")
|
|
||||||
{
|
|
||||||
if (Token::Match(tok2, ") const| {"))
|
|
||||||
{
|
|
||||||
_functionList.push_back(tok);
|
|
||||||
tok = tok2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tok = tok2;
|
|
||||||
while (tok->next() && !Token::Match(tok->next(), "[;{]"))
|
|
||||||
tok = tok->next();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the _functionList functions with duplicate names, remove them
|
|
||||||
/** @todo handle when functions with the same name */
|
|
||||||
for (unsigned int func1 = 0; func1 < _functionList.size();)
|
|
||||||
{
|
|
||||||
bool hasDuplicates = false;
|
|
||||||
for (unsigned int func2 = func1 + 1; func2 < _functionList.size();)
|
|
||||||
{
|
|
||||||
if (_functionList[func1]->str() == _functionList[func2]->str())
|
|
||||||
{
|
|
||||||
hasDuplicates = true;
|
|
||||||
_functionList.erase(_functionList.begin() + static_cast<int>(func2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++func2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! hasDuplicates)
|
|
||||||
{
|
|
||||||
++func1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_functionList.erase(_functionList.begin() + static_cast<int>(func1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -7604,106 +7544,6 @@ std::string Tokenizer::file(const Token *tok) const
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
const Token * Tokenizer::findClassFunction(const Token *tok, const std::string &classname, const std::string &funcname, int &indentlevel, bool isStruct) const
|
|
||||||
{
|
|
||||||
if (indentlevel < 0 || tok == NULL)
|
|
||||||
return NULL;
|
|
||||||
/*
|
|
||||||
// TODO: This is currently commented out as updateClassList doesn't
|
|
||||||
// fully work yet and call to updateClassList is currently also
|
|
||||||
// commented out.
|
|
||||||
|
|
||||||
//std::cout << tok->str()<<"--\n";
|
|
||||||
if( tok == _tokens || tok->str() == "class" || tok->str() == "struct")
|
|
||||||
tok = 0;
|
|
||||||
|
|
||||||
std::map<std::string, ClassInfo>::const_iterator iter;
|
|
||||||
iter = _classInfoList.find(classname);
|
|
||||||
if( iter == _classInfoList.end() )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for( size_t i = 0; i < iter->second._memberFunctions.size(); i++ )
|
|
||||||
if( Token::Match( iter->second._memberFunctions[i]._declaration, funcname ) )
|
|
||||||
{
|
|
||||||
if( tok != 0 )
|
|
||||||
{
|
|
||||||
if( tok == iter->second._memberFunctions[i]._implementation ||
|
|
||||||
tok->previous() == iter->second._memberFunctions[i]._implementation)
|
|
||||||
tok = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return iter->second._memberFunctions[i]._implementation;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
*/
|
|
||||||
const std::string classPattern(std::string(isStruct ? "struct " : "class ") + classname + " :|{");
|
|
||||||
const std::string internalPattern(std::string("!!~ ") + funcname + " (");
|
|
||||||
const std::string externalPattern(classname + " :: " + funcname + " (");
|
|
||||||
|
|
||||||
for (; tok; tok = tok->next())
|
|
||||||
{
|
|
||||||
if (indentlevel == 0 && Token::Match(tok, classPattern.c_str()))
|
|
||||||
{
|
|
||||||
while (tok && tok->str() != "{")
|
|
||||||
tok = tok->next();
|
|
||||||
if (tok)
|
|
||||||
tok = tok->next();
|
|
||||||
if (! tok)
|
|
||||||
break;
|
|
||||||
indentlevel = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok->str() == "{")
|
|
||||||
{
|
|
||||||
// If indentlevel==0 don't go to indentlevel 1. Skip the block.
|
|
||||||
if (indentlevel > 0)
|
|
||||||
++indentlevel;
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// skip the block
|
|
||||||
tok = tok->link();
|
|
||||||
if (tok == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok->str() == "}")
|
|
||||||
{
|
|
||||||
--indentlevel;
|
|
||||||
if (indentlevel < 0)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indentlevel == 1)
|
|
||||||
{
|
|
||||||
// Member function implemented in the class declaration?
|
|
||||||
if (Token::Match(tok->previous(), internalPattern.c_str()))
|
|
||||||
{
|
|
||||||
const Token *tok2 = tok;
|
|
||||||
while (tok2 && tok2->str() != "{" && tok2->str() != ";")
|
|
||||||
tok2 = tok2->next();
|
|
||||||
if (tok2 && tok2->str() == "{")
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (indentlevel == 0 && Token::Match(tok, externalPattern.c_str()))
|
|
||||||
{
|
|
||||||
if (!Token::simpleMatch(tok->previous(), "::"))
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not found
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void Tokenizer::syntaxError(const Token *tok)
|
void Tokenizer::syntaxError(const Token *tok)
|
||||||
{
|
{
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
class Token;
|
class Token;
|
||||||
class ErrorLogger;
|
class ErrorLogger;
|
||||||
class Settings;
|
class Settings;
|
||||||
|
class SymbolDatabase;
|
||||||
|
|
||||||
/// @addtogroup Core
|
/// @addtogroup Core
|
||||||
/// @{
|
/// @{
|
||||||
|
@ -124,17 +125,6 @@ public:
|
||||||
|
|
||||||
std::string file(const Token *tok) const;
|
std::string file(const Token *tok) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a class or struct member function
|
|
||||||
* @param tok where to begin the search
|
|
||||||
* @param classname name of class
|
|
||||||
* @param funcname name of function ("~ Fred" => destructor for fred, "%var%" => any function)
|
|
||||||
* @param indentlevel Just an integer that you initialize to 0 before the first call.
|
|
||||||
* @param isStruct is it a struct
|
|
||||||
* @return First matching token or NULL.
|
|
||||||
*/
|
|
||||||
const Token *findClassFunction(const Token *tok, const std::string &classname, const std::string &funcname, int &indentlevel, bool isStruct = false) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get error messages
|
* get error messages
|
||||||
*/
|
*/
|
||||||
|
@ -285,7 +275,7 @@ public:
|
||||||
/** Simplify "if else" */
|
/** Simplify "if else" */
|
||||||
void elseif();
|
void elseif();
|
||||||
|
|
||||||
std::vector<const Token *> _functionList;
|
SymbolDatabase * _symbolDatabase;
|
||||||
|
|
||||||
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno, bool split = false);
|
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno, bool split = false);
|
||||||
void addtoken(const Token *tok, const unsigned int lineno, const unsigned int fileno);
|
void addtoken(const Token *tok, const unsigned int lineno, const unsigned int fileno);
|
||||||
|
|
|
@ -3139,6 +3139,7 @@ private:
|
||||||
TEST_CASE(class16);
|
TEST_CASE(class16);
|
||||||
TEST_CASE(class17);
|
TEST_CASE(class17);
|
||||||
TEST_CASE(class18);
|
TEST_CASE(class18);
|
||||||
|
TEST_CASE(class19); // ticket #2219
|
||||||
|
|
||||||
TEST_CASE(staticvar);
|
TEST_CASE(staticvar);
|
||||||
|
|
||||||
|
@ -3528,6 +3529,25 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void class19()
|
||||||
|
{
|
||||||
|
// Ticket #2219
|
||||||
|
check("class Foo\n"
|
||||||
|
"{\n"
|
||||||
|
"private:\n"
|
||||||
|
" TRadioButton* rp1;\n"
|
||||||
|
" TRadioButton* rp2;\n"
|
||||||
|
"public:\n"
|
||||||
|
" Foo();\n"
|
||||||
|
"};\n"
|
||||||
|
"Foo::Foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" rp1 = new TRadioButton(this);\n"
|
||||||
|
" rp2 = new TRadioButton(this);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void staticvar()
|
void staticvar()
|
||||||
{
|
{
|
||||||
check("class A\n"
|
check("class A\n"
|
||||||
|
|
|
@ -67,10 +67,6 @@ private:
|
||||||
|
|
||||||
TEST_CASE(inlineasm);
|
TEST_CASE(inlineasm);
|
||||||
|
|
||||||
TEST_CASE(dupfuncname);
|
|
||||||
|
|
||||||
TEST_CASE(const_and_volatile_functions);
|
|
||||||
|
|
||||||
TEST_CASE(ifAddBraces1);
|
TEST_CASE(ifAddBraces1);
|
||||||
TEST_CASE(ifAddBraces2);
|
TEST_CASE(ifAddBraces2);
|
||||||
TEST_CASE(ifAddBraces3);
|
TEST_CASE(ifAddBraces3);
|
||||||
|
@ -204,9 +200,6 @@ private:
|
||||||
TEST_CASE(simplify_constants);
|
TEST_CASE(simplify_constants);
|
||||||
TEST_CASE(simplify_constants2);
|
TEST_CASE(simplify_constants2);
|
||||||
|
|
||||||
TEST_CASE(findClassFunction1);
|
|
||||||
TEST_CASE(findClassFunction2);
|
|
||||||
|
|
||||||
TEST_CASE(vardecl1);
|
TEST_CASE(vardecl1);
|
||||||
TEST_CASE(vardecl2);
|
TEST_CASE(vardecl2);
|
||||||
TEST_CASE(vardecl3);
|
TEST_CASE(vardecl3);
|
||||||
|
@ -587,61 +580,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dupfuncname()
|
|
||||||
{
|
|
||||||
const char code[] = "void a()\n"
|
|
||||||
"{ }\n"
|
|
||||||
"void a(int i)\n"
|
|
||||||
"{ }\n"
|
|
||||||
"void b()\n"
|
|
||||||
"{ }\n";
|
|
||||||
// tokenize..
|
|
||||||
Tokenizer tokenizer;
|
|
||||||
std::istringstream istr(code);
|
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
|
||||||
|
|
||||||
tokenizer.fillFunctionList();
|
|
||||||
|
|
||||||
ASSERT_EQUALS(1, static_cast<unsigned int>(tokenizer._functionList.size()));
|
|
||||||
ASSERT_EQUALS("b", tokenizer._functionList[0]->str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void const_and_volatile_functions()
|
|
||||||
{
|
|
||||||
const char code[] = "class B\n\
|
|
||||||
{\n\
|
|
||||||
public:\n\
|
|
||||||
void a();\n\
|
|
||||||
void b() const;\n\
|
|
||||||
void c() volatile;\n\
|
|
||||||
};\n\
|
|
||||||
\n\
|
|
||||||
void B::a()\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
void B::b() const\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
void B::c() volatile\n\
|
|
||||||
{}\n";
|
|
||||||
|
|
||||||
|
|
||||||
// tokenize..
|
|
||||||
Tokenizer tokenizer;
|
|
||||||
std::istringstream istr(code);
|
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
|
||||||
|
|
||||||
tokenizer.fillFunctionList();
|
|
||||||
|
|
||||||
ASSERT_EQUALS(3, static_cast<unsigned int>(tokenizer._functionList.size()));
|
|
||||||
if (tokenizer._functionList.size() == 3)
|
|
||||||
{
|
|
||||||
ASSERT_EQUALS("a", tokenizer._functionList[0]->str());
|
|
||||||
ASSERT_EQUALS("b", tokenizer._functionList[1]->str());
|
|
||||||
ASSERT_EQUALS("c", tokenizer._functionList[2]->str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void pointers_condition()
|
void pointers_condition()
|
||||||
{
|
{
|
||||||
ASSERT_EQUALS("( p )", tokenizeAndStringify("( p != NULL )", true));
|
ASSERT_EQUALS("( p )", tokenizeAndStringify("( p != NULL )", true));
|
||||||
|
@ -3531,54 +3469,6 @@ private:
|
||||||
ASSERT_EQUALS(oss.str(), ostr.str());
|
ASSERT_EQUALS(oss.str(), ostr.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void findClassFunction1()
|
|
||||||
{
|
|
||||||
const char code[] =
|
|
||||||
"class Fred"
|
|
||||||
"{\n"
|
|
||||||
"public:\n"
|
|
||||||
" Fred()\n"
|
|
||||||
" { }\n"
|
|
||||||
"};\n";
|
|
||||||
|
|
||||||
// tokenize..
|
|
||||||
Tokenizer tokenizer;
|
|
||||||
std::istringstream istr(code);
|
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
const Token *tok = tokenizer.findClassFunction(tokenizer.tokens(), "Fred", "%var%", i);
|
|
||||||
ASSERT_EQUALS(true, Token::simpleMatch(tok, "Fred ( ) {"));
|
|
||||||
tok = tokenizer.findClassFunction(tok->next(), "Fred", "%var%", i);
|
|
||||||
ASSERT_EQUALS(0, tok ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void findClassFunction2()
|
|
||||||
{
|
|
||||||
const char code[] =
|
|
||||||
"struct Fred"
|
|
||||||
"{\n"
|
|
||||||
" Fred()\n"
|
|
||||||
" { }\n"
|
|
||||||
"};\n";
|
|
||||||
|
|
||||||
// tokenize..
|
|
||||||
Tokenizer tokenizer;
|
|
||||||
std::istringstream istr(code);
|
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
const Token *tok = tokenizer.findClassFunction(tokenizer.tokens(), "Fred", "%var%", i, true);
|
|
||||||
ASSERT_EQUALS(true, Token::simpleMatch(tok, "Fred ( ) {"));
|
|
||||||
tok = tokenizer.findClassFunction(tok->next(), "Fred", "%var%", i, false);
|
|
||||||
ASSERT_EQUALS(0, tok ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vardecl1()
|
void vardecl1()
|
||||||
{
|
{
|
||||||
const char code[] = "unsigned int a, b;";
|
const char code[] = "unsigned int a, b;";
|
||||||
|
|
Loading…
Reference in New Issue