Revert revisions 627 and 628
This commit is contained in:
parent
e8d2c7cfb3
commit
eb80c9786f
|
@ -35,7 +35,7 @@
|
||||||
// _callStack used when parsing into subfunctions.
|
// _callStack used when parsing into subfunctions.
|
||||||
|
|
||||||
|
|
||||||
CheckBufferOverrunClass::CheckBufferOverrunClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger )
|
CheckBufferOverrunClass::CheckBufferOverrunClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger )
|
||||||
: _settings(settings)
|
: _settings(settings)
|
||||||
{
|
{
|
||||||
_tokenizer = tokenizer;
|
_tokenizer = tokenizer;
|
||||||
|
@ -216,10 +216,10 @@ void CheckBufferOverrunClass::CheckBufferOverrun_CheckScope( const TOKEN *tok, c
|
||||||
{
|
{
|
||||||
// Don't make recursive checking..
|
// Don't make recursive checking..
|
||||||
if (std::find(_callStack.begin(), _callStack.end(), tok) != _callStack.end())
|
if (std::find(_callStack.begin(), _callStack.end(), tok) != _callStack.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Only perform this checking if showAll setting is enabled..
|
// Only perform this checking if showAll setting is enabled..
|
||||||
if ( ! _settings._showAll )
|
if ( ! _settings._showAll )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned int parlevel = 0, par = 0;
|
unsigned int parlevel = 0, par = 0;
|
||||||
|
|
|
@ -43,7 +43,7 @@ private:
|
||||||
void CheckBufferOverrun_CheckScope( const TOKEN *tok, const char *varname[], const int size, const int total_size );
|
void CheckBufferOverrun_CheckScope( const TOKEN *tok, const char *varname[], const int size, const int total_size );
|
||||||
void ReportError(const TOKEN *tok, const char errmsg[]);
|
void ReportError(const TOKEN *tok, const char errmsg[]);
|
||||||
|
|
||||||
const Tokenizer *_tokenizer;
|
const Tokenizer *_tokenizer;
|
||||||
const Settings _settings;
|
const Settings _settings;
|
||||||
ErrorLogger *_errorLogger;
|
ErrorLogger *_errorLogger;
|
||||||
std::list<const TOKEN *> _callStack;
|
std::list<const TOKEN *> _callStack;
|
||||||
|
|
146
CheckClass.cpp
146
CheckClass.cpp
|
@ -111,27 +111,27 @@ struct CheckClass::VAR *CheckClass::ClassChecking_GetVarList(const TOKEN *tok1)
|
||||||
|
|
||||||
const TOKEN * CheckClass::FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel )
|
const TOKEN * CheckClass::FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel )
|
||||||
{
|
{
|
||||||
if ( indentlevel < 0 || tok == NULL )
|
if ( indentlevel < 0 || tok == NULL )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
std::ostringstream classPattern;
|
std::ostringstream classPattern;
|
||||||
classPattern << "class " << classname << " :|{";
|
classPattern << "class " << classname << " :|{";
|
||||||
|
|
||||||
std::ostringstream internalPattern;
|
std::ostringstream internalPattern;
|
||||||
internalPattern << funcname << " (";
|
internalPattern << funcname << " (";
|
||||||
|
|
||||||
std::ostringstream externalPattern;
|
std::ostringstream externalPattern;
|
||||||
externalPattern << classname << " :: " << funcname << " (";
|
externalPattern << classname << " :: " << funcname << " (";
|
||||||
|
|
||||||
for ( ;tok; tok = tok->next() )
|
for ( ;tok; tok = tok->next() )
|
||||||
{
|
{
|
||||||
if ( indentlevel == 0 && TOKEN::Match(tok, classPattern.str().c_str()) )
|
if ( indentlevel == 0 && TOKEN::Match(tok, classPattern.str().c_str()) )
|
||||||
{
|
{
|
||||||
while ( tok && tok->str() != "{" )
|
while ( tok && tok->str() != "{" )
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
if ( tok )
|
if ( tok )
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
if ( ! tok )
|
if ( ! tok )
|
||||||
break;
|
break;
|
||||||
indentlevel = 1;
|
indentlevel = 1;
|
||||||
}
|
}
|
||||||
|
@ -403,12 +403,12 @@ void CheckClass::CheckConstructors()
|
||||||
|
|
||||||
// Check that all member variables are initialized..
|
// Check that all member variables are initialized..
|
||||||
struct VAR *varlist = ClassChecking_GetVarList(tok1);
|
struct VAR *varlist = ClassChecking_GetVarList(tok1);
|
||||||
|
|
||||||
// Check constructors
|
// Check constructors
|
||||||
CheckConstructors( tok1, varlist, className[0] );
|
CheckConstructors( tok1, varlist, className[0] );
|
||||||
|
|
||||||
// Check assignment operators
|
// Check assignment operators
|
||||||
CheckConstructors( tok1, varlist, "operator =" );
|
CheckConstructors( tok1, varlist, "operator =" );
|
||||||
|
|
||||||
// Delete the varlist..
|
// Delete the varlist..
|
||||||
while (varlist)
|
while (varlist)
|
||||||
|
@ -421,43 +421,43 @@ void CheckClass::CheckConstructors()
|
||||||
tok1 = TOKEN::findmatch( tok1->next(), pattern_class );
|
tok1 = TOKEN::findmatch( tok1->next(), pattern_class );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckClass::CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[])
|
void CheckClass::CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[])
|
||||||
{
|
{
|
||||||
const char * const className = tok1->strAt(1);
|
const char * const className = tok1->strAt(1);
|
||||||
|
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
const TOKEN *constructor_token = FindClassFunction( tok1, className, funcname, indentlevel );
|
const TOKEN *constructor_token = FindClassFunction( tok1, className, funcname, indentlevel );
|
||||||
std::list<std::string> callstack;
|
std::list<std::string> callstack;
|
||||||
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className, callstack);
|
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className, callstack);
|
||||||
while ( constructor_token )
|
while ( constructor_token )
|
||||||
{
|
{
|
||||||
// Check if any variables are uninitialized
|
// Check if any variables are uninitialized
|
||||||
for (struct VAR *var = varlist; var; var = var->next)
|
for (struct VAR *var = varlist; var; var = var->next)
|
||||||
{
|
{
|
||||||
if ( var->init )
|
if ( var->init )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Is it a static member variable?
|
// Is it a static member variable?
|
||||||
std::ostringstream pattern;
|
std::ostringstream pattern;
|
||||||
pattern << className << "::" << var->name << "=";
|
pattern << className << "::" << var->name << "=";
|
||||||
if (TOKEN::findmatch(_tokenizer->tokens(), pattern.str().c_str()))
|
if (TOKEN::findmatch(_tokenizer->tokens(), pattern.str().c_str()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// It's non-static and it's not initialized => error
|
// It's non-static and it's not initialized => error
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
ostr << _tokenizer->fileLine(constructor_token);
|
ostr << _tokenizer->fileLine(constructor_token);
|
||||||
ostr << " Uninitialized member variable '" << className << "::" << var->name << "'";
|
ostr << " Uninitialized member variable '" << className << "::" << var->name << "'";
|
||||||
_errorLogger->reportErr(ostr.str());
|
_errorLogger->reportErr(ostr.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( struct VAR *var = varlist; var; var = var->next )
|
for ( struct VAR *var = varlist; var; var = var->next )
|
||||||
var->init = false;
|
var->init = false;
|
||||||
|
|
||||||
constructor_token = FindClassFunction( constructor_token->next(), className, funcname, indentlevel );
|
constructor_token = FindClassFunction( constructor_token->next(), className, funcname, indentlevel );
|
||||||
callstack.clear();
|
callstack.clear();
|
||||||
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className, callstack);
|
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className, callstack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -692,9 +692,9 @@ void CheckClass::virtualDestructor()
|
||||||
// Iterate through each base class...
|
// Iterate through each base class...
|
||||||
derived = derived->tokAt(3);
|
derived = derived->tokAt(3);
|
||||||
while ( TOKEN::Match(derived, "%var%") )
|
while ( TOKEN::Match(derived, "%var%") )
|
||||||
{
|
{
|
||||||
bool isPublic = TOKEN::Match(derived, "public");
|
bool isPublic = TOKEN::Match(derived, "public");
|
||||||
|
|
||||||
// What kind of inheritance is it.. public|protected|private
|
// What kind of inheritance is it.. public|protected|private
|
||||||
if ( TOKEN::Match( derived, "public|protected|private" ) )
|
if ( TOKEN::Match( derived, "public|protected|private" ) )
|
||||||
derived = derived->next();
|
derived = derived->next();
|
||||||
|
@ -702,15 +702,15 @@ void CheckClass::virtualDestructor()
|
||||||
// Name of base class..
|
// Name of base class..
|
||||||
const char *baseName[2];
|
const char *baseName[2];
|
||||||
baseName[0] = derived->strAt(0);
|
baseName[0] = derived->strAt(0);
|
||||||
baseName[1] = 0;
|
baseName[1] = 0;
|
||||||
|
|
||||||
// Update derived so it's ready for the next loop.
|
// Update derived so it's ready for the next loop.
|
||||||
derived = derived->next();
|
derived = derived->next();
|
||||||
if ( TOKEN::Match(derived, ",") )
|
if ( TOKEN::Match(derived, ",") )
|
||||||
derived = derived->next();
|
derived = derived->next();
|
||||||
|
|
||||||
// If not public inheritance, skip checking of this base class..
|
// If not public inheritance, skip checking of this base class..
|
||||||
if ( ! isPublic )
|
if ( ! isPublic )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Find the destructor declaration for the base class.
|
// Find the destructor declaration for the base class.
|
||||||
|
|
26
CheckClass.h
26
CheckClass.h
|
@ -38,25 +38,25 @@ public:
|
||||||
void CheckMemset();
|
void CheckMemset();
|
||||||
|
|
||||||
void CheckOperatorEq1(); // Warning upon "void operator=(.."
|
void CheckOperatorEq1(); // Warning upon "void operator=(.."
|
||||||
|
|
||||||
// The destructor in a base class should be virtual
|
// The destructor in a base class should be virtual
|
||||||
void virtualDestructor();
|
void virtualDestructor();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct VAR
|
struct VAR
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
bool init;
|
bool init;
|
||||||
struct VAR *next;
|
struct VAR *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ClassChecking_VarList_Initialize(const TOKEN *tok1, const TOKEN *ftok, struct VAR *varlist, const char classname[], std::list<std::string> &callstack);
|
void ClassChecking_VarList_Initialize(const TOKEN *tok1, const TOKEN *ftok, struct VAR *varlist, const char classname[], std::list<std::string> &callstack);
|
||||||
void InitVar(struct VAR *varlist, const char varname[]);
|
void InitVar(struct VAR *varlist, const char varname[]);
|
||||||
const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel );
|
const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel );
|
||||||
struct VAR *ClassChecking_GetVarList(const TOKEN *tok1);
|
struct VAR *ClassChecking_GetVarList(const TOKEN *tok1);
|
||||||
|
|
||||||
// Check constructors for a specified class
|
// Check constructors for a specified class
|
||||||
void CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[]);
|
void CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[]);
|
||||||
|
|
||||||
const Tokenizer *_tokenizer;
|
const Tokenizer *_tokenizer;
|
||||||
Settings _settings;
|
Settings _settings;
|
||||||
|
|
|
@ -95,9 +95,9 @@ void CheckFunctionUsage::parseTokens( const Tokenizer &tokenizer )
|
||||||
TOKEN::Match(tok, ":: %var% (") ||
|
TOKEN::Match(tok, ":: %var% (") ||
|
||||||
TOKEN::Match(tok, "|= %var% (") ||
|
TOKEN::Match(tok, "|= %var% (") ||
|
||||||
TOKEN::Match(tok, "&= %var% (") ||
|
TOKEN::Match(tok, "&= %var% (") ||
|
||||||
TOKEN::Match(tok, "&& %var% (") ||
|
TOKEN::Match(tok, "&& %var% (") ||
|
||||||
TOKEN::Match(tok, "|| %var% (") ||
|
TOKEN::Match(tok, "|| %var% (") ||
|
||||||
TOKEN::Match(tok, "else %var% (") ||
|
TOKEN::Match(tok, "else %var% (") ||
|
||||||
TOKEN::Match(tok, "return %var% (") )
|
TOKEN::Match(tok, "return %var% (") )
|
||||||
funcname = tok->next();
|
funcname = tok->next();
|
||||||
|
|
||||||
|
@ -146,9 +146,9 @@ void CheckFunctionUsage::check()
|
||||||
continue;
|
continue;
|
||||||
if ( ! func.usedSameFile )
|
if ( ! func.usedSameFile )
|
||||||
{
|
{
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
if ( func.filename != "+" )
|
if ( func.filename != "+" )
|
||||||
errmsg << "[" << func.filename << "] ";
|
errmsg << "[" << func.filename << "] ";
|
||||||
errmsg << "The function '" << it->first << "' is never used.";
|
errmsg << "The function '" << it->first << "' is never used.";
|
||||||
_errorLogger->reportErr( errmsg.str() );
|
_errorLogger->reportErr( errmsg.str() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <stdlib.h> // free
|
#include <stdlib.h> // free
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CheckMemoryLeakClass::CheckMemoryLeakClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger )
|
CheckMemoryLeakClass::CheckMemoryLeakClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger )
|
||||||
: _settings(settings)
|
: _settings(settings)
|
||||||
{
|
{
|
||||||
_tokenizer = tokenizer;
|
_tokenizer = tokenizer;
|
||||||
|
@ -51,7 +51,7 @@ CheckMemoryLeakClass::~CheckMemoryLeakClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckMemoryLeakClass::isclass( const TOKEN *tok )
|
bool CheckMemoryLeakClass::isclass( const TOKEN *tok )
|
||||||
{
|
{
|
||||||
if ( tok->isStandardType() )
|
if ( tok->isStandardType() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -135,32 +135,32 @@ CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetAllocationType( const T
|
||||||
return No;
|
return No;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetReallocationType( const TOKEN *tok2 )
|
CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetReallocationType( const TOKEN *tok2 )
|
||||||
{
|
{
|
||||||
// What we may have...
|
// What we may have...
|
||||||
// * var = (char *)realloc(..;
|
// * var = (char *)realloc(..;
|
||||||
if ( tok2 && tok2->str() == "(" )
|
if ( tok2 && tok2->str() == "(" )
|
||||||
{
|
{
|
||||||
while ( tok2 && tok2->str() != ")" )
|
while ( tok2 && tok2->str() != ")" )
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
tok2 = tok2 ? tok2->next() : NULL;
|
tok2 = tok2 ? tok2->next() : NULL;
|
||||||
}
|
}
|
||||||
if ( ! tok2 )
|
if ( ! tok2 )
|
||||||
return No;
|
return No;
|
||||||
|
|
||||||
if ( TOKEN::Match(tok2, "realloc") )
|
if ( TOKEN::Match(tok2, "realloc") )
|
||||||
return Malloc;
|
return Malloc;
|
||||||
|
|
||||||
// GTK memory reallocation..
|
// GTK memory reallocation..
|
||||||
if ( TOKEN::Match(tok2, "g_realloc|g_try_realloc|g_renew|g_try_renew") )
|
if ( TOKEN::Match(tok2, "g_realloc|g_try_realloc|g_renew|g_try_renew") )
|
||||||
return gMalloc;
|
return gMalloc;
|
||||||
|
|
||||||
return No;
|
return No;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetDeallocationType( const TOKEN *tok, const char *varnames[] )
|
CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetDeallocationType( const TOKEN *tok, const char *varnames[] )
|
||||||
{
|
{
|
||||||
if ( TOKEN::Match(tok, "delete %var1% ;", varnames) )
|
if ( TOKEN::Match(tok, "delete %var1% ;", varnames) )
|
||||||
|
@ -234,30 +234,30 @@ const char * CheckMemoryLeakClass::call_func( const TOKEN *tok, std::list<const
|
||||||
while ( ftok && (ftok->str() != "{") )
|
while ( ftok && (ftok->str() != "{") )
|
||||||
ftok = ftok->next();
|
ftok = ftok->next();
|
||||||
TOKEN *func = getcode( ftok->tokAt(1), callstack, parname, alloctype, dealloctype );
|
TOKEN *func = getcode( ftok->tokAt(1), callstack, parname, alloctype, dealloctype );
|
||||||
simplifycode( func );
|
simplifycode( func );
|
||||||
const TOKEN *func_ = func;
|
const TOKEN *func_ = func;
|
||||||
while ( func_ && func_->str() == ";" )
|
while ( func_ && func_->str() == ";" )
|
||||||
func_ = func_->next();
|
func_ = func_->next();
|
||||||
/*
|
/*
|
||||||
for (const TOKEN *t = func; t; t = t->next())
|
for (const TOKEN *t = func; t; t = t->next())
|
||||||
{
|
{
|
||||||
std::cout << t->str() << "\n";
|
std::cout << t->str() << "\n";
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
const char *ret = 0;
|
const char *ret = 0;
|
||||||
if (TOKEN::findmatch(func_, "goto"))
|
if (TOKEN::findmatch(func_, "goto"))
|
||||||
{
|
{
|
||||||
// TODO : "goto" isn't handled well
|
// TODO : "goto" isn't handled well
|
||||||
if ( TOKEN::findmatch(func_, "dealloc") )
|
if ( TOKEN::findmatch(func_, "dealloc") )
|
||||||
ret = "dealloc";
|
ret = "dealloc";
|
||||||
else if ( TOKEN::findmatch(func_, "use") )
|
else if ( TOKEN::findmatch(func_, "use") )
|
||||||
ret = "use";
|
ret = "use";
|
||||||
}
|
}
|
||||||
else if ( TOKEN::findmatch(func_, "dealloc") )
|
else if ( TOKEN::findmatch(func_, "dealloc") )
|
||||||
ret = "dealloc";
|
ret = "dealloc";
|
||||||
else if ( TOKEN::findmatch(func_, "use") )
|
else if ( TOKEN::findmatch(func_, "use") )
|
||||||
ret = "use";
|
ret = "use";
|
||||||
|
|
||||||
Tokenizer::deleteTokens(func);
|
Tokenizer::deleteTokens(func);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -325,11 +325,11 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, std::list<const TOKEN *>
|
||||||
rethead = newtok; \
|
rethead = newtok; \
|
||||||
rettail=newtok; \
|
rettail=newtok; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The first token should be ";"
|
// The first token should be ";"
|
||||||
addtoken(";");
|
addtoken(";");
|
||||||
|
|
||||||
|
|
||||||
bool isloop = false;
|
bool isloop = false;
|
||||||
|
|
||||||
|
@ -361,24 +361,24 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, std::list<const TOKEN *>
|
||||||
|
|
||||||
if (TOKEN::Match(tok, "[(;{}] %var1% =", varnames))
|
if (TOKEN::Match(tok, "[(;{}] %var1% =", varnames))
|
||||||
{
|
{
|
||||||
AllocType alloc = GetAllocationType(tok->tokAt(3));
|
AllocType alloc = GetAllocationType(tok->tokAt(3));
|
||||||
|
|
||||||
if ( alloc == No )
|
if ( alloc == No )
|
||||||
{
|
{
|
||||||
alloc = GetReallocationType( tok->tokAt(3) );
|
alloc = GetReallocationType( tok->tokAt(3) );
|
||||||
if ( alloc != No )
|
if ( alloc != No )
|
||||||
{
|
{
|
||||||
addtoken( "dealloc" );
|
addtoken( "dealloc" );
|
||||||
addtoken( ";" );
|
addtoken( ";" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If "--all" hasn't been given, don't check classes..
|
// If "--all" hasn't been given, don't check classes..
|
||||||
if ( alloc == New && ! _settings._showAll )
|
if ( alloc == New && ! _settings._showAll )
|
||||||
{
|
{
|
||||||
if ( TOKEN::Match(tok->tokAt(3), "new %type% [(;]") )
|
if ( TOKEN::Match(tok->tokAt(3), "new %type% [(;]") )
|
||||||
{
|
{
|
||||||
if ( isclass( tok->tokAt(4) ) )
|
if ( isclass( tok->tokAt(4) ) )
|
||||||
alloc = No;
|
alloc = No;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,12 +391,12 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, std::list<const TOKEN *>
|
||||||
if (dealloctype!=No && dealloctype!=alloc)
|
if (dealloctype!=No && dealloctype!=alloc)
|
||||||
MismatchError(tok, callstack, varname);
|
MismatchError(tok, callstack, varname);
|
||||||
alloctype = alloc;
|
alloctype = alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// assignment..
|
// assignment..
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addtoken( "assign" );
|
addtoken( "assign" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,10 +416,10 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, std::list<const TOKEN *>
|
||||||
TOKEN::Match(tok, "if ( %var1% != 0 )", varnames) ||
|
TOKEN::Match(tok, "if ( %var1% != 0 )", varnames) ||
|
||||||
TOKEN::Match(tok, "if ( 0 != %var1% )", varnames) )
|
TOKEN::Match(tok, "if ( 0 != %var1% )", varnames) )
|
||||||
{
|
{
|
||||||
addtoken("if(var)");
|
addtoken("if(var)");
|
||||||
|
|
||||||
// Make sure the "use" will not be added
|
// Make sure the "use" will not be added
|
||||||
while ( tok->str() != ")" )
|
while ( tok->str() != ")" )
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
}
|
}
|
||||||
else if ( TOKEN::Match(tok, "if (") && notvar(tok->tokAt(2), varnames) )
|
else if ( TOKEN::Match(tok, "if (") && notvar(tok->tokAt(2), varnames) )
|
||||||
|
@ -514,10 +514,10 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, std::list<const TOKEN *>
|
||||||
if ( tok->str() == "throw" )
|
if ( tok->str() == "throw" )
|
||||||
addtoken("throw");
|
addtoken("throw");
|
||||||
|
|
||||||
// Assignment..
|
// Assignment..
|
||||||
if ( TOKEN::Match(tok,"[)=] %var1% [;)]", varnames) ||
|
if ( TOKEN::Match(tok,"[)=] %var1% [;)]", varnames) ||
|
||||||
TOKEN::Match(tok, "%var1% +=|-=", varnames) )
|
TOKEN::Match(tok, "%var1% +=|-=", varnames) )
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
|
|
||||||
// Investigate function calls..
|
// Investigate function calls..
|
||||||
if ( TOKEN::Match(tok, "%var% (") )
|
if ( TOKEN::Match(tok, "%var% (") )
|
||||||
|
@ -525,21 +525,21 @@ TOKEN *CheckMemoryLeakClass::getcode(const TOKEN *tok, std::list<const TOKEN *>
|
||||||
const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype);
|
const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype);
|
||||||
if ( str )
|
if ( str )
|
||||||
addtoken( str );
|
addtoken( str );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback..
|
// Callback..
|
||||||
if ( TOKEN::Match(tok, "( * %var% ) (") )
|
if ( TOKEN::Match(tok, "( * %var% ) (") )
|
||||||
{
|
{
|
||||||
for ( const TOKEN *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next() )
|
for ( const TOKEN *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next() )
|
||||||
{
|
{
|
||||||
if ( TOKEN::Match(tok2, ";{") )
|
if ( TOKEN::Match(tok2, ";{") )
|
||||||
break;
|
break;
|
||||||
else if ( tok2->str() == varname )
|
else if ( tok2->str() == varname )
|
||||||
{
|
{
|
||||||
addtoken("use");
|
addtoken("use");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linux lists..
|
// Linux lists..
|
||||||
|
@ -605,80 +605,80 @@ void CheckMemoryLeakClass::simplifycode(TOKEN *tok)
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete empty if that is not followed by an else
|
// Delete empty if that is not followed by an else
|
||||||
if (tok2->tokAt(2) &&
|
if (tok2->tokAt(2) &&
|
||||||
(tok2->next()->str().find("if") == 0) &&
|
(tok2->next()->str().find("if") == 0) &&
|
||||||
TOKEN::Match(tok2->tokAt(2), ";") &&
|
TOKEN::Match(tok2->tokAt(2), ";") &&
|
||||||
!TOKEN::Match(tok2->tokAt(3), "else"))
|
!TOKEN::Match(tok2->tokAt(3), "else"))
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(2));
|
erase(tok2, tok2->tokAt(2));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete "if ; else ;"
|
// Delete "if ; else ;"
|
||||||
if ( TOKEN::Match(tok2->next(), "if ; else ;") )
|
if ( TOKEN::Match(tok2->next(), "if ; else ;") )
|
||||||
{
|
{
|
||||||
erase( tok2, tok2->tokAt(4) );
|
erase( tok2, tok2->tokAt(4) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Make this more generic. Delete "if ; else use ; use"
|
// TODO Make this more generic. Delete "if ; else use ; use"
|
||||||
if ( TOKEN::Match(tok2, "; if ; else use ; use") ||
|
if ( TOKEN::Match(tok2, "; if ; else use ; use") ||
|
||||||
TOKEN::Match(tok2, "; if use ; else ; use") )
|
TOKEN::Match(tok2, "; if use ; else ; use") )
|
||||||
{
|
{
|
||||||
erase( tok2, tok2->tokAt(4) );
|
erase( tok2, tok2->tokAt(4) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "if dealloc ;" and "if use ;" that is not followed by an else..
|
// Reduce "if dealloc ;" and "if use ;" that is not followed by an else..
|
||||||
// If "--all" has been given these are deleted
|
// If "--all" has been given these are deleted
|
||||||
// Otherwise, ony the "if" will be deleted
|
// Otherwise, ony the "if" will be deleted
|
||||||
if ((TOKEN::Match(tok2, "[;{}] if dealloc ;") || TOKEN::Match(tok2, "[;{}] if use ;")) &&
|
if ((TOKEN::Match(tok2, "[;{}] if dealloc ;") || TOKEN::Match(tok2, "[;{}] if use ;")) &&
|
||||||
!TOKEN::Match(tok2->tokAt(4), "else"))
|
!TOKEN::Match(tok2->tokAt(4), "else"))
|
||||||
{
|
{
|
||||||
if ( _settings._showAll )
|
if ( _settings._showAll )
|
||||||
erase(tok2, tok2->tokAt(3));
|
erase(tok2, tok2->tokAt(3));
|
||||||
else
|
else
|
||||||
erase( tok2, tok2->tokAt(2) );
|
erase( tok2, tok2->tokAt(2) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "if(var) dealloc ;" and "if(var) use ;" that is not followed by an else..
|
// Reduce "if(var) dealloc ;" and "if(var) use ;" that is not followed by an else..
|
||||||
if ((TOKEN::Match(tok2, "[;{}] if(var) dealloc ;") || TOKEN::Match(tok2, "[;{}] if(var) use ;")) &&
|
if ((TOKEN::Match(tok2, "[;{}] if(var) dealloc ;") || TOKEN::Match(tok2, "[;{}] if(var) use ;")) &&
|
||||||
!TOKEN::Match(tok2->tokAt(4), "else"))
|
!TOKEN::Match(tok2->tokAt(4), "else"))
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(2));
|
erase(tok2, tok2->tokAt(2));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "if if" => "if"
|
// Reduce "if if" => "if"
|
||||||
if ( TOKEN::Match(tok2, "if if") )
|
if ( TOKEN::Match(tok2, "if if") )
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(2));
|
erase(tok2, tok2->tokAt(2));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "else ;" => ";"
|
// Reduce "else ;" => ";"
|
||||||
if ( TOKEN::Match(tok2->next(), "else ;") )
|
if ( TOKEN::Match(tok2->next(), "else ;") )
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(2));
|
erase(tok2, tok2->tokAt(2));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete if block: "alloc; if return use ;"
|
// Delete if block: "alloc; if return use ;"
|
||||||
if (TOKEN::Match(tok2,"alloc ; if return use ;") && !TOKEN::Match(tok2->tokAt(6),"else"))
|
if (TOKEN::Match(tok2,"alloc ; if return use ;") && !TOKEN::Match(tok2->tokAt(6),"else"))
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(5));
|
erase(tok2, tok2->tokAt(5));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Reduce "if return ; alloc ;" => "alloc ;"
|
// Reduce "if return ; alloc ;" => "alloc ;"
|
||||||
if (TOKEN::Match(tok2, "[;{}] if return ; alloc ;"))
|
if (TOKEN::Match(tok2, "[;{}] if return ; alloc ;"))
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(4));
|
erase(tok2, tok2->tokAt(4));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "[;{}] if alloc ; else return ;" => "[;{}] alloc ;"
|
// "[;{}] if alloc ; else return ;" => "[;{}] alloc ;"
|
||||||
if (TOKEN::Match(tok2,"[;{}] if alloc ; else return ;"))
|
if (TOKEN::Match(tok2,"[;{}] if alloc ; else return ;"))
|
||||||
|
@ -705,55 +705,55 @@ void CheckMemoryLeakClass::simplifycode(TOKEN *tok)
|
||||||
{
|
{
|
||||||
erase(tok2,tok2->tokAt(8));
|
erase(tok2,tok2->tokAt(8));
|
||||||
done = false;
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce "if ; else %var% ;" => "if %var% ;"
|
||||||
|
if ( TOKEN::Match(tok2, "if ; else %var% ;") )
|
||||||
|
{
|
||||||
|
erase( tok2, tok2->tokAt(3) );
|
||||||
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "if ; else %var% ;" => "if %var% ;"
|
// Reduce "if ; else return use ;" => "if return use ;"
|
||||||
if ( TOKEN::Match(tok2, "if ; else %var% ;") )
|
if ( TOKEN::Match(tok2, "if ; else %var% ;") )
|
||||||
{
|
{
|
||||||
erase( tok2, tok2->tokAt(3) );
|
erase( tok2, tok2->tokAt(3) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce "if ; else return use ;" => "if return use ;"
|
|
||||||
if ( TOKEN::Match(tok2, "if ; else %var% ;") )
|
|
||||||
{
|
|
||||||
erase( tok2, tok2->tokAt(3) );
|
|
||||||
done = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce "do { alloc ; } " => "alloc ;"
|
|
||||||
if ( TOKEN::Match(tok2->next(), "do { alloc ; }") )
|
|
||||||
{
|
|
||||||
erase(tok2, tok2->tokAt(3));
|
|
||||||
erase(tok2->next()->next(), tok2->tokAt(4));
|
|
||||||
done = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce "loop if break ; => ";"
|
|
||||||
if ( TOKEN::Match( tok2->next(), "loop %var%" ) &&
|
|
||||||
tok2->tokAt(2)->str().find("if") == 0 &&
|
|
||||||
(TOKEN::Match( tok2->tokAt(3), "break ; ") || TOKEN::Match( tok2->tokAt(3), "continue ;")) &&
|
|
||||||
!TOKEN::Match(tok2->tokAt(5),"else") )
|
|
||||||
{
|
|
||||||
erase( tok2, tok2->tokAt(4) );
|
|
||||||
done = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce "if(true) X ;" => "X ;"
|
|
||||||
if (TOKEN::Match(tok2->next(), "if(true) %var% ;") && !TOKEN::Match(tok2->tokAt(4),"else"))
|
|
||||||
{
|
|
||||||
erase( tok2, tok2->tokAt(2) );
|
|
||||||
done = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduce "do { alloc ; } " => "alloc ;"
|
||||||
|
if ( TOKEN::Match(tok2->next(), "do { alloc ; }") )
|
||||||
|
{
|
||||||
|
erase(tok2, tok2->tokAt(3));
|
||||||
|
erase(tok2->next()->next(), tok2->tokAt(4));
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce "loop if break ; => ";"
|
||||||
|
if ( TOKEN::Match( tok2->next(), "loop %var%" ) &&
|
||||||
|
tok2->tokAt(2)->str().find("if") == 0 &&
|
||||||
|
(TOKEN::Match( tok2->tokAt(3), "break ; ") || TOKEN::Match( tok2->tokAt(3), "continue ;")) &&
|
||||||
|
!TOKEN::Match(tok2->tokAt(5),"else") )
|
||||||
|
{
|
||||||
|
erase( tok2, tok2->tokAt(4) );
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce "if(true) X ;" => "X ;"
|
||||||
|
if (TOKEN::Match(tok2->next(), "if(true) %var% ;") && !TOKEN::Match(tok2->tokAt(4),"else"))
|
||||||
|
{
|
||||||
|
erase( tok2, tok2->tokAt(2) );
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Replace "loop { X ; break ; }" with "X ;"
|
// Replace "loop { X ; break ; }" with "X ;"
|
||||||
if ( TOKEN::Match(tok2->next(), "loop { %var% ; break ; }") )
|
if ( TOKEN::Match(tok2->next(), "loop { %var% ; break ; }") )
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(3));
|
erase(tok2, tok2->tokAt(3));
|
||||||
erase(tok2->next()->next(), tok2->tokAt(6));
|
erase(tok2->next()->next(), tok2->tokAt(6));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace "loop ;" with ";"
|
// Replace "loop ;" with ";"
|
||||||
if ( TOKEN::Match(tok2->next(), "loop ;") )
|
if ( TOKEN::Match(tok2->next(), "loop ;") )
|
||||||
{
|
{
|
||||||
|
@ -780,64 +780,64 @@ void CheckMemoryLeakClass::simplifycode(TOKEN *tok)
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(4));
|
erase(tok2, tok2->tokAt(4));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete if block: "alloc; if return use ;"
|
// Delete if block: "alloc; if return use ;"
|
||||||
if (TOKEN::Match(tok2,"alloc ; if return use ;") && !TOKEN::Match(tok2->tokAt(6),"else"))
|
if (TOKEN::Match(tok2,"alloc ; if return use ;") && !TOKEN::Match(tok2->tokAt(6),"else"))
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(5));
|
erase(tok2, tok2->tokAt(5));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "if return ; if return ;" => "if return ;"
|
// Reduce "if return ; if return ;" => "if return ;"
|
||||||
if ( TOKEN::Match(tok2->next(), "if return ; if return ;") )
|
if ( TOKEN::Match(tok2->next(), "if return ; if return ;") )
|
||||||
{
|
{
|
||||||
erase( tok2, tok2->tokAt(4) );
|
erase( tok2, tok2->tokAt(4) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "[;{}] return ; %var%" => "[;{}] return ;"
|
// Reduce "[;{}] return ; %var%" => "[;{}] return ;"
|
||||||
if ( TOKEN::Match(tok2, "[;{}] return ; %var%") )
|
if ( TOKEN::Match(tok2, "[;{}] return ; %var%") )
|
||||||
{
|
{
|
||||||
erase( tok2->next()->next(), tok2->tokAt(4) );
|
erase( tok2->next()->next(), tok2->tokAt(4) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "[;{}] return use ; %var%" => "[;{}] return use ;"
|
// Reduce "[;{}] return use ; %var%" => "[;{}] return use ;"
|
||||||
if ( TOKEN::Match(tok2, "[;{}] return use ; %var%") )
|
if ( TOKEN::Match(tok2, "[;{}] return use ; %var%") )
|
||||||
{
|
{
|
||||||
erase( tok2->next()->next()->next(), tok2->tokAt(5) );
|
erase( tok2->next()->next()->next(), tok2->tokAt(5) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "if(var) return use ;" => "return use ;"
|
// Reduce "if(var) return use ;" => "return use ;"
|
||||||
if ( TOKEN::Match(tok2->next(), "if(var) return use ;") && !TOKEN::Match(tok2->tokAt(5),"else"))
|
if ( TOKEN::Match(tok2->next(), "if(var) return use ;") && !TOKEN::Match(tok2->tokAt(5),"else"))
|
||||||
{
|
{
|
||||||
erase( tok2, tok2->tokAt(2) );
|
erase( tok2, tok2->tokAt(2) );
|
||||||
done = false;
|
done = false;
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce "if(var) use ;" => "use ;"
|
|
||||||
if ( TOKEN::Match(tok2->next(), "if(var) use ;") && !TOKEN::Match(tok2->tokAt(4),"else"))
|
|
||||||
{
|
|
||||||
erase( tok2, tok2->tokAt(2) );
|
|
||||||
done = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce "[;{}] alloc ; dealloc ;" => "[;{}]"
|
|
||||||
if ( TOKEN::Match(tok2, "[;{}] alloc ; dealloc ;") )
|
|
||||||
{
|
|
||||||
erase( tok2, tok2->tokAt(5) );
|
|
||||||
done = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce "if* alloc ; dealloc ;" => ";"
|
|
||||||
if ( TOKEN::Match(tok2->tokAt(2), "alloc ; dealloc ;") &&
|
|
||||||
tok2->next()->str().find("if") == 0 )
|
|
||||||
{
|
|
||||||
erase( tok2, tok2->tokAt(5) );
|
|
||||||
done = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduce "if(var) use ;" => "use ;"
|
||||||
|
if ( TOKEN::Match(tok2->next(), "if(var) use ;") && !TOKEN::Match(tok2->tokAt(4),"else"))
|
||||||
|
{
|
||||||
|
erase( tok2, tok2->tokAt(2) );
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce "[;{}] alloc ; dealloc ;" => "[;{}]"
|
||||||
|
if ( TOKEN::Match(tok2, "[;{}] alloc ; dealloc ;") )
|
||||||
|
{
|
||||||
|
erase( tok2, tok2->tokAt(5) );
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce "if* alloc ; dealloc ;" => ";"
|
||||||
|
if ( TOKEN::Match(tok2->tokAt(2), "alloc ; dealloc ;") &&
|
||||||
|
tok2->next()->str().find("if") == 0 )
|
||||||
|
{
|
||||||
|
erase( tok2, tok2->tokAt(5) );
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Delete second use in "use ; use ;"
|
// Delete second use in "use ; use ;"
|
||||||
while (TOKEN::Match(tok2, "[;{}] use ; use ;"))
|
while (TOKEN::Match(tok2, "[;{}] use ; use ;"))
|
||||||
|
@ -851,7 +851,7 @@ void CheckMemoryLeakClass::simplifycode(TOKEN *tok)
|
||||||
{
|
{
|
||||||
erase(tok2, tok2->tokAt(3));
|
erase(tok2, tok2->tokAt(3));
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete first use in "use ; return use ;"
|
// Delete first use in "use ; return use ;"
|
||||||
if (TOKEN::Match(tok2, "[;{}] use ; return use ;"))
|
if (TOKEN::Match(tok2, "[;{}] use ; return use ;"))
|
||||||
|
@ -981,8 +981,8 @@ void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const
|
||||||
|
|
||||||
else if ( (result = TOKEN::findmatch(tok, "alloc ; if break|continue|return ;")) != NULL )
|
else if ( (result = TOKEN::findmatch(tok, "alloc ; if break|continue|return ;")) != NULL )
|
||||||
{
|
{
|
||||||
// MemoryLeak(Tokenizer::gettok(TOKEN::findmatch(tok, "alloc ; if continue ;"), 3), varname);
|
// MemoryLeak(Tokenizer::gettok(TOKEN::findmatch(tok, "alloc ; if continue ;"), 3), varname);
|
||||||
MemoryLeak(result->tokAt(3), varname);
|
MemoryLeak(result->tokAt(3), varname);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( _settings._showAll && (result = TOKEN::findmatch(tok, "alloc ; ifv break|continue|return ;")) != NULL )
|
else if ( _settings._showAll && (result = TOKEN::findmatch(tok, "alloc ; ifv break|continue|return ;")) != NULL )
|
||||||
|
@ -1004,36 +1004,36 @@ void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const
|
||||||
last = last->next();
|
last = last->next();
|
||||||
MemoryLeak(last, varname);
|
MemoryLeak(last, varname);
|
||||||
}
|
}
|
||||||
|
|
||||||
// detect cases that "simplifycode" don't handle well..
|
// detect cases that "simplifycode" don't handle well..
|
||||||
else if ( _settings._debug )
|
else if ( _settings._debug )
|
||||||
{
|
{
|
||||||
TOKEN *first = tok;
|
TOKEN *first = tok;
|
||||||
while ( first && first->str() == ";" )
|
while ( first && first->str() == ";" )
|
||||||
first = first->next();
|
first = first->next();
|
||||||
|
|
||||||
bool noerr = false;
|
bool noerr = false;
|
||||||
noerr |= TOKEN::Match( first, "alloc ; }" );
|
noerr |= TOKEN::Match( first, "alloc ; }" );
|
||||||
noerr |= TOKEN::Match( first, "alloc ; dealloc ; }" );
|
noerr |= TOKEN::Match( first, "alloc ; dealloc ; }" );
|
||||||
noerr |= TOKEN::Match( first, "alloc ; return use ; }" );
|
noerr |= TOKEN::Match( first, "alloc ; return use ; }" );
|
||||||
noerr |= TOKEN::Match( first, "alloc ; use ; }" );
|
noerr |= TOKEN::Match( first, "alloc ; use ; }" );
|
||||||
noerr |= TOKEN::Match( first, "alloc ; use ; return ; }" );
|
noerr |= TOKEN::Match( first, "alloc ; use ; return ; }" );
|
||||||
noerr |= TOKEN::Match( first, "if alloc ; dealloc ; }" );
|
noerr |= TOKEN::Match( first, "if alloc ; dealloc ; }" );
|
||||||
noerr |= TOKEN::Match( first, "if alloc ; return use ; }" );
|
noerr |= TOKEN::Match( first, "if alloc ; return use ; }" );
|
||||||
noerr |= TOKEN::Match( first, "if alloc ; use ; }" );
|
noerr |= TOKEN::Match( first, "if alloc ; use ; }" );
|
||||||
noerr |= TOKEN::Match( first, "alloc ; ifv return ; dealloc ; }" );
|
noerr |= TOKEN::Match( first, "alloc ; ifv return ; dealloc ; }" );
|
||||||
noerr |= TOKEN::Match( first, "alloc ; if return ; dealloc; }" );
|
noerr |= TOKEN::Match( first, "alloc ; if return ; dealloc; }" );
|
||||||
|
|
||||||
// Unhandled case..
|
// Unhandled case..
|
||||||
if ( ! noerr )
|
if ( ! noerr )
|
||||||
{
|
{
|
||||||
std::cout << "Token listing..\n ";
|
std::cout << "Token listing..\n ";
|
||||||
for ( const TOKEN *tok2 = tok; tok2; tok2 = tok2->next() )
|
for ( const TOKEN *tok2 = tok; tok2; tok2 = tok2->next() )
|
||||||
std::cout << " " << tok2->str();
|
std::cout << " " << tok2->str();
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Tokenizer::deleteTokens(tok);
|
Tokenizer::deleteTokens(tok);
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -1261,7 +1261,7 @@ void CheckMemoryLeakClass::CheckMemoryLeak()
|
||||||
// Check for memory leaks inside functions..
|
// Check for memory leaks inside functions..
|
||||||
CheckMemoryLeak_InFunction();
|
CheckMemoryLeak_InFunction();
|
||||||
|
|
||||||
// Check that all class members are deallocated..
|
// Check that all class members are deallocated..
|
||||||
if ( _settings._showAll )
|
if ( _settings._showAll )
|
||||||
CheckMemoryLeak_ClassMembers();
|
CheckMemoryLeak_ClassMembers();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,31 +61,31 @@ private:
|
||||||
void CheckMemoryLeak_ClassMembers();
|
void CheckMemoryLeak_ClassMembers();
|
||||||
void CheckMemoryLeak_InFunction();
|
void CheckMemoryLeak_InFunction();
|
||||||
void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] );
|
void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplify code e.g. by replacing empty "{ }" with ";"
|
* Simplify code e.g. by replacing empty "{ }" with ";"
|
||||||
* @param tok first token. The tokens list can be modified.
|
* @param tok first token. The tokens list can be modified.
|
||||||
*/
|
*/
|
||||||
void simplifycode(TOKEN *tok);
|
void simplifycode(TOKEN *tok);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete tokens between begin and end. E.g. if begin = 1
|
* Delete tokens between begin and end. E.g. if begin = 1
|
||||||
* and end = 5, tokens 2,3 and 4 would be erased.
|
* and end = 5, tokens 2,3 and 4 would be erased.
|
||||||
*
|
*
|
||||||
* @param begin Tokens after this will be erased.
|
* @param begin Tokens after this will be erased.
|
||||||
* @param end Tokens before this will be erased.
|
* @param end Tokens before this will be erased.
|
||||||
*/
|
*/
|
||||||
void erase(TOKEN *begin, const TOKEN *end);
|
void erase(TOKEN *begin, const TOKEN *end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract a new tokens list that is easier to parse than the "tokens"
|
* Extract a new tokens list that is easier to parse than the "tokens"
|
||||||
* @param tok start parse token
|
* @param tok start parse token
|
||||||
* @param callstack callstack
|
* @param callstack callstack
|
||||||
* @param varname name of variable
|
* @param varname name of variable
|
||||||
* @param alloctype
|
* @param alloctype
|
||||||
* @param dealloctype
|
* @param dealloctype
|
||||||
* @return Newly allocated token array. Caller needs to release reserved
|
* @return Newly allocated token array. Caller needs to release reserved
|
||||||
* memory by calling Tokenizer::deleteTokens(returnValue);
|
* memory by calling Tokenizer::deleteTokens(returnValue);
|
||||||
*/
|
*/
|
||||||
TOKEN *getcode(const TOKEN *tok, std::list<const TOKEN *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype);
|
TOKEN *getcode(const TOKEN *tok, std::list<const TOKEN *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype);
|
||||||
bool notvar(const TOKEN *tok, const char *varnames[]);
|
bool notvar(const TOKEN *tok, const char *varnames[]);
|
||||||
|
@ -95,7 +95,7 @@ private:
|
||||||
const char * call_func( const TOKEN *tok, std::list<const TOKEN *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype );
|
const char * call_func( const TOKEN *tok, std::list<const TOKEN *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype );
|
||||||
AllocType GetDeallocationType( const TOKEN *tok, const char *varnames[]);
|
AllocType GetDeallocationType( const TOKEN *tok, const char *varnames[]);
|
||||||
AllocType GetAllocationType( const TOKEN *tok2 );
|
AllocType GetAllocationType( const TOKEN *tok2 );
|
||||||
AllocType GetReallocationType( const TOKEN *tok2 );
|
AllocType GetReallocationType( const TOKEN *tok2 );
|
||||||
bool isclass( const TOKEN *typestr );
|
bool isclass( const TOKEN *typestr );
|
||||||
|
|
||||||
const Tokenizer *_tokenizer;
|
const Tokenizer *_tokenizer;
|
||||||
|
|
316
CheckOther.cpp
316
CheckOther.cpp
|
@ -283,13 +283,13 @@ void CheckOther::WarningIf()
|
||||||
// Check that there is a condition..
|
// Check that there is a condition..
|
||||||
const char *p[6] = {"==","<=",">=","!=","<",">"};
|
const char *p[6] = {"==","<=",">=","!=","<",">"};
|
||||||
bool iscond = false;
|
bool iscond = false;
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
if (strcmp(cond, p[i]) == 0)
|
if (strcmp(cond, p[i]) == 0)
|
||||||
{
|
{
|
||||||
iscond = true;
|
iscond = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!iscond)
|
if (!iscond)
|
||||||
break;
|
break;
|
||||||
|
@ -783,157 +783,157 @@ void CheckOther::CheckIncompleteStatement()
|
||||||
_errorLogger->reportErr(errmsg.str());
|
_errorLogger->reportErr(errmsg.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Unreachable code below a 'return'
|
// Unreachable code below a 'return'
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void CheckOther::unreachableCode()
|
void CheckOther::unreachableCode()
|
||||||
{
|
{
|
||||||
const TOKEN *tok = TOKEN::findmatch( _tokenizer->tokens(), "[;{}] return" );
|
const TOKEN *tok = TOKEN::findmatch( _tokenizer->tokens(), "[;{}] return" );
|
||||||
while ( tok )
|
while ( tok )
|
||||||
{
|
{
|
||||||
// Goto the 'return' token
|
// Goto the 'return' token
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
|
||||||
// Locate the end of the 'return' statement
|
// Locate the end of the 'return' statement
|
||||||
while ( tok && ! TOKEN::Match(tok, ";") )
|
while ( tok && ! TOKEN::Match(tok, ";") )
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
while ( tok && TOKEN::Match(tok->next(), ";") )
|
while ( tok && TOKEN::Match(tok->next(), ";") )
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
|
||||||
// If there is a statement below the return it is unreachable
|
// If there is a statement below the return it is unreachable
|
||||||
if (!TOKEN::Match(tok, "; case|default|}|#") && !TOKEN::Match(tok, "; %var% :"))
|
if (!TOKEN::Match(tok, "; case|default|}|#") && !TOKEN::Match(tok, "; %var% :"))
|
||||||
{
|
{
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << _tokenizer->fileLine(tok->next()) << ": Unreachable code below a 'return'";
|
errmsg << _tokenizer->fileLine(tok->next()) << ": Unreachable code below a 'return'";
|
||||||
_errorLogger->reportErr(errmsg.str());
|
_errorLogger->reportErr(errmsg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the next 'return' statement
|
// Find the next 'return' statement
|
||||||
tok = TOKEN::findmatch( tok, "[;{}] return" );
|
tok = TOKEN::findmatch( tok, "[;{}] return" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Usage of function variables
|
// Usage of function variables
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static bool isOp(const TOKEN *tok)
|
static bool isOp(const TOKEN *tok)
|
||||||
{
|
{
|
||||||
return bool(tok &&
|
return bool(tok &&
|
||||||
(tok->str() == "&&" ||
|
(tok->str() == "&&" ||
|
||||||
tok->str() == "||" ||
|
tok->str() == "||" ||
|
||||||
tok->str() == "==" ||
|
tok->str() == "==" ||
|
||||||
tok->str() == "!=" ||
|
tok->str() == "!=" ||
|
||||||
tok->str() == "<" ||
|
tok->str() == "<" ||
|
||||||
tok->str() == "<=" ||
|
tok->str() == "<=" ||
|
||||||
tok->str() == ">" ||
|
tok->str() == ">" ||
|
||||||
tok->str() == ">=" ||
|
tok->str() == ">=" ||
|
||||||
tok->str() == "<<" ||
|
tok->str() == "<<" ||
|
||||||
TOKEN::Match(tok, "[+-*/&|,]")));
|
TOKEN::Match(tok, "[+-*/&|,]")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckOther::functionVariableUsage()
|
void CheckOther::functionVariableUsage()
|
||||||
{
|
{
|
||||||
// Parse all executing scopes..
|
// Parse all executing scopes..
|
||||||
const TOKEN *tok1 = TOKEN::findmatch( _tokenizer->tokens(), ") const| {" );
|
const TOKEN *tok1 = TOKEN::findmatch( _tokenizer->tokens(), ") const| {" );
|
||||||
while ( tok1 )
|
while ( tok1 )
|
||||||
{
|
{
|
||||||
// Varname, usage {1=declare, 2=read, 4=write}
|
// Varname, usage {1=declare, 2=read, 4=write}
|
||||||
std::map<std::string, unsigned int> varUsage;
|
std::map<std::string, unsigned int> varUsage;
|
||||||
static const unsigned int USAGE_DECLARE = 1;
|
static const unsigned int USAGE_DECLARE = 1;
|
||||||
static const unsigned int USAGE_READ = 2;
|
static const unsigned int USAGE_READ = 2;
|
||||||
static const unsigned int USAGE_WRITE = 4;
|
static const unsigned int USAGE_WRITE = 4;
|
||||||
|
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
for ( const TOKEN *tok = tok1; tok; tok = tok->next() )
|
for ( const TOKEN *tok = tok1; tok; tok = tok->next() )
|
||||||
{
|
{
|
||||||
if ( tok->str() == "{" )
|
if ( tok->str() == "{" )
|
||||||
++indentlevel;
|
++indentlevel;
|
||||||
else if ( tok->str() == "}" )
|
else if ( tok->str() == "}" )
|
||||||
{
|
{
|
||||||
--indentlevel;
|
--indentlevel;
|
||||||
if ( indentlevel <= 0 )
|
if ( indentlevel <= 0 )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( TOKEN::Match(tok, "[;{}] bool|char|short|int|long|float|double %var% ;|=") )
|
if ( TOKEN::Match(tok, "[;{}] bool|char|short|int|long|float|double %var% ;|=") )
|
||||||
varUsage[ tok->strAt(2) ] = USAGE_DECLARE;
|
varUsage[ tok->strAt(2) ] = USAGE_DECLARE;
|
||||||
|
|
||||||
if ( TOKEN::Match(tok, "[;{}] bool|char|short|int|long|float|double * %var% ;|=") )
|
if ( TOKEN::Match(tok, "[;{}] bool|char|short|int|long|float|double * %var% ;|=") )
|
||||||
varUsage[ tok->strAt(3) ] = USAGE_DECLARE;
|
varUsage[ tok->strAt(3) ] = USAGE_DECLARE;
|
||||||
|
|
||||||
if ( TOKEN::Match(tok, "delete|return %var%") )
|
if ( TOKEN::Match(tok, "delete|return %var%") )
|
||||||
varUsage[ tok->strAt(1) ] |= USAGE_READ;
|
varUsage[ tok->strAt(1) ] |= USAGE_READ;
|
||||||
|
|
||||||
if ( TOKEN::Match(tok, "%var% =") )
|
if ( TOKEN::Match(tok, "%var% =") )
|
||||||
varUsage[ tok->str() ] |= USAGE_WRITE;
|
varUsage[ tok->str() ] |= USAGE_WRITE;
|
||||||
|
|
||||||
if ( TOKEN::Match(tok, "else %var% =") )
|
if ( TOKEN::Match(tok, "else %var% =") )
|
||||||
varUsage[ tok->strAt(1) ] |= USAGE_WRITE;
|
varUsage[ tok->strAt(1) ] |= USAGE_WRITE;
|
||||||
|
|
||||||
if ( TOKEN::Match(tok, ">>|& %var%") )
|
if ( TOKEN::Match(tok, ">>|& %var%") )
|
||||||
varUsage[ tok->strAt(1) ] |= USAGE_WRITE;
|
varUsage[ tok->strAt(1) ] |= USAGE_WRITE;
|
||||||
|
|
||||||
if ((TOKEN::Match(tok,"[(=&!]") || isOp(tok)) && TOKEN::Match(tok->next(), "%var%"))
|
if ((TOKEN::Match(tok,"[(=&!]") || isOp(tok)) && TOKEN::Match(tok->next(), "%var%"))
|
||||||
varUsage[ tok->strAt(1) ] |= USAGE_READ;
|
varUsage[ tok->strAt(1) ] |= USAGE_READ;
|
||||||
|
|
||||||
if (TOKEN::Match(tok, "%var%") && (tok->next()->str()==")" || isOp(tok->next())))
|
if (TOKEN::Match(tok, "%var%") && (tok->next()->str()==")" || isOp(tok->next())))
|
||||||
varUsage[ tok->str() ] |= USAGE_READ;
|
varUsage[ tok->str() ] |= USAGE_READ;
|
||||||
|
|
||||||
if ( TOKEN::Match(tok, "[(,] %var% [,)]") )
|
if ( TOKEN::Match(tok, "[(,] %var% [,)]") )
|
||||||
varUsage[ tok->strAt(1) ] |= USAGE_WRITE;
|
varUsage[ tok->strAt(1) ] |= USAGE_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check usage of all variables in the current scope..
|
// Check usage of all variables in the current scope..
|
||||||
for ( std::map<std::string, unsigned int>::const_iterator it = varUsage.begin(); it != varUsage.end(); ++it )
|
for ( std::map<std::string, unsigned int>::const_iterator it = varUsage.begin(); it != varUsage.end(); ++it )
|
||||||
{
|
{
|
||||||
std::string varname = it->first;
|
std::string varname = it->first;
|
||||||
unsigned int usage = it->second;
|
unsigned int usage = it->second;
|
||||||
|
|
||||||
if (!isalpha(varname[0]))
|
if (!isalpha(varname[0]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( ! ( usage & USAGE_DECLARE ) )
|
if ( ! ( usage & USAGE_DECLARE ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( usage == USAGE_DECLARE )
|
if ( usage == USAGE_DECLARE )
|
||||||
{
|
{
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << _tokenizer->fileLine(tok1->next()) << ": Unused variable '" << varname << "'";
|
errmsg << _tokenizer->fileLine(tok1->next()) << ": Unused variable '" << varname << "'";
|
||||||
_errorLogger->reportErr(errmsg.str());
|
_errorLogger->reportErr(errmsg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( ! (usage & USAGE_READ) )
|
else if ( ! (usage & USAGE_READ) )
|
||||||
{
|
{
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << _tokenizer->fileLine(tok1->next()) << ": Variable '" << varname << "' is assigned a value that is never used";
|
errmsg << _tokenizer->fileLine(tok1->next()) << ": Variable '" << varname << "' is assigned a value that is never used";
|
||||||
_errorLogger->reportErr(errmsg.str());
|
_errorLogger->reportErr(errmsg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( ! (usage & USAGE_WRITE) )
|
else if ( ! (usage & USAGE_WRITE) )
|
||||||
{
|
{
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
errmsg << _tokenizer->fileLine(tok1->next()) << ": Variable '" << varname << "' is not assigned a value";
|
errmsg << _tokenizer->fileLine(tok1->next()) << ": Variable '" << varname << "' is not assigned a value";
|
||||||
_errorLogger->reportErr(errmsg.str());
|
_errorLogger->reportErr(errmsg.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Goto next executing scope..
|
// Goto next executing scope..
|
||||||
tok1 = TOKEN::findmatch( tok1->next(), ") const| {" );
|
tok1 = TOKEN::findmatch( tok1->next(), ") const| {" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
CheckOther.h
12
CheckOther.h
|
@ -69,12 +69,12 @@ public:
|
||||||
void CheckCharVariable();
|
void CheckCharVariable();
|
||||||
|
|
||||||
// Incomplete statement. A statement that only contains a constant or variable
|
// Incomplete statement. A statement that only contains a constant or variable
|
||||||
void CheckIncompleteStatement();
|
void CheckIncompleteStatement();
|
||||||
|
|
||||||
/** Unreachable code below a 'return' */
|
/** Unreachable code below a 'return' */
|
||||||
void unreachableCode();
|
void unreachableCode();
|
||||||
|
|
||||||
/** Unused function variables */
|
/** Unused function variables */
|
||||||
void functionVariableUsage();
|
void functionVariableUsage();
|
||||||
private:
|
private:
|
||||||
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
|
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
|
||||||
|
|
|
@ -38,7 +38,7 @@ bool FileLister::AcceptFile( const std::string &filename )
|
||||||
|
|
||||||
std::string extension = filename.substr( dotLocation );
|
std::string extension = filename.substr( dotLocation );
|
||||||
|
|
||||||
if( extension == ".cpp" ||
|
if( extension == ".cpp" ||
|
||||||
extension == ".cxx" ||
|
extension == ".cxx" ||
|
||||||
extension == ".cc" ||
|
extension == ".cc" ||
|
||||||
extension == ".c" )
|
extension == ".c" )
|
||||||
|
@ -127,7 +127,7 @@ void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const s
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFiles( filenames, path, "*.cpp" );
|
AddFiles( filenames, path, "*.cpp" );
|
||||||
AddFiles( filenames, path, "*.cxx" );
|
AddFiles( filenames, path, "*.cxx" );
|
||||||
AddFiles( filenames, path, "*.cc" );
|
AddFiles( filenames, path, "*.cc" );
|
||||||
AddFiles( filenames, path, "*.c" );
|
AddFiles( filenames, path, "*.c" );
|
||||||
|
|
24
FileLister.h
24
FileLister.h
|
@ -38,18 +38,18 @@
|
||||||
class FileLister
|
class FileLister
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive );
|
static void RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool AcceptFile( const std::string &filename );
|
static bool AcceptFile( const std::string &filename );
|
||||||
|
|
||||||
#ifdef __BORLANDC__
|
#ifdef __BORLANDC__
|
||||||
static void AddFiles( std::vector<std::string> &filenames, const std::string &path, const std::string &pattern );
|
static void AddFiles( std::vector<std::string> &filenames, const std::string &path, const std::string &pattern );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
static void AddFiles( std::vector<std::string> &filenames, const std::string &path, const std::string &pattern );
|
static void AddFiles( std::vector<std::string> &filenames, const std::string &path, const std::string &pattern );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
720
cppcheck.cpp
720
cppcheck.cpp
|
@ -1,360 +1,360 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
#include "cppcheck.h"
|
#include "cppcheck.h"
|
||||||
|
|
||||||
#include "preprocessor.h" // preprocessor.
|
#include "preprocessor.h" // preprocessor.
|
||||||
#include "tokenize.h" // <- Tokenizer
|
#include "tokenize.h" // <- Tokenizer
|
||||||
|
|
||||||
#include "CheckMemoryLeak.h"
|
#include "CheckMemoryLeak.h"
|
||||||
#include "CheckBufferOverrun.h"
|
#include "CheckBufferOverrun.h"
|
||||||
#include "CheckClass.h"
|
#include "CheckClass.h"
|
||||||
#include "CheckHeaders.h"
|
#include "CheckHeaders.h"
|
||||||
#include "CheckOther.h"
|
#include "CheckOther.h"
|
||||||
#include "CheckFunctionUsage.h"
|
#include "CheckFunctionUsage.h"
|
||||||
#include "FileLister.h"
|
#include "FileLister.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CppCheck::CppCheck( ErrorLogger &errorLogger ) : _checkFunctionUsage( this )
|
CppCheck::CppCheck( ErrorLogger &errorLogger ) : _checkFunctionUsage( this )
|
||||||
{
|
{
|
||||||
_errorLogger = &errorLogger;
|
_errorLogger = &errorLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
CppCheck::~CppCheck()
|
CppCheck::~CppCheck()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheck::settings( const Settings &settings )
|
void CppCheck::settings( const Settings &settings )
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheck::addFile( const std::string &path )
|
void CppCheck::addFile( const std::string &path )
|
||||||
{
|
{
|
||||||
_filenames.push_back( path );
|
_filenames.push_back( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheck::addFile( const std::string &path, const std::string &content )
|
void CppCheck::addFile( const std::string &path, const std::string &content )
|
||||||
{
|
{
|
||||||
_filenames.push_back( path );
|
_filenames.push_back( path );
|
||||||
_fileContents[ path ] = content;
|
_fileContents[ path ] = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CppCheck::parseFromArgs( int argc, const char* const argv[] )
|
std::string CppCheck::parseFromArgs( int argc, const char* const argv[] )
|
||||||
{
|
{
|
||||||
std::vector<std::string> pathnames;
|
std::vector<std::string> pathnames;
|
||||||
bool Recursive = false;
|
bool Recursive = false;
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
// Flag used for various purposes during debugging
|
// Flag used for various purposes during debugging
|
||||||
if (strcmp(argv[i],"--debug") == 0)
|
if (strcmp(argv[i],"--debug") == 0)
|
||||||
_settings._debug = true;
|
_settings._debug = true;
|
||||||
|
|
||||||
// Show all messages
|
// Show all messages
|
||||||
else if (strcmp(argv[i],"--all") == 0)
|
else if (strcmp(argv[i],"--all") == 0)
|
||||||
_settings._showAll = true;
|
_settings._showAll = true;
|
||||||
|
|
||||||
// Only print something when there are errors
|
// Only print something when there are errors
|
||||||
else if (strcmp(argv[i],"--errorsonly")==0)
|
else if (strcmp(argv[i],"--errorsonly")==0)
|
||||||
_settings._errorsOnly = true;
|
_settings._errorsOnly = true;
|
||||||
|
|
||||||
// Checking coding style
|
// Checking coding style
|
||||||
else if (strcmp(argv[i],"--style")==0)
|
else if (strcmp(argv[i],"--style")==0)
|
||||||
_settings._checkCodingStyle = true;
|
_settings._checkCodingStyle = true;
|
||||||
|
|
||||||
// Recursively check source files
|
// Recursively check source files
|
||||||
else if (strcmp(argv[i],"--recursive")==0)
|
else if (strcmp(argv[i],"--recursive")==0)
|
||||||
Recursive = true;
|
Recursive = true;
|
||||||
|
|
||||||
// Verbose error messages (configuration info)
|
// Verbose error messages (configuration info)
|
||||||
else if (strcmp(argv[i],"--verbose")==0)
|
else if (strcmp(argv[i],"--verbose")==0)
|
||||||
_settings._verbose = true;
|
_settings._verbose = true;
|
||||||
|
|
||||||
else
|
else
|
||||||
pathnames.push_back( argv[i] );
|
pathnames.push_back( argv[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
// --recursive was used
|
// --recursive was used
|
||||||
if ( Recursive )
|
if ( Recursive )
|
||||||
{
|
{
|
||||||
if( pathnames.size() == 0 )
|
if( pathnames.size() == 0 )
|
||||||
{
|
{
|
||||||
// Handle situation: cppcheck --recursive
|
// Handle situation: cppcheck --recursive
|
||||||
FileLister::RecursiveAddFiles( _filenames, "", true );
|
FileLister::RecursiveAddFiles( _filenames, "", true );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Handle situation: cppcheck --recursive path1 path2
|
// Handle situation: cppcheck --recursive path1 path2
|
||||||
|
|
||||||
// Execute RecursiveAddFiles() to each given file parameter
|
// Execute RecursiveAddFiles() to each given file parameter
|
||||||
std::vector<std::string>::const_iterator iter;
|
std::vector<std::string>::const_iterator iter;
|
||||||
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
||||||
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), true );
|
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::vector<std::string>::const_iterator iter;
|
std::vector<std::string>::const_iterator iter;
|
||||||
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
||||||
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), false );
|
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), false );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_filenames.empty())
|
if (_filenames.empty())
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "c++check 1.26\n"
|
oss << "c++check 1.26\n"
|
||||||
"\n"
|
"\n"
|
||||||
"C/C++ code checking\n"
|
"C/C++ code checking\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Syntax:\n"
|
"Syntax:\n"
|
||||||
" cppcheck [--all] [--errorsonly] [--recursive] [--style] [--verbose] [filename1] [filename2]\n"
|
" cppcheck [--all] [--errorsonly] [--recursive] [--style] [--verbose] [filename1] [filename2]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" --all Make the checking more sensitive. More bugs are detected,\n"
|
" --all Make the checking more sensitive. More bugs are detected,\n"
|
||||||
" but there are also more false positives\n"
|
" but there are also more false positives\n"
|
||||||
" --errorsonly Only print error messages\n"
|
" --errorsonly Only print error messages\n"
|
||||||
" --recursive Recursively check all *.cpp, *.cxx, *.cc and *.c files\n"
|
" --recursive Recursively check all *.cpp, *.cxx, *.cc and *.c files\n"
|
||||||
" --style Check coding style\n"
|
" --style Check coding style\n"
|
||||||
" --verbose More detailed error reports\n";
|
" --verbose More detailed error reports\n";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check function usage if "--style" and "--all" was given.
|
// Check function usage if "--style" and "--all" was given.
|
||||||
// There will be false positives for exported library functions
|
// There will be false positives for exported library functions
|
||||||
if ( _settings._showAll && _settings._checkCodingStyle )
|
if ( _settings._showAll && _settings._checkCodingStyle )
|
||||||
_settings._checkFunctionUsage = true;
|
_settings._checkFunctionUsage = true;
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheck::check()
|
void CppCheck::check()
|
||||||
{
|
{
|
||||||
std::sort( _filenames.begin(), _filenames.end() );
|
std::sort( _filenames.begin(), _filenames.end() );
|
||||||
for (unsigned int c = 0; c < _filenames.size(); c++)
|
for (unsigned int c = 0; c < _filenames.size(); c++)
|
||||||
{
|
{
|
||||||
_errout.str("");
|
_errout.str("");
|
||||||
std::string fname = _filenames[c];
|
std::string fname = _filenames[c];
|
||||||
|
|
||||||
// If only errors are printed, print filename after the check
|
// If only errors are printed, print filename after the check
|
||||||
if ( _settings._errorsOnly == false )
|
if ( _settings._errorsOnly == false )
|
||||||
_errorLogger->reportOut( std::string( "Checking " ) + fname + std::string( "..." ) );
|
_errorLogger->reportOut( std::string( "Checking " ) + fname + std::string( "..." ) );
|
||||||
|
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
std::map<std::string, std::string> code;
|
std::map<std::string, std::string> code;
|
||||||
if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() )
|
if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() )
|
||||||
{
|
{
|
||||||
// File content was given as a string
|
// File content was given as a string
|
||||||
std::istringstream iss( _fileContents[ _filenames[c] ] );
|
std::istringstream iss( _fileContents[ _filenames[c] ] );
|
||||||
preprocessor.preprocess(iss, code, fname);
|
preprocessor.preprocess(iss, code, fname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only file name was given, read the content from file
|
// Only file name was given, read the content from file
|
||||||
std::ifstream fin( fname.c_str() );
|
std::ifstream fin( fname.c_str() );
|
||||||
preprocessor.preprocess(fin, code, fname);
|
preprocessor.preprocess(fin, code, fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( std::map<std::string,std::string>::const_iterator it = code.begin(); it != code.end(); ++it )
|
for ( std::map<std::string,std::string>::const_iterator it = code.begin(); it != code.end(); ++it )
|
||||||
{
|
{
|
||||||
cfg = it->first;
|
cfg = it->first;
|
||||||
checkFile(it->second, _filenames[c].c_str());
|
checkFile(it->second, _filenames[c].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _settings._errorsOnly == false && _errout.str().empty() )
|
if ( _settings._errorsOnly == false && _errout.str().empty() )
|
||||||
_errorLogger->reportOut( "No errors found" );
|
_errorLogger->reportOut( "No errors found" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// This generates false positives - especially for libraries
|
// This generates false positives - especially for libraries
|
||||||
_settings._verbose = false;
|
_settings._verbose = false;
|
||||||
if ( _settings._checkFunctionUsage )
|
if ( _settings._checkFunctionUsage )
|
||||||
{
|
{
|
||||||
_errout.str("");
|
_errout.str("");
|
||||||
if( _settings._errorsOnly == false )
|
if( _settings._errorsOnly == false )
|
||||||
_errorLogger->reportOut( "Checking usage of global functions (this may take several minutes).." );
|
_errorLogger->reportOut( "Checking usage of global functions (this may take several minutes).." );
|
||||||
|
|
||||||
_checkFunctionUsage.check();
|
_checkFunctionUsage.check();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// CppCheck - A function that checks a specified file
|
// CppCheck - A function that checks a specified file
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void CppCheck::checkFile(const std::string &code, const char FileName[])
|
void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||||
{
|
{
|
||||||
Tokenizer _tokenizer;
|
Tokenizer _tokenizer;
|
||||||
|
|
||||||
// Tokenize the file
|
// Tokenize the file
|
||||||
{
|
{
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
_tokenizer.tokenize(istr, FileName);
|
_tokenizer.tokenize(istr, FileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
_tokenizer.fillFunctionList();
|
_tokenizer.fillFunctionList();
|
||||||
|
|
||||||
// Check that the memsets are valid.
|
// Check that the memsets are valid.
|
||||||
// The 'memset' function can do dangerous things if used wrong.
|
// The 'memset' function can do dangerous things if used wrong.
|
||||||
// Important: The checking doesn't work on simplified tokens list.
|
// Important: The checking doesn't work on simplified tokens list.
|
||||||
CheckClass checkClass( &_tokenizer, _settings, this );
|
CheckClass checkClass( &_tokenizer, _settings, this );
|
||||||
checkClass.CheckMemset();
|
checkClass.CheckMemset();
|
||||||
|
|
||||||
|
|
||||||
// Check for unsigned divisions where one operand is signed
|
// Check for unsigned divisions where one operand is signed
|
||||||
// Very important to run it before 'SimplifyTokenList'
|
// Very important to run it before 'SimplifyTokenList'
|
||||||
CheckOther checkOther( &_tokenizer, this );
|
CheckOther checkOther( &_tokenizer, this );
|
||||||
if ( _settings._checkCodingStyle )
|
if ( _settings._checkCodingStyle )
|
||||||
checkOther.CheckUnsignedDivision();
|
checkOther.CheckUnsignedDivision();
|
||||||
|
|
||||||
// Give warning when using char variable as array index
|
// Give warning when using char variable as array index
|
||||||
// Doesn't work on simplified token list ('unsigned')
|
// Doesn't work on simplified token list ('unsigned')
|
||||||
if ( _settings._checkCodingStyle )
|
if ( _settings._checkCodingStyle )
|
||||||
checkOther.CheckCharVariable();
|
checkOther.CheckCharVariable();
|
||||||
|
|
||||||
|
|
||||||
// Including header which is not needed (too many false positives)
|
// Including header which is not needed (too many false positives)
|
||||||
// if ( _settings._checkCodingStyle )
|
// if ( _settings._checkCodingStyle )
|
||||||
// {
|
// {
|
||||||
// CheckHeaders checkHeaders( &tokenizer );
|
// CheckHeaders checkHeaders( &tokenizer );
|
||||||
// checkHeaders.WarningIncludeHeader();
|
// checkHeaders.WarningIncludeHeader();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
_tokenizer.simplifyTokenList();
|
_tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
|
|
||||||
if ( _settings._checkFunctionUsage )
|
if ( _settings._checkFunctionUsage )
|
||||||
_checkFunctionUsage.parseTokens(_tokenizer);
|
_checkFunctionUsage.parseTokens(_tokenizer);
|
||||||
|
|
||||||
// Memory leak
|
// Memory leak
|
||||||
CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this );
|
CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this );
|
||||||
checkMemoryLeak.CheckMemoryLeak();
|
checkMemoryLeak.CheckMemoryLeak();
|
||||||
|
|
||||||
// Buffer overruns..
|
// Buffer overruns..
|
||||||
CheckBufferOverrunClass checkBufferOverrun( &_tokenizer, _settings, this );
|
CheckBufferOverrunClass checkBufferOverrun( &_tokenizer, _settings, this );
|
||||||
checkBufferOverrun.CheckBufferOverrun();
|
checkBufferOverrun.CheckBufferOverrun();
|
||||||
|
|
||||||
// Check that all class constructors are ok.
|
// Check that all class constructors are ok.
|
||||||
checkClass.CheckConstructors();
|
checkClass.CheckConstructors();
|
||||||
|
|
||||||
// Check that all base classes have virtual destructors
|
// Check that all base classes have virtual destructors
|
||||||
checkClass.virtualDestructor();
|
checkClass.virtualDestructor();
|
||||||
|
|
||||||
if (_settings._showAll)
|
if (_settings._showAll)
|
||||||
{
|
{
|
||||||
// Check for "if (a=b)"
|
// Check for "if (a=b)"
|
||||||
checkOther.CheckIfAssignment();
|
checkOther.CheckIfAssignment();
|
||||||
|
|
||||||
// Check for case without break
|
// Check for case without break
|
||||||
// Disabled because it generates many false positives
|
// Disabled because it generates many false positives
|
||||||
// CheckCaseWithoutBreak();
|
// CheckCaseWithoutBreak();
|
||||||
|
|
||||||
// Dangerous usage of strtok
|
// Dangerous usage of strtok
|
||||||
// Disabled because it generates false positives
|
// Disabled because it generates false positives
|
||||||
//WarningStrTok();
|
//WarningStrTok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Dangerous functions, such as 'gets' and 'scanf'
|
// Dangerous functions, such as 'gets' and 'scanf'
|
||||||
checkBufferOverrun.WarningDangerousFunctions();
|
checkBufferOverrun.WarningDangerousFunctions();
|
||||||
|
|
||||||
|
|
||||||
// Invalid function usage..
|
// Invalid function usage..
|
||||||
checkOther.InvalidFunctionUsage();
|
checkOther.InvalidFunctionUsage();
|
||||||
|
|
||||||
|
|
||||||
if (_settings._checkCodingStyle)
|
if (_settings._checkCodingStyle)
|
||||||
{
|
{
|
||||||
// Check that all private functions are called.
|
// Check that all private functions are called.
|
||||||
checkClass.CheckUnusedPrivateFunctions();
|
checkClass.CheckUnusedPrivateFunctions();
|
||||||
|
|
||||||
// Warning upon c-style pointer casts
|
// Warning upon c-style pointer casts
|
||||||
const char *ext = strrchr(FileName, '.');
|
const char *ext = strrchr(FileName, '.');
|
||||||
if (ext && strcmp(ext,".cpp")==0)
|
if (ext && strcmp(ext,".cpp")==0)
|
||||||
checkOther.WarningOldStylePointerCast();
|
checkOther.WarningOldStylePointerCast();
|
||||||
|
|
||||||
// Use standard functions instead
|
// Use standard functions instead
|
||||||
checkOther.WarningIsDigit();
|
checkOther.WarningIsDigit();
|
||||||
checkOther.WarningIsAlpha();
|
checkOther.WarningIsAlpha();
|
||||||
|
|
||||||
checkClass.CheckOperatorEq1();
|
checkClass.CheckOperatorEq1();
|
||||||
|
|
||||||
// if (a) delete a;
|
// if (a) delete a;
|
||||||
checkOther.WarningRedundantCode();
|
checkOther.WarningRedundantCode();
|
||||||
|
|
||||||
// if (condition);
|
// if (condition);
|
||||||
checkOther.WarningIf();
|
checkOther.WarningIf();
|
||||||
|
|
||||||
// Variable scope (check if the scope could be limited)
|
// Variable scope (check if the scope could be limited)
|
||||||
//CheckVariableScope();
|
//CheckVariableScope();
|
||||||
|
|
||||||
// Check if a constant function parameter is passed by value
|
// Check if a constant function parameter is passed by value
|
||||||
checkOther.CheckConstantFunctionParameter();
|
checkOther.CheckConstantFunctionParameter();
|
||||||
|
|
||||||
// Unused struct members..
|
// Unused struct members..
|
||||||
checkOther.CheckStructMemberUsage();
|
checkOther.CheckStructMemberUsage();
|
||||||
|
|
||||||
// Check for various types of incomplete statements that could for example
|
// Check for various types of incomplete statements that could for example
|
||||||
// mean that an ';' has been added by accident
|
// mean that an ';' has been added by accident
|
||||||
checkOther.CheckIncompleteStatement();
|
checkOther.CheckIncompleteStatement();
|
||||||
|
|
||||||
// Unreachable code below a 'return' statement
|
// Unreachable code below a 'return' statement
|
||||||
checkOther.unreachableCode();
|
checkOther.unreachableCode();
|
||||||
|
|
||||||
// Usage of local functions
|
// Usage of local functions
|
||||||
checkOther.functionVariableUsage();
|
checkOther.functionVariableUsage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void CppCheck::reportErr( const std::string &errmsg)
|
void CppCheck::reportErr( const std::string &errmsg)
|
||||||
{
|
{
|
||||||
if ( /*OnlyReportUniqueErrors*/ true )
|
if ( /*OnlyReportUniqueErrors*/ true )
|
||||||
{
|
{
|
||||||
if ( std::find( _errorList.begin(), _errorList.end(), errmsg ) != _errorList.end() )
|
if ( std::find( _errorList.begin(), _errorList.end(), errmsg ) != _errorList.end() )
|
||||||
return;
|
return;
|
||||||
_errorList.push_back( errmsg );
|
_errorList.push_back( errmsg );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string errmsg2( errmsg );
|
std::string errmsg2( errmsg );
|
||||||
if ( _settings._verbose )
|
if ( _settings._verbose )
|
||||||
{
|
{
|
||||||
errmsg2 += "\n Defines=\'" + cfg + "\'\n";
|
errmsg2 += "\n Defines=\'" + cfg + "\'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_errorLogger->reportErr( errmsg2 );
|
_errorLogger->reportErr( errmsg2 );
|
||||||
|
|
||||||
_errout << errmsg2 << std::endl;
|
_errout << errmsg2 << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheck::reportOut( const std::string &outmsg)
|
void CppCheck::reportOut( const std::string &outmsg)
|
||||||
{
|
{
|
||||||
// This is currently never called. It is here just to comply with
|
// This is currently never called. It is here just to comply with
|
||||||
// the interface.
|
// the interface.
|
||||||
}
|
}
|
||||||
|
|
252
cppcheck.h
252
cppcheck.h
|
@ -1,126 +1,126 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CPPCHECK_H
|
#ifndef CPPCHECK_H
|
||||||
#define CPPCHECK_H
|
#define CPPCHECK_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "errorlogger.h"
|
#include "errorlogger.h"
|
||||||
#include "CheckFunctionUsage.h"
|
#include "CheckFunctionUsage.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the base class which will use other classes to do
|
* This is the base class which will use other classes to do
|
||||||
* static code analysis for C and C++ code to find possible
|
* static code analysis for C and C++ code to find possible
|
||||||
* errors or places that could be improved.
|
* errors or places that could be improved.
|
||||||
* Usage: See check() for more info.
|
* Usage: See check() for more info.
|
||||||
*/
|
*/
|
||||||
class CppCheck : public ErrorLogger
|
class CppCheck : public ErrorLogger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
CppCheck( ErrorLogger &errorLogger );
|
CppCheck( ErrorLogger &errorLogger );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
virtual ~CppCheck();
|
virtual ~CppCheck();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This starts the actual checking. Note that you must call
|
* This starts the actual checking. Note that you must call
|
||||||
* parseFromArgs() or settings() and addFile() before calling this.
|
* parseFromArgs() or settings() and addFile() before calling this.
|
||||||
*/
|
*/
|
||||||
void check();
|
void check();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust the settings before doing the check. E.g. show only
|
* Adjust the settings before doing the check. E.g. show only
|
||||||
* actual bugs or also coding style issues.
|
* actual bugs or also coding style issues.
|
||||||
*
|
*
|
||||||
* @param settings New settings which will overwrite the old.
|
* @param settings New settings which will overwrite the old.
|
||||||
*/
|
*/
|
||||||
void settings( const Settings &settings );
|
void settings( const Settings &settings );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new file to be checked.
|
* Add new file to be checked.
|
||||||
*
|
*
|
||||||
* @param path Relative or absolute path to the file to be checked,
|
* @param path Relative or absolute path to the file to be checked,
|
||||||
* e.g. "cppcheck.cpp". Note that only source files (.c, .cc or .cpp)
|
* e.g. "cppcheck.cpp". Note that only source files (.c, .cc or .cpp)
|
||||||
* should be added to the list. Include filese are gathered automatically.
|
* should be added to the list. Include filese are gathered automatically.
|
||||||
*/
|
*/
|
||||||
void addFile( const std::string &path );
|
void addFile( const std::string &path );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new unreal file to be checked.
|
* Add new unreal file to be checked.
|
||||||
*
|
*
|
||||||
* @param path File name (used for error reporting).
|
* @param path File name (used for error reporting).
|
||||||
* @param content If the file would be a real file, this should be
|
* @param content If the file would be a real file, this should be
|
||||||
* the content of the file.
|
* the content of the file.
|
||||||
*/
|
*/
|
||||||
void addFile( const std::string &path, const std::string &content );
|
void addFile( const std::string &path, const std::string &content );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse command line args and get settings and file lists
|
* Parse command line args and get settings and file lists
|
||||||
* from there.
|
* from there.
|
||||||
*
|
*
|
||||||
* @param argc argc from main()
|
* @param argc argc from main()
|
||||||
* @param argv argv from main()
|
* @param argv argv from main()
|
||||||
* @return Empty string if parameters were accepted, or
|
* @return Empty string if parameters were accepted, or
|
||||||
* string containing "help" text if no files were found to be
|
* string containing "help" text if no files were found to be
|
||||||
* checked.
|
* checked.
|
||||||
*/
|
*/
|
||||||
std::string parseFromArgs( int argc, const char* const argv[] );
|
std::string parseFromArgs( int argc, const char* const argv[] );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkFile(const std::string &code, const char FileName[]);
|
void checkFile(const std::string &code, const char FileName[]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Errors and warnings are directed here.
|
* Errors and warnings are directed here.
|
||||||
*
|
*
|
||||||
* @param errmsg Errors messages are normally in format
|
* @param errmsg Errors messages are normally in format
|
||||||
* "[filepath:line number] Message", e.g.
|
* "[filepath:line number] Message", e.g.
|
||||||
* "[main.cpp:4] Uninitialized member variable"
|
* "[main.cpp:4] Uninitialized member variable"
|
||||||
*/
|
*/
|
||||||
virtual void reportErr( const std::string &errmsg);
|
virtual void reportErr( const std::string &errmsg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about progress is directed here.
|
* Information about progress is directed here.
|
||||||
*
|
*
|
||||||
* @param outmsg, E.g. "Checking main.cpp..."
|
* @param outmsg, E.g. "Checking main.cpp..."
|
||||||
*/
|
*/
|
||||||
virtual void reportOut( const std::string &outmsg);
|
virtual void reportOut( const std::string &outmsg);
|
||||||
|
|
||||||
std::list<std::string> _errorList;
|
std::list<std::string> _errorList;
|
||||||
std::ostringstream _errout;
|
std::ostringstream _errout;
|
||||||
Settings _settings;
|
Settings _settings;
|
||||||
std::vector<std::string> _filenames;
|
std::vector<std::string> _filenames;
|
||||||
/** Key is file name, and value is the content of the file */
|
/** Key is file name, and value is the content of the file */
|
||||||
std::map<std::string,std::string> _fileContents;
|
std::map<std::string,std::string> _fileContents;
|
||||||
CheckFunctionUsage _checkFunctionUsage;
|
CheckFunctionUsage _checkFunctionUsage;
|
||||||
ErrorLogger *_errorLogger;
|
ErrorLogger *_errorLogger;
|
||||||
|
|
||||||
/** Current configuration */
|
/** Current configuration */
|
||||||
std::string cfg;
|
std::string cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPPCHECK_H
|
#endif // CPPCHECK_H
|
||||||
|
|
|
@ -1,51 +1,51 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cppcheckexecutor.h"
|
#include "cppcheckexecutor.h"
|
||||||
#include "cppcheck.h"
|
#include "cppcheck.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
CppCheckExecutor::CppCheckExecutor()
|
CppCheckExecutor::CppCheckExecutor()
|
||||||
{
|
{
|
||||||
//ctor
|
//ctor
|
||||||
}
|
}
|
||||||
|
|
||||||
CppCheckExecutor::~CppCheckExecutor()
|
CppCheckExecutor::~CppCheckExecutor()
|
||||||
{
|
{
|
||||||
//dtor
|
//dtor
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheckExecutor::check( int argc, const char* const argv[] )
|
void CppCheckExecutor::check( int argc, const char* const argv[] )
|
||||||
{
|
{
|
||||||
CppCheck cppCheck( *this );
|
CppCheck cppCheck( *this );
|
||||||
std::string result = cppCheck.parseFromArgs( argc, argv );
|
std::string result = cppCheck.parseFromArgs( argc, argv );
|
||||||
if( result.length() == 0 )
|
if( result.length() == 0 )
|
||||||
cppCheck.check();
|
cppCheck.check();
|
||||||
else
|
else
|
||||||
std::cout << result;
|
std::cout << result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheckExecutor::reportErr( const std::string &errmsg)
|
void CppCheckExecutor::reportErr( const std::string &errmsg)
|
||||||
{
|
{
|
||||||
std::cerr << errmsg << std::endl;
|
std::cerr << errmsg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheckExecutor::reportOut( const std::string &outmsg)
|
void CppCheckExecutor::reportOut( const std::string &outmsg)
|
||||||
{
|
{
|
||||||
std::cout << outmsg << std::endl;
|
std::cout << outmsg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +1,71 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CPPCHECKEXECUTOR_H
|
#ifndef CPPCHECKEXECUTOR_H
|
||||||
#define CPPCHECKEXECUTOR_H
|
#define CPPCHECKEXECUTOR_H
|
||||||
|
|
||||||
#include "errorlogger.h"
|
#include "errorlogger.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class works as an example of how CppCheck can be used in external
|
* This class works as an example of how CppCheck can be used in external
|
||||||
* programs without very little knowledge of the internal parts of the
|
* programs without very little knowledge of the internal parts of the
|
||||||
* program itself. If you wish to use cppcheck e.g. as a part of IDE,
|
* program itself. If you wish to use cppcheck e.g. as a part of IDE,
|
||||||
* just rewrite this class for your needs and possibly use other methods
|
* just rewrite this class for your needs and possibly use other methods
|
||||||
* from CppCheck class instead the ones used here.
|
* from CppCheck class instead the ones used here.
|
||||||
*/
|
*/
|
||||||
class CppCheckExecutor : public ErrorLogger
|
class CppCheckExecutor : public ErrorLogger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
CppCheckExecutor();
|
CppCheckExecutor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor
|
* Destructor
|
||||||
*/
|
*/
|
||||||
virtual ~CppCheckExecutor();
|
virtual ~CppCheckExecutor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the checking.
|
* Starts the checking.
|
||||||
*
|
*
|
||||||
* @param argc from main()
|
* @param argc from main()
|
||||||
* @param argv from main()
|
* @param argv from main()
|
||||||
*/
|
*/
|
||||||
void check( int argc, const char* const argv[] );
|
void check( int argc, const char* const argv[] );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Errors and warnings are directed here. This should be
|
* Errors and warnings are directed here. This should be
|
||||||
* called by the CppCheck class only.
|
* called by the CppCheck class only.
|
||||||
*
|
*
|
||||||
* @param errmsg Errors messages are normally in format
|
* @param errmsg Errors messages are normally in format
|
||||||
* "[filepath:line number] Message", e.g.
|
* "[filepath:line number] Message", e.g.
|
||||||
* "[main.cpp:4] Uninitialized member variable"
|
* "[main.cpp:4] Uninitialized member variable"
|
||||||
*/
|
*/
|
||||||
virtual void reportErr( const std::string &errmsg);
|
virtual void reportErr( const std::string &errmsg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about progress is directed here. This should be
|
* Information about progress is directed here. This should be
|
||||||
* called by the CppCheck class only.
|
* called by the CppCheck class only.
|
||||||
*
|
*
|
||||||
* @param outmsg, E.g. "Checking main.cpp..."
|
* @param outmsg, E.g. "Checking main.cpp..."
|
||||||
*/
|
*/
|
||||||
virtual void reportOut( const std::string &outmsg);
|
virtual void reportOut( const std::string &outmsg);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPPCHECKEXECUTOR_H
|
#endif // CPPCHECKEXECUTOR_H
|
||||||
|
|
100
errorlogger.h
100
errorlogger.h
|
@ -1,50 +1,50 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ERRORLOGGER_H
|
#ifndef ERRORLOGGER_H
|
||||||
#define ERRORLOGGER_H
|
#define ERRORLOGGER_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an interface, which the class responsible of error logging
|
* This is an interface, which the class responsible of error logging
|
||||||
* should implement.
|
* should implement.
|
||||||
*/
|
*/
|
||||||
class ErrorLogger
|
class ErrorLogger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ErrorLogger() {}
|
virtual ~ErrorLogger() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Errors and warnings are directed here.
|
* Errors and warnings are directed here.
|
||||||
*
|
*
|
||||||
* @param errmsg Errors messages are normally in format
|
* @param errmsg Errors messages are normally in format
|
||||||
* "[filepath:line number] Message", e.g.
|
* "[filepath:line number] Message", e.g.
|
||||||
* "[main.cpp:4] Uninitialized member variable"
|
* "[main.cpp:4] Uninitialized member variable"
|
||||||
*/
|
*/
|
||||||
virtual void reportErr( const std::string &errmsg) = 0;
|
virtual void reportErr( const std::string &errmsg) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about progress is directed here.
|
* Information about progress is directed here.
|
||||||
*
|
*
|
||||||
* @param outmsg, E.g. "Checking main.cpp..."
|
* @param outmsg, E.g. "Checking main.cpp..."
|
||||||
*/
|
*/
|
||||||
virtual void reportOut( const std::string &outmsg) = 0;
|
virtual void reportOut( const std::string &outmsg) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #ifndef ERRORLOGGER_H
|
#endif // #ifndef ERRORLOGGER_H
|
||||||
|
|
20
main.cpp
20
main.cpp
|
@ -15,19 +15,19 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "cppcheckexecutor.h"
|
||||||
|
|
||||||
#include "cppcheckexecutor.h"
|
/**
|
||||||
|
* Main function of cppcheck
|
||||||
/**
|
*
|
||||||
* Main function of cppcheck
|
* @param argc Passed to CppCheck::parseFromArgs()
|
||||||
*
|
* @param argv Passed to CppCheck::parseFromArgs()
|
||||||
* @param argc Passed to CppCheck::parseFromArgs()
|
* @return 0
|
||||||
* @param argv Passed to CppCheck::parseFromArgs()
|
|
||||||
* @return 0
|
|
||||||
*/
|
*/
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
CppCheckExecutor exec;
|
CppCheckExecutor exec;
|
||||||
exec.check( argc, argv );
|
exec.check( argc, argv );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,34 +28,34 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Preprocessor::Preprocessor( ErrorLogger *errorLogger )
|
Preprocessor::Preprocessor( ErrorLogger *errorLogger )
|
||||||
{
|
{
|
||||||
_errorLogger = errorLogger;
|
_errorLogger = errorLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||||
std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
||||||
{
|
{
|
||||||
// Get filedata from stream..
|
// Get filedata from stream..
|
||||||
bool ignoreSpace = true;
|
bool ignoreSpace = true;
|
||||||
|
|
||||||
// For the error report
|
// For the error report
|
||||||
int lineno = 1;
|
int lineno = 1;
|
||||||
|
|
||||||
std::ostringstream code;
|
std::ostringstream code;
|
||||||
for (char ch = (char)istr.get(); istr.good(); ch = (char)istr.get())
|
for (char ch = (char)istr.get(); istr.good(); ch = (char)istr.get())
|
||||||
{
|
{
|
||||||
if ( ch < 0 )
|
if ( ch < 0 )
|
||||||
{
|
{
|
||||||
// Bad content..
|
// Bad content..
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "[" << filename << ":" << lineno << "] Bad character found: " << int((unsigned char)ch) << std::endl;
|
oss << "[" << filename << ":" << lineno << "] Bad character found: " << int((unsigned char)ch) << std::endl;
|
||||||
_errorLogger->reportErr( oss.str() );
|
_errorLogger->reportErr( oss.str() );
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ch == '\n' )
|
if ( ch == '\n' )
|
||||||
++lineno;
|
++lineno;
|
||||||
|
|
||||||
// Replace assorted special chars with spaces..
|
// Replace assorted special chars with spaces..
|
||||||
if ( (ch != '\n') && (isspace(ch) || iscntrl(ch)) )
|
if ( (ch != '\n') && (isspace(ch) || iscntrl(ch)) )
|
||||||
|
@ -75,7 +75,7 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
||||||
{
|
{
|
||||||
while (istr.good() && ch!='\n')
|
while (istr.good() && ch!='\n')
|
||||||
ch = (char)istr.get();
|
ch = (char)istr.get();
|
||||||
code << "\n";
|
code << "\n";
|
||||||
++lineno;
|
++lineno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,17 +86,17 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
||||||
{
|
{
|
||||||
chPrev = ch;
|
chPrev = ch;
|
||||||
ch = (char)istr.get();
|
ch = (char)istr.get();
|
||||||
if (ch == '\n')
|
if (ch == '\n')
|
||||||
{
|
{
|
||||||
code << "\n";
|
code << "\n";
|
||||||
++lineno;
|
++lineno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( chNext == '\n' )
|
if ( chNext == '\n' )
|
||||||
++lineno;
|
++lineno;
|
||||||
code << std::string(1,ch) << std::string(1,chNext);
|
code << std::string(1,ch) << std::string(1,chNext);
|
||||||
}
|
}
|
||||||
|
@ -113,10 +113,10 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
||||||
if ( ch == '\\' )
|
if ( ch == '\\' )
|
||||||
{
|
{
|
||||||
ch = (char)istr.get();
|
ch = (char)istr.get();
|
||||||
code << std::string(1,ch);
|
code << std::string(1,ch);
|
||||||
|
|
||||||
// Avoid exiting loop if string contains "-characters
|
// Avoid exiting loop if string contains "-characters
|
||||||
ch = 0;
|
ch = 0;
|
||||||
}
|
}
|
||||||
} while ( istr.good() && ch != '\"' );
|
} while ( istr.good() && ch != '\"' );
|
||||||
}
|
}
|
||||||
|
@ -141,9 +141,9 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
||||||
{
|
{
|
||||||
code << std::string(1, ch);
|
code << std::string(1, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return code.str();
|
return code.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -158,22 +158,22 @@ void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::str
|
||||||
// Replace all tabs with spaces..
|
// Replace all tabs with spaces..
|
||||||
std::string::size_type loc = 0;
|
std::string::size_type loc = 0;
|
||||||
while ( (loc = codestr.find("\t", loc)) != std::string::npos )
|
while ( (loc = codestr.find("\t", loc)) != std::string::npos )
|
||||||
codestr[loc] = ' ';
|
codestr[loc] = ' ';
|
||||||
|
|
||||||
// Remove all indentation..
|
// Remove all indentation..
|
||||||
if ( !codestr.empty() && codestr[0] == ' ' )
|
if ( !codestr.empty() && codestr[0] == ' ' )
|
||||||
codestr.erase( 0, codestr.find_first_not_of(" ") );
|
codestr.erase( 0, codestr.find_first_not_of(" ") );
|
||||||
loc = 0;
|
loc = 0;
|
||||||
while ( (loc = codestr.find("\n ", loc)) != std::string::npos )
|
while ( (loc = codestr.find("\n ", loc)) != std::string::npos )
|
||||||
codestr.erase( 1 + loc, 1 );
|
codestr.erase( 1 + loc, 1 );
|
||||||
|
|
||||||
// Remove all trailing spaces..
|
// Remove all trailing spaces..
|
||||||
loc = 0;
|
loc = 0;
|
||||||
while ( (loc = codestr.find(" \n", loc)) != std::string::npos )
|
while ( (loc = codestr.find(" \n", loc)) != std::string::npos )
|
||||||
{
|
{
|
||||||
codestr.erase( loc, 1 );
|
codestr.erase( loc, 1 );
|
||||||
if ( loc > 0 )
|
if ( loc > 0 )
|
||||||
--loc;
|
--loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using the backslash at the end of a line..
|
// Using the backslash at the end of a line..
|
||||||
|
|
|
@ -24,34 +24,34 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include "errorlogger.h"
|
#include "errorlogger.h"
|
||||||
|
|
||||||
class Preprocessor
|
class Preprocessor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Preprocessor( ErrorLogger *errorLogger );
|
Preprocessor( ErrorLogger *errorLogger );
|
||||||
void preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename);
|
void preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename);
|
||||||
|
|
||||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||||
std::string read(std::istream &istr, const std::string &filename);
|
std::string read(std::istream &istr, const std::string &filename);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Get preprocessed code for a given configuration
|
* Get preprocessed code for a given configuration
|
||||||
*/
|
*/
|
||||||
std::string getcode(const std::string &filedata, std::string cfg);
|
std::string getcode(const std::string &filedata, std::string cfg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all possible configurations. By looking at the ifdefs and ifndefs in filedata
|
* Get all possible configurations. By looking at the ifdefs and ifndefs in filedata
|
||||||
*/
|
*/
|
||||||
std::list<std::string> getcfgs( const std::string &filedata );
|
std::list<std::string> getcfgs( const std::string &filedata );
|
||||||
|
|
||||||
std::string getdef(std::string line, bool def);
|
std::string getdef(std::string line, bool def);
|
||||||
|
|
||||||
bool match_cfg_def( std::string cfg, const std::string &def );
|
bool match_cfg_def( std::string cfg, const std::string &def );
|
||||||
|
|
||||||
ErrorLogger *_errorLogger;
|
ErrorLogger *_errorLogger;
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
68
settings.cpp
68
settings.cpp
|
@ -1,34 +1,34 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
Settings::Settings()
|
Settings::Settings()
|
||||||
{
|
{
|
||||||
_debug = false;
|
_debug = false;
|
||||||
_showAll = false;
|
_showAll = false;
|
||||||
_checkCodingStyle = false;
|
_checkCodingStyle = false;
|
||||||
_errorsOnly = false;
|
_errorsOnly = false;
|
||||||
_checkFunctionUsage = false;
|
_checkFunctionUsage = false;
|
||||||
_verbose = false;
|
_verbose = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::~Settings()
|
Settings::~Settings()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
82
settings.h
82
settings.h
|
@ -1,41 +1,41 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SETTINGS_H
|
#ifndef SETTINGS_H
|
||||||
#define SETTINGS_H
|
#define SETTINGS_H
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is just a container for general settings so that we don't need
|
* This is just a container for general settings so that we don't need
|
||||||
* to pass individual values to functions or constructors now or in the
|
* to pass individual values to functions or constructors now or in the
|
||||||
* future when we might have even more detailed settings.
|
* future when we might have even more detailed settings.
|
||||||
*/
|
*/
|
||||||
class Settings
|
class Settings
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Settings();
|
Settings();
|
||||||
virtual ~Settings();
|
virtual ~Settings();
|
||||||
|
|
||||||
bool _debug;
|
bool _debug;
|
||||||
bool _showAll;
|
bool _showAll;
|
||||||
bool _checkCodingStyle;
|
bool _checkCodingStyle;
|
||||||
bool _errorsOnly;
|
bool _errorsOnly;
|
||||||
bool _checkFunctionUsage;
|
bool _checkFunctionUsage;
|
||||||
bool _verbose;
|
bool _verbose;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
|
|
@ -50,8 +50,8 @@ private:
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
// Check for buffer overruns..
|
// Check for buffer overruns..
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings._showAll = true;
|
settings._showAll = true;
|
||||||
CheckBufferOverrunClass checkBufferOverrun( &tokenizer, settings, this );
|
CheckBufferOverrunClass checkBufferOverrun( &tokenizer, settings, this );
|
||||||
checkBufferOverrun.CheckBufferOverrun();
|
checkBufferOverrun.CheckBufferOverrun();
|
||||||
|
|
|
@ -58,17 +58,17 @@ private:
|
||||||
TEST_CASE( simple1 );
|
TEST_CASE( simple1 );
|
||||||
TEST_CASE( simple2 );
|
TEST_CASE( simple2 );
|
||||||
TEST_CASE( simple3 );
|
TEST_CASE( simple3 );
|
||||||
TEST_CASE( simple4 );
|
TEST_CASE( simple4 );
|
||||||
|
|
||||||
TEST_CASE( initvar_with_this ); // BUG 2190300
|
TEST_CASE( initvar_with_this ); // BUG 2190300
|
||||||
TEST_CASE( initvar_if ); // BUG 2190290
|
TEST_CASE( initvar_if ); // BUG 2190290
|
||||||
TEST_CASE( initvar_operator_eq1 ); // BUG 2190376
|
TEST_CASE( initvar_operator_eq1 ); // BUG 2190376
|
||||||
TEST_CASE( initvar_operator_eq2 ); // BUG 2190376
|
TEST_CASE( initvar_operator_eq2 ); // BUG 2190376
|
||||||
TEST_CASE( initvar_operator_eq3 );
|
TEST_CASE( initvar_operator_eq3 );
|
||||||
TEST_CASE( initvar_same_classname ); // BUG 2208157
|
TEST_CASE( initvar_same_classname ); // BUG 2208157
|
||||||
TEST_CASE( initvar_chained_assign ); // BUG 2270433
|
TEST_CASE( initvar_chained_assign ); // BUG 2270433
|
||||||
TEST_CASE( initvar_2constructors ); // BUG 2270353
|
TEST_CASE( initvar_2constructors ); // BUG 2270353
|
||||||
|
|
||||||
TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor
|
TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor
|
||||||
|
|
||||||
TEST_CASE( initvar_destructor ); // No variables need to be initialized in a destructor
|
TEST_CASE( initvar_destructor ); // No variables need to be initialized in a destructor
|
||||||
|
@ -185,33 +185,33 @@ private:
|
||||||
std::string err( errout.str() );
|
std::string err( errout.str() );
|
||||||
ASSERT_EQUALS( std::string(""), err );
|
ASSERT_EQUALS( std::string(""), err );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void initvar_operator_eq2()
|
void initvar_operator_eq2()
|
||||||
{
|
{
|
||||||
check( "class Fred\n"
|
check( "class Fred\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
"public:\n"
|
"public:\n"
|
||||||
" Fred() { i = 0; }\n"
|
" Fred() { i = 0; }\n"
|
||||||
" void operator=() { }\n"
|
" void operator=() { }\n"
|
||||||
" int i;\n"
|
" int i;\n"
|
||||||
"};\n" );
|
"};\n" );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:5] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
ASSERT_EQUALS( std::string("[test.cpp:5] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void initvar_operator_eq3()
|
void initvar_operator_eq3()
|
||||||
{
|
{
|
||||||
check( "class Fred\n"
|
check( "class Fred\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
"public:\n"
|
"public:\n"
|
||||||
" Fred() { Init(); }\n"
|
" Fred() { Init(); }\n"
|
||||||
" void operator=() { Init(); }\n"
|
" void operator=() { Init(); }\n"
|
||||||
"private:\n"
|
"private:\n"
|
||||||
" Init() { i = 0; }\n"
|
" Init() { i = 0; }\n"
|
||||||
" int i;\n"
|
" int i;\n"
|
||||||
"};\n" );
|
"};\n" );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void initvar_same_classname()
|
void initvar_same_classname()
|
||||||
{
|
{
|
||||||
|
@ -294,31 +294,31 @@ private:
|
||||||
std::string err( errout.str() );
|
std::string err( errout.str() );
|
||||||
ASSERT_EQUALS( std::string(""), err );
|
ASSERT_EQUALS( std::string(""), err );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void initvar_private_constructor()
|
void initvar_private_constructor()
|
||||||
{
|
{
|
||||||
check( "class Fred\n"
|
check( "class Fred\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
"private:\n"
|
"private:\n"
|
||||||
" int var;\n"
|
" int var;\n"
|
||||||
" Fred();\n"
|
" Fred();\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"Fred::Fred()\n"
|
"Fred::Fred()\n"
|
||||||
"{ }" );
|
"{ }" );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void initvar_destructor()
|
void initvar_destructor()
|
||||||
{
|
{
|
||||||
check( "class Fred\n"
|
check( "class Fred\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
"private:\n"
|
"private:\n"
|
||||||
" int var;\n"
|
" int var;\n"
|
||||||
"public:\n"
|
"public:\n"
|
||||||
" Fred() : var(0) {}\n"
|
" Fred() : var(0) {}\n"
|
||||||
" ~Fred() {}\n"
|
" ~Fred() {}\n"
|
||||||
"};\n" );
|
"};\n" );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,9 +36,9 @@ private:
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
TEST_CASE( incondition );
|
TEST_CASE( incondition );
|
||||||
TEST_CASE( return1 );
|
TEST_CASE( return1 );
|
||||||
TEST_CASE( callback1 );
|
TEST_CASE( callback1 );
|
||||||
TEST_CASE( else1 );
|
TEST_CASE( else1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,41 +63,41 @@ private:
|
||||||
check( "int f1()\n"
|
check( "int f1()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" if (f1())\n"
|
" if (f1())\n"
|
||||||
" { }\n"
|
" { }\n"
|
||||||
"}\n" );
|
|
||||||
std::string err( errout.str() );
|
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void return1()
|
|
||||||
{
|
|
||||||
check( "int f1()\n"
|
|
||||||
"{\n"
|
|
||||||
" return f1();\n"
|
|
||||||
"}\n" );
|
|
||||||
std::string err( errout.str() );
|
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback1()
|
|
||||||
{
|
|
||||||
check( "void f1()\n"
|
|
||||||
"{\n"
|
|
||||||
" void (*f)() = cond ? f1 : NULL;\n"
|
|
||||||
"}\n" );
|
|
||||||
std::string err( errout.str() );
|
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void else1()
|
|
||||||
{
|
|
||||||
check( "void f1()\n"
|
|
||||||
"{\n"
|
|
||||||
" if (cond) ;\n"
|
|
||||||
" else f1();\n"
|
|
||||||
"}\n" );
|
"}\n" );
|
||||||
std::string err( errout.str() );
|
std::string err( errout.str() );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void return1()
|
||||||
|
{
|
||||||
|
check( "int f1()\n"
|
||||||
|
"{\n"
|
||||||
|
" return f1();\n"
|
||||||
|
"}\n" );
|
||||||
|
std::string err( errout.str() );
|
||||||
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback1()
|
||||||
|
{
|
||||||
|
check( "void f1()\n"
|
||||||
|
"{\n"
|
||||||
|
" void (*f)() = cond ? f1 : NULL;\n"
|
||||||
|
"}\n" );
|
||||||
|
std::string err( errout.str() );
|
||||||
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void else1()
|
||||||
|
{
|
||||||
|
check( "void f1()\n"
|
||||||
|
"{\n"
|
||||||
|
" if (cond) ;\n"
|
||||||
|
" else f1();\n"
|
||||||
|
"}\n" );
|
||||||
|
std::string err( errout.str() );
|
||||||
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
194
testmemleak.cpp
194
testmemleak.cpp
|
@ -23,7 +23,7 @@
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include "CheckMemoryLeak.h"
|
#include "CheckMemoryLeak.h"
|
||||||
#include "testsuite.h"
|
#include "testsuite.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ private:
|
||||||
|
|
||||||
// Check for memory leaks..
|
// Check for memory leaks..
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings._debug = true;
|
settings._debug = true;
|
||||||
settings._showAll = false;
|
settings._showAll = false;
|
||||||
tokenizer.fillFunctionList();
|
tokenizer.fillFunctionList();
|
||||||
CheckMemoryLeakClass checkMemoryLeak( &tokenizer, settings, this );
|
CheckMemoryLeakClass checkMemoryLeak( &tokenizer, settings, this );
|
||||||
|
@ -112,7 +112,7 @@ private:
|
||||||
TEST_CASE( func4 );
|
TEST_CASE( func4 );
|
||||||
TEST_CASE( func5 );
|
TEST_CASE( func5 );
|
||||||
TEST_CASE( func6 );
|
TEST_CASE( func6 );
|
||||||
// TODO TEST_CASE( func7 );
|
// TODO TEST_CASE( func7 );
|
||||||
TEST_CASE( func8 ); // Using callback
|
TEST_CASE( func8 ); // Using callback
|
||||||
|
|
||||||
// TODO TEST_CASE( class1 );
|
// TODO TEST_CASE( class1 );
|
||||||
|
@ -122,11 +122,11 @@ private:
|
||||||
|
|
||||||
TEST_CASE( linux_list_1 );
|
TEST_CASE( linux_list_1 );
|
||||||
|
|
||||||
TEST_CASE( sizeof1 );
|
TEST_CASE( sizeof1 );
|
||||||
|
|
||||||
TEST_CASE( realloc1 );
|
TEST_CASE( realloc1 );
|
||||||
TEST_CASE( realloc2 );
|
TEST_CASE( realloc2 );
|
||||||
|
|
||||||
TEST_CASE( assign );
|
TEST_CASE( assign );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ private:
|
||||||
check( "void f()\n"
|
check( "void f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int *a = new int[10];\n"
|
" int *a = new int[10];\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Memory leak: a\n"), errout.str() );
|
ASSERT_EQUALS( std::string("[test.cpp:4]: Memory leak: a\n"), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,8 +611,8 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
" while (!str);\n"
|
" while (!str);\n"
|
||||||
" return str;\n"
|
" return str;\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
std::string err( errout.str() );
|
std::string err( errout.str() );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Memory leak: str\n"), err );
|
ASSERT_EQUALS( std::string("[test.cpp:5]: Memory leak: str\n"), err );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,37 +789,37 @@ private:
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:10]: Memory leak: p\n"), err );
|
ASSERT_EQUALS( std::string("[test.cpp:10]: Memory leak: p\n"), err );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void func7()
|
void func7()
|
||||||
{
|
{
|
||||||
check( "static void foo(char *str)\n"
|
check( "static void foo(char *str)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" if (abc)\n"
|
" if (abc)\n"
|
||||||
" return;"
|
" return;"
|
||||||
" delete [] str;\n"
|
" delete [] str;\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"static void f()\n"
|
"static void f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *p = new char[100];\n"
|
" char *p = new char[100];\n"
|
||||||
" foo(p);\n"
|
" foo(p);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
std::string err( errout.str() );
|
std::string err( errout.str() );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:11]: Memory leak: p\n"), err );
|
ASSERT_EQUALS( std::string("[test.cpp:11]: Memory leak: p\n"), err );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void func8()
|
void func8()
|
||||||
{
|
{
|
||||||
check( "static void foo()\n"
|
check( "static void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *str = new char[100];"
|
" char *str = new char[100];"
|
||||||
" (*release)(str);\n"
|
" (*release)(str);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void func3()
|
void func3()
|
||||||
|
@ -969,61 +969,61 @@ private:
|
||||||
|
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:12]: Memory leak: s2\n"), err );
|
ASSERT_EQUALS( std::string("[test.cpp:12]: Memory leak: s2\n"), err );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void realloc1()
|
void realloc1()
|
||||||
{
|
{
|
||||||
check( "void foo()\n"
|
check( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *a = (char *)malloc(10);\n"
|
" char *a = (char *)malloc(10);\n"
|
||||||
" a = realloc(a, 100);\n"
|
" a = realloc(a, 100);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
|
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Memory leak: a\n"), errout.str() );
|
ASSERT_EQUALS( std::string("[test.cpp:5]: Memory leak: a\n"), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void realloc2()
|
void realloc2()
|
||||||
{
|
{
|
||||||
check( "void foo()\n"
|
check( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *a = (char *)malloc(10);\n"
|
" char *a = (char *)malloc(10);\n"
|
||||||
" a = (char *)realloc(a, 100);\n"
|
" a = (char *)realloc(a, 100);\n"
|
||||||
" free(a);\n"
|
" free(a);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
|
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void assign()
|
void assign()
|
||||||
{
|
{
|
||||||
check( "void foo()\n"
|
check( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *a = (char *)malloc(10);\n"
|
" char *a = (char *)malloc(10);\n"
|
||||||
" a = 0;\n"
|
" a = 0;\n"
|
||||||
" free(a);\n"
|
" free(a);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
|
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Memory leak: a\n"), errout.str() );
|
ASSERT_EQUALS( std::string("[test.cpp:3]: Memory leak: a\n"), errout.str() );
|
||||||
|
|
||||||
check( "void foo()\n"
|
check( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *a = (char *)malloc(10);\n"
|
" char *a = (char *)malloc(10);\n"
|
||||||
" char *p = a;\n"
|
" char *p = a;\n"
|
||||||
" free(p);\n"
|
" free(p);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
|
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
|
|
||||||
check( "void foo()\n"
|
check( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *a = (char *)malloc(10);\n"
|
" char *a = (char *)malloc(10);\n"
|
||||||
" a += 10;\n"
|
" a += 10;\n"
|
||||||
" free(a - 10);\n"
|
" free(a - 10);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
|
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,9 +37,9 @@ private:
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
// Just read the code into a string. Perform simple cleanup of the code
|
// Just read the code into a string. Perform simple cleanup of the code
|
||||||
TEST_CASE(readCode);
|
TEST_CASE(readCode);
|
||||||
|
|
||||||
// The bug that started the whole work with the new preprocessor
|
// The bug that started the whole work with the new preprocessor
|
||||||
TEST_CASE( Bug2190219 );
|
TEST_CASE( Bug2190219 );
|
||||||
|
|
||||||
|
@ -62,18 +62,18 @@ private:
|
||||||
|
|
||||||
TEST_CASE( multiline );
|
TEST_CASE( multiline );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void readCode()
|
void readCode()
|
||||||
{
|
{
|
||||||
const char code[] = " \t a //\n"
|
const char code[] = " \t a //\n"
|
||||||
" #aa\t /* remove this */\tb \r\n";
|
" #aa\t /* remove this */\tb \r\n";
|
||||||
Preprocessor p(NULL);
|
Preprocessor p(NULL);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
std::string codestr( p.read(istr,"") );
|
std::string codestr( p.read(istr,"") );
|
||||||
ASSERT_EQUALS( "a \n#aa b \n", codestr );
|
ASSERT_EQUALS( "a \n#aa b \n", codestr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool cmpmaps(const std::map<std::string, std::string> &m1, const std::map<std::string, std::string> &m2)
|
bool cmpmaps(const std::map<std::string, std::string> &m1, const std::map<std::string, std::string> &m2)
|
||||||
{
|
{
|
||||||
|
@ -154,7 +154,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -178,7 +178,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -201,7 +201,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -227,7 +227,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -251,7 +251,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -278,7 +278,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -301,7 +301,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -324,7 +324,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -344,7 +344,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -369,7 +369,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -389,7 +389,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -414,7 +414,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
@ -434,7 +434,7 @@ private:
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Preprocessor preprocessor( this );
|
Preprocessor preprocessor( this );
|
||||||
preprocessor.preprocess( istr, actual, "" );
|
preprocessor.preprocess( istr, actual, "" );
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
|
|
|
@ -15,13 +15,13 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "testsuite.h"
|
#include "testsuite.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
TestFixture::runTests( (argc==2) ? argv[1] : NULL );
|
TestFixture::runTests( (argc==2) ? argv[1] : NULL );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,73 +1,73 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007 Daniel Marjamäki
|
* Copyright (C) 2007 Daniel Marjamäki
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "testsuite.h"
|
#include "testsuite.h"
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
extern std::ostringstream errout;
|
extern std::ostringstream errout;
|
||||||
|
|
||||||
class TestSimplifyTokens : public TestFixture
|
class TestSimplifyTokens : public TestFixture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestSimplifyTokens() : TestFixture("TestSimplifyTokens")
|
TestSimplifyTokens() : TestFixture("TestSimplifyTokens")
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
TEST_CASE( cast0 );
|
TEST_CASE( cast0 );
|
||||||
TEST_CASE( sizeof1 );
|
TEST_CASE( sizeof1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tok(const char code[])
|
std::string tok(const char code[])
|
||||||
{
|
{
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
tokenizer.tokenize( istr, "test.cpp" );
|
tokenizer.tokenize( istr, "test.cpp" );
|
||||||
tokenizer.simplifyTokenList();
|
tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
std::string ret;
|
std::string ret;
|
||||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||||
{
|
{
|
||||||
ret += std::string(tok->aaaa()) + " ";
|
ret += std::string(tok->aaaa()) + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cast0()
|
void cast0()
|
||||||
{
|
{
|
||||||
const char code1[] = " if ( p == (char *)0 ) ";
|
const char code1[] = " if ( p == (char *)0 ) ";
|
||||||
const char code2[] = " if ( p == 0 ) ";
|
const char code2[] = " if ( p == 0 ) ";
|
||||||
ASSERT_EQUALS( tok(code1), tok(code2) );
|
ASSERT_EQUALS( tok(code1), tok(code2) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void sizeof1()
|
void sizeof1()
|
||||||
{
|
{
|
||||||
const char code1[] = " struct ABC *abc = malloc(sizeof(*abc)); ";
|
const char code1[] = " struct ABC *abc = malloc(sizeof(*abc)); ";
|
||||||
const char code2[] = " struct ABC *abc = malloc(100); ";
|
const char code2[] = " struct ABC *abc = malloc(100); ";
|
||||||
ASSERT_EQUALS( tok(code1), tok(code2) );
|
ASSERT_EQUALS( tok(code1), tok(code2) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST( TestSimplifyTokens )
|
REGISTER_TEST( TestSimplifyTokens )
|
||||||
|
|
|
@ -76,48 +76,48 @@ bool TestFixture::runTest(const char testname[])
|
||||||
std::cout << classname << "::" << testname << "\n";
|
std::cout << classname << "::" << testname << "\n";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string writestr( const std::string &str )
|
static std::string writestr( const std::string &str )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
ostr << "\"";
|
ostr << "\"";
|
||||||
for (unsigned int i = 0; i < str.length(); ++i)
|
for (unsigned int i = 0; i < str.length(); ++i)
|
||||||
{
|
{
|
||||||
char ch = str[i];
|
char ch = str[i];
|
||||||
if ( ch == '\n' )
|
if ( ch == '\n' )
|
||||||
ostr << "\\n";
|
ostr << "\\n";
|
||||||
else if ( ch == '\t' )
|
else if ( ch == '\t' )
|
||||||
ostr << "\\t";
|
ostr << "\\t";
|
||||||
else if ( ch == '\"' )
|
else if ( ch == '\"' )
|
||||||
ostr << "\\\"";
|
ostr << "\\\"";
|
||||||
else
|
else
|
||||||
ostr << std::string(1, ch);
|
ostr << std::string(1, ch);
|
||||||
}
|
}
|
||||||
ostr << "\"";
|
ostr << "\"";
|
||||||
return ostr.str();
|
return ostr.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
|
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
|
||||||
{
|
{
|
||||||
if ( expected != actual )
|
if ( expected != actual )
|
||||||
{
|
{
|
||||||
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
|
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
|
||||||
<< "Expected:" << std::endl
|
<< "Expected:" << std::endl
|
||||||
<< writestr(expected) << std::endl
|
<< writestr(expected) << std::endl
|
||||||
<< "Actual:" << std::endl
|
<< "Actual:" << std::endl
|
||||||
<< writestr(actual) << std::endl;
|
<< writestr(actual) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestFixture::assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual)
|
void TestFixture::assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual)
|
||||||
{
|
{
|
||||||
std::ostringstream ostr1;
|
std::ostringstream ostr1;
|
||||||
ostr1 << expected;
|
ostr1 << expected;
|
||||||
std::ostringstream ostr2;
|
std::ostringstream ostr2;
|
||||||
ostr2 << actual;
|
ostr2 << actual;
|
||||||
assertEquals( filename, linenr, ostr1.str(), ostr2.str() );
|
assertEquals( filename, linenr, ostr1.str(), ostr2.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestFixture::printTests()
|
void TestFixture::printTests()
|
||||||
{
|
{
|
||||||
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
|
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
|
||||||
|
@ -160,7 +160,7 @@ void TestFixture::reportErr( const std::string &errmsg)
|
||||||
errout << errmsg << std::endl;
|
errout << errmsg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestFixture::reportOut( const std::string &outmsg)
|
void TestFixture::reportOut( const std::string &outmsg)
|
||||||
{
|
{
|
||||||
// These can probably be ignored
|
// These can probably be ignored
|
||||||
}
|
}
|
||||||
|
|
12
testsuite.h
12
testsuite.h
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "errorlogger.h"
|
#include "errorlogger.h"
|
||||||
|
|
||||||
class TOKEN;
|
class TOKEN;
|
||||||
|
|
||||||
class TestFixture : public ErrorLogger
|
class TestFixture : public ErrorLogger
|
||||||
{
|
{
|
||||||
|
@ -40,10 +40,10 @@ protected:
|
||||||
void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual);
|
void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual);
|
||||||
void assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual);
|
void assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void reportErr( const std::string &errmsg);
|
virtual void reportErr( const std::string &errmsg);
|
||||||
|
|
||||||
virtual void reportOut( const std::string &outmsg);
|
virtual void reportOut( const std::string &outmsg);
|
||||||
|
|
||||||
TestFixture(const std::string &_name);
|
TestFixture(const std::string &_name);
|
||||||
virtual ~TestFixture() { }
|
virtual ~TestFixture() { }
|
||||||
|
|
300
testtokenize.cpp
300
testtokenize.cpp
|
@ -21,10 +21,10 @@
|
||||||
// the code for a known configuration, it generates the code for each configuration.
|
// the code for a known configuration, it generates the code for each configuration.
|
||||||
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "testsuite.h"
|
#include "testsuite.h"
|
||||||
#define UNIT_TESTING // Get access to "private" data in Tokenizer
|
#define UNIT_TESTING // Get access to "private" data in Tokenizer
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
|
|
||||||
extern std::ostringstream errout;
|
extern std::ostringstream errout;
|
||||||
class TestTokenizer : public TestFixture
|
class TestTokenizer : public TestFixture
|
||||||
|
@ -42,16 +42,16 @@ private:
|
||||||
|
|
||||||
TEST_CASE( inlineasm );
|
TEST_CASE( inlineasm );
|
||||||
|
|
||||||
TEST_CASE( dupfuncname );
|
TEST_CASE( dupfuncname );
|
||||||
|
|
||||||
TEST_CASE( const_and_volatile_functions );
|
TEST_CASE( const_and_volatile_functions );
|
||||||
|
|
||||||
TEST_CASE( numeric_true_condition );
|
TEST_CASE( numeric_true_condition );
|
||||||
|
|
||||||
TEST_CASE( multi_compare );
|
TEST_CASE( multi_compare );
|
||||||
|
|
||||||
TEST_CASE( match1 );
|
TEST_CASE( match1 );
|
||||||
|
|
||||||
TEST_CASE( varid1 );
|
TEST_CASE( varid1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,144 +156,144 @@ private:
|
||||||
|
|
||||||
ASSERT_EQUALS( 1, static_cast<unsigned int>(tokenizer._functionList.size()) );
|
ASSERT_EQUALS( 1, static_cast<unsigned int>(tokenizer._functionList.size()) );
|
||||||
ASSERT_EQUALS( std::string("b"), tokenizer._functionList[0]->aaaa() );
|
ASSERT_EQUALS( std::string("b"), tokenizer._functionList[0]->aaaa() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void const_and_volatile_functions()
|
void const_and_volatile_functions()
|
||||||
{
|
{
|
||||||
const char code[] = "class B\n\
|
const char code[] = "class B\n\
|
||||||
{\n\
|
{\n\
|
||||||
public:\n\
|
public:\n\
|
||||||
void a();\n\
|
void a();\n\
|
||||||
void b() const;\n\
|
void b() const;\n\
|
||||||
void c() volatile;\n\
|
void c() volatile;\n\
|
||||||
};\n\
|
};\n\
|
||||||
\n\
|
\n\
|
||||||
void B::a()\n\
|
void B::a()\n\
|
||||||
{}\n\
|
{}\n\
|
||||||
\n\
|
\n\
|
||||||
void B::b() const\n\
|
void B::b() const\n\
|
||||||
{}\n\
|
{}\n\
|
||||||
\n\
|
\n\
|
||||||
void B::c() volatile\n\
|
void B::c() volatile\n\
|
||||||
{}\n";
|
{}\n";
|
||||||
|
|
||||||
|
|
||||||
// tokenize..
|
// tokenize..
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
tokenizer.fillFunctionList();
|
tokenizer.fillFunctionList();
|
||||||
|
|
||||||
ASSERT_EQUALS( 3, static_cast<unsigned int>(tokenizer._functionList.size()) );
|
ASSERT_EQUALS( 3, static_cast<unsigned int>(tokenizer._functionList.size()) );
|
||||||
if( tokenizer._functionList.size() == 3 )
|
if( tokenizer._functionList.size() == 3 )
|
||||||
{
|
{
|
||||||
ASSERT_EQUALS( std::string("a"), tokenizer._functionList[0]->str() );
|
ASSERT_EQUALS( std::string("a"), tokenizer._functionList[0]->str() );
|
||||||
ASSERT_EQUALS( std::string("b"), tokenizer._functionList[1]->str() );
|
ASSERT_EQUALS( std::string("b"), tokenizer._functionList[1]->str() );
|
||||||
ASSERT_EQUALS( std::string("c"), tokenizer._functionList[2]->str() );
|
ASSERT_EQUALS( std::string("c"), tokenizer._functionList[2]->str() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void numeric_true_condition()
|
void numeric_true_condition()
|
||||||
{
|
{
|
||||||
const char code[] = "void f()\n"
|
const char code[] = "void f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" if (5==5);\n"
|
" if (5==5);\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
// tokenize..
|
// tokenize..
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
tokenizer.simplifyTokenList();
|
tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
for (const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next())
|
for (const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next())
|
||||||
ostr << " " << tok->str();
|
ostr << " " << tok->str();
|
||||||
ASSERT_EQUALS( std::string(" void f ( ) { if ( true ) ; }"), ostr.str() );
|
ASSERT_EQUALS( std::string(" void f ( ) { if ( true ) ; }"), ostr.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void multi_compare()
|
void multi_compare()
|
||||||
{
|
{
|
||||||
// Test for found
|
// Test for found
|
||||||
ASSERT_EQUALS( 1, TOKEN::multiCompare( "one|two", "one" ) );
|
ASSERT_EQUALS( 1, TOKEN::multiCompare( "one|two", "one" ) );
|
||||||
ASSERT_EQUALS( 1, TOKEN::multiCompare( "one|two", "two" ) );
|
ASSERT_EQUALS( 1, TOKEN::multiCompare( "one|two", "two" ) );
|
||||||
ASSERT_EQUALS( 1, TOKEN::multiCompare( "verybig|two|", "two" ) );
|
ASSERT_EQUALS( 1, TOKEN::multiCompare( "verybig|two|", "two" ) );
|
||||||
|
|
||||||
// Test for empty string found
|
// Test for empty string found
|
||||||
ASSERT_EQUALS( 0, TOKEN::multiCompare( "|one|two", "notfound" ) );
|
ASSERT_EQUALS( 0, TOKEN::multiCompare( "|one|two", "notfound" ) );
|
||||||
ASSERT_EQUALS( 0, TOKEN::multiCompare( "one||two", "notfound" ) );
|
ASSERT_EQUALS( 0, TOKEN::multiCompare( "one||two", "notfound" ) );
|
||||||
ASSERT_EQUALS( 0, TOKEN::multiCompare( "one|two|", "notfound" ) );
|
ASSERT_EQUALS( 0, TOKEN::multiCompare( "one|two|", "notfound" ) );
|
||||||
|
|
||||||
// Test for not found
|
// Test for not found
|
||||||
ASSERT_EQUALS( -1, TOKEN::multiCompare( "one|two", "notfound" ) );
|
ASSERT_EQUALS( -1, TOKEN::multiCompare( "one|two", "notfound" ) );
|
||||||
ASSERT_EQUALS( -1, TOKEN::multiCompare( "verybig|two", "s" ) );
|
ASSERT_EQUALS( -1, TOKEN::multiCompare( "verybig|two", "s" ) );
|
||||||
ASSERT_EQUALS( -1, TOKEN::multiCompare( "one|two", "ne" ) );
|
ASSERT_EQUALS( -1, TOKEN::multiCompare( "one|two", "ne" ) );
|
||||||
ASSERT_EQUALS( -1, TOKEN::multiCompare( "abc|def", "a" ) );
|
ASSERT_EQUALS( -1, TOKEN::multiCompare( "abc|def", "a" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void match1()
|
void match1()
|
||||||
{
|
{
|
||||||
// Match "%var% | %var%"
|
// Match "%var% | %var%"
|
||||||
{
|
{
|
||||||
const std::string code("abc|def");
|
const std::string code("abc|def");
|
||||||
|
|
||||||
// tokenize..
|
// tokenize..
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
// Match..
|
// Match..
|
||||||
ASSERT_EQUALS( true, TOKEN::Match(tokenizer.tokens(), "%var% | %var%") );
|
ASSERT_EQUALS( true, TOKEN::Match(tokenizer.tokens(), "%var% | %var%") );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match "%var% || %var%"
|
// Match "%var% || %var%"
|
||||||
{
|
{
|
||||||
const std::string code("abc||def");
|
const std::string code("abc||def");
|
||||||
|
|
||||||
// tokenize..
|
// tokenize..
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
// Match..
|
// Match..
|
||||||
ASSERT_EQUALS( true, TOKEN::Match(tokenizer.tokens(), "%var% || %var%") );
|
ASSERT_EQUALS( true, TOKEN::Match(tokenizer.tokens(), "%var% || %var%") );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void varid1()
|
void varid1()
|
||||||
{
|
{
|
||||||
const std::string code(";static int i = 1;\n"
|
const std::string code(";static int i = 1;\n"
|
||||||
"void f()\n"
|
"void f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int i = 2;\n"
|
" int i = 2;\n"
|
||||||
" for (int i = 0; i < 10; ++i)\n"
|
" for (int i = 0; i < 10; ++i)\n"
|
||||||
" i = 3;\n"
|
" i = 3;\n"
|
||||||
" i = 4;\n"
|
" i = 4;\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
|
|
||||||
// tokenize..
|
// tokenize..
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
tokenizer.setVarId();
|
tokenizer.setVarId();
|
||||||
|
|
||||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||||
{
|
{
|
||||||
if ( tok->str() != "i" )
|
if ( tok->str() != "i" )
|
||||||
ASSERT_EQUALS( 0, tok->varId() );
|
ASSERT_EQUALS( 0, tok->varId() );
|
||||||
else if ( TOKEN::Match(tok, "i = 1") )
|
else if ( TOKEN::Match(tok, "i = 1") )
|
||||||
ASSERT_EQUALS( 1, tok->varId() );
|
ASSERT_EQUALS( 1, tok->varId() );
|
||||||
else if ( TOKEN::Match(tok, "i = 2") )
|
else if ( TOKEN::Match(tok, "i = 2") )
|
||||||
ASSERT_EQUALS( 2, tok->varId() );
|
ASSERT_EQUALS( 2, tok->varId() );
|
||||||
else if ( TOKEN::Match(tok, "i = 3") )
|
else if ( TOKEN::Match(tok, "i = 3") )
|
||||||
ASSERT_EQUALS( 3, tok->varId() );
|
ASSERT_EQUALS( 3, tok->varId() );
|
||||||
else if ( TOKEN::Match(tok, "i = 4") )
|
else if ( TOKEN::Match(tok, "i = 4") )
|
||||||
ASSERT_EQUALS( 2, tok->varId() );
|
ASSERT_EQUALS( 2, tok->varId() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,184 +1,184 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007 Daniel Marjamäki
|
* Copyright (C) 2007 Daniel Marjamäki
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Check for unused variables..
|
// Check for unused variables..
|
||||||
|
|
||||||
#define UNIT_TESTING
|
#define UNIT_TESTING
|
||||||
#include "testsuite.h"
|
#include "testsuite.h"
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include "CheckOther.h"
|
#include "CheckOther.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
extern std::ostringstream errout;
|
extern std::ostringstream errout;
|
||||||
|
|
||||||
class TestUnusedVar : public TestFixture
|
class TestUnusedVar : public TestFixture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestUnusedVar() : TestFixture("TestUnusedVar")
|
TestUnusedVar() : TestFixture("TestUnusedVar")
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void check( const char code[] )
|
void check( const char code[] )
|
||||||
{
|
{
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize( istr, "test.cpp" );
|
tokenizer.tokenize( istr, "test.cpp" );
|
||||||
tokenizer.simplifyTokenList();
|
tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
// Check for unused variables..
|
// Check for unused variables..
|
||||||
CheckOther checkOther( &tokenizer, this );
|
CheckOther checkOther( &tokenizer, this );
|
||||||
checkOther.CheckStructMemberUsage();
|
checkOther.CheckStructMemberUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
TEST_CASE( structmember1 );
|
TEST_CASE( structmember1 );
|
||||||
TEST_CASE( structmember2 );
|
TEST_CASE( structmember2 );
|
||||||
TEST_CASE( structmember3 );
|
TEST_CASE( structmember3 );
|
||||||
|
|
||||||
TEST_CASE( localvar1 );
|
TEST_CASE( localvar1 );
|
||||||
TEST_CASE( localvar2 );
|
TEST_CASE( localvar2 );
|
||||||
TEST_CASE( localvar3 );
|
TEST_CASE( localvar3 );
|
||||||
TEST_CASE( localvar4 );
|
TEST_CASE( localvar4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void structmember1()
|
void structmember1()
|
||||||
{
|
{
|
||||||
check( "struct abc\n"
|
check( "struct abc\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int a;\n"
|
" int a;\n"
|
||||||
" int b;\n"
|
" int b;\n"
|
||||||
" int c;\n"
|
" int c;\n"
|
||||||
"};\n" );
|
"};\n" );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:2]: struct member 'abc::a' is never read\n"
|
ASSERT_EQUALS( std::string("[test.cpp:2]: struct member 'abc::a' is never read\n"
|
||||||
"[test.cpp:3]: struct member 'abc::b' is never read\n"
|
"[test.cpp:3]: struct member 'abc::b' is never read\n"
|
||||||
"[test.cpp:4]: struct member 'abc::c' is never read\n"), errout.str() );
|
"[test.cpp:4]: struct member 'abc::c' is never read\n"), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void structmember2()
|
void structmember2()
|
||||||
{
|
{
|
||||||
check( "struct ABC\n"
|
check( "struct ABC\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int a;\n"
|
" int a;\n"
|
||||||
" int b;\n"
|
" int b;\n"
|
||||||
" int c;\n"
|
" int c;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"\n"
|
"\n"
|
||||||
"void foo()\n"
|
"void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" struct ABC abc;\n"
|
" struct ABC abc;\n"
|
||||||
" int a = abc.a;\n"
|
" int a = abc.a;\n"
|
||||||
" int b = abc.b;\n"
|
" int b = abc.b;\n"
|
||||||
" int c = abc.c;\n"
|
" int c = abc.c;\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void structmember3()
|
void structmember3()
|
||||||
{
|
{
|
||||||
check( "struct ABC\n"
|
check( "struct ABC\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int a;\n"
|
" int a;\n"
|
||||||
" int b;\n"
|
" int b;\n"
|
||||||
" int c;\n"
|
" int c;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"\n"
|
"\n"
|
||||||
"static struct ABC abc[] = { {1, 2, 3} };\n"
|
"static struct ABC abc[] = { {1, 2, 3} };\n"
|
||||||
"\n"
|
"\n"
|
||||||
"void foo()\n"
|
"void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int a = abc[0].a;\n"
|
" int a = abc[0].a;\n"
|
||||||
" int b = abc[0].b;\n"
|
" int b = abc[0].b;\n"
|
||||||
" int c = abc[0].c;\n"
|
" int c = abc[0].c;\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void functionVariableUsage( const char code[] )
|
void functionVariableUsage( const char code[] )
|
||||||
{
|
{
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize( istr, "test.cpp" );
|
tokenizer.tokenize( istr, "test.cpp" );
|
||||||
tokenizer.simplifyTokenList();
|
tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
// Check for unused variables..
|
// Check for unused variables..
|
||||||
CheckOther checkOther( &tokenizer, this );
|
CheckOther checkOther( &tokenizer, this );
|
||||||
checkOther.functionVariableUsage();
|
checkOther.functionVariableUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar1()
|
void localvar1()
|
||||||
{
|
{
|
||||||
functionVariableUsage( "void foo()\n"
|
functionVariableUsage( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int i = 0;\n"
|
" int i = 0;\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar2()
|
void localvar2()
|
||||||
{
|
{
|
||||||
functionVariableUsage( "void foo()\n"
|
functionVariableUsage( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int i;\n"
|
" int i;\n"
|
||||||
" return i;\n"
|
" return i;\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is not assigned a value\n"), errout.str() );
|
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is not assigned a value\n"), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar3()
|
void localvar3()
|
||||||
{
|
{
|
||||||
functionVariableUsage( "void foo()\n"
|
functionVariableUsage( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int i;\n"
|
" int i;\n"
|
||||||
" if ( abc )\n"
|
" if ( abc )\n"
|
||||||
" ;\n"
|
" ;\n"
|
||||||
" else i = 0;\n"
|
" else i = 0;\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar4()
|
void localvar4()
|
||||||
{
|
{
|
||||||
functionVariableUsage( "void foo()\n"
|
functionVariableUsage( "void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int i = 0;\n"
|
" int i = 0;\n"
|
||||||
" f(i);\n"
|
" f(i);\n"
|
||||||
"}\n" );
|
"}\n" );
|
||||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST( TestUnusedVar )
|
REGISTER_TEST( TestUnusedVar )
|
||||||
|
|
||||||
|
|
||||||
|
|
234
token.cpp
234
token.cpp
|
@ -28,10 +28,10 @@
|
||||||
TOKEN::TOKEN()
|
TOKEN::TOKEN()
|
||||||
{
|
{
|
||||||
_fileIndex = 0;
|
_fileIndex = 0;
|
||||||
_cstr = 0;
|
_cstr = 0;
|
||||||
_str = "";
|
_str = "";
|
||||||
_linenr = 0;
|
_linenr = 0;
|
||||||
_next = 0;
|
_next = 0;
|
||||||
_varId = 0;
|
_varId = 0;
|
||||||
_isName = false;
|
_isName = false;
|
||||||
_isNumber = false;
|
_isNumber = false;
|
||||||
|
@ -43,7 +43,7 @@ TOKEN::~TOKEN()
|
||||||
}
|
}
|
||||||
|
|
||||||
void TOKEN::setstr( const char s[] )
|
void TOKEN::setstr( const char s[] )
|
||||||
{
|
{
|
||||||
_str = s;
|
_str = s;
|
||||||
std::free(_cstr);
|
std::free(_cstr);
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
@ -90,56 +90,56 @@ const char *TOKEN::strAt(int index) const
|
||||||
const TOKEN *tok = this->tokAt(index);
|
const TOKEN *tok = this->tokAt(index);
|
||||||
return tok ? tok->_cstr : "";
|
return tok ? tok->_cstr : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int TOKEN::multiCompare( const char *needle, const char *haystack )
|
int TOKEN::multiCompare( const char *needle, const char *haystack )
|
||||||
{
|
{
|
||||||
bool emptyStringFound = false;
|
bool emptyStringFound = false;
|
||||||
bool findNextOr = false;
|
bool findNextOr = false;
|
||||||
const char *haystackPointer = haystack;
|
const char *haystackPointer = haystack;
|
||||||
for( ; *needle; ++needle )
|
for( ; *needle; ++needle )
|
||||||
{
|
{
|
||||||
if( *needle == '|' )
|
if( *needle == '|' )
|
||||||
{
|
{
|
||||||
// If needle and haystack are both at the end, we have a match.
|
// If needle and haystack are both at the end, we have a match.
|
||||||
if( *haystackPointer == 0 )
|
if( *haystackPointer == 0 )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
haystackPointer = haystack;
|
haystackPointer = haystack;
|
||||||
if( findNextOr )
|
if( findNextOr )
|
||||||
findNextOr = false;
|
findNextOr = false;
|
||||||
else
|
else
|
||||||
emptyStringFound = true;
|
emptyStringFound = true;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( findNextOr )
|
if( findNextOr )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If haystack and needle don't share the same character, reset
|
// If haystack and needle don't share the same character, reset
|
||||||
// haystackpointer and find next '|' character.
|
// haystackpointer and find next '|' character.
|
||||||
if( *haystackPointer != *needle )
|
if( *haystackPointer != *needle )
|
||||||
{
|
{
|
||||||
haystackPointer = haystack;
|
haystackPointer = haystack;
|
||||||
findNextOr = true;
|
findNextOr = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All characters in haystack and needle have matched this far
|
// All characters in haystack and needle have matched this far
|
||||||
haystackPointer++;
|
haystackPointer++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If both needle and haystack are at the end, then we have a match.
|
// If both needle and haystack are at the end, then we have a match.
|
||||||
if( *haystackPointer == 0 )
|
if( *haystackPointer == 0 )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// If empty string was found or if last character in needle was '|'
|
// If empty string was found or if last character in needle was '|'
|
||||||
if( emptyStringFound || findNextOr == false )
|
if( emptyStringFound || findNextOr == false )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[])
|
bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[])
|
||||||
{
|
{
|
||||||
|
@ -153,7 +153,7 @@ bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[]
|
||||||
while ( *p == ' ' )
|
while ( *p == ' ' )
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
// Extract token from pattern..
|
// Extract token from pattern..
|
||||||
// TODO: Refactor this so there can't be buffer overflows
|
// TODO: Refactor this so there can't be buffer overflows
|
||||||
char str[500];
|
char str[500];
|
||||||
char *s = str;
|
char *s = str;
|
||||||
|
@ -175,12 +175,12 @@ bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[]
|
||||||
{
|
{
|
||||||
if (!tok->isName())
|
if (!tok->isName())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept any token
|
// Accept any token
|
||||||
else if (strcmp(str,"%any%")==0 )
|
else if (strcmp(str,"%any%")==0 )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variable name..
|
// Variable name..
|
||||||
|
@ -229,22 +229,22 @@ bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[]
|
||||||
if ( strchr( str + 1, tok->_str[0] ) == 0 )
|
if ( strchr( str + 1, tok->_str[0] ) == 0 )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse multi options, such as void|int|char (accept token which is one of these 3)
|
// Parse multi options, such as void|int|char (accept token which is one of these 3)
|
||||||
else if ( strchr(str, '|') && strlen( str ) > 2 )
|
else if ( strchr(str, '|') && strlen( str ) > 2 )
|
||||||
{
|
{
|
||||||
int res = multiCompare( str, tok->_cstr );
|
int res = multiCompare( str, tok->_cstr );
|
||||||
if( res == 0 )
|
if( res == 0 )
|
||||||
{
|
{
|
||||||
// Empty alternative matches, use the same token on next round
|
// Empty alternative matches, use the same token on next round
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if( res == -1 )
|
else if( res == -1 )
|
||||||
{
|
{
|
||||||
// No match
|
// No match
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (str != tok->_str)
|
else if (str != tok->_str)
|
||||||
return false;
|
return false;
|
||||||
|
@ -269,7 +269,7 @@ bool TOKEN::isNumber() const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TOKEN::isStandardType() const
|
bool TOKEN::isStandardType() const
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
const char *type[] = {"bool","char","short","int","long","float","double",0};
|
const char *type[] = {"bool","char","short","int","long","float","double",0};
|
||||||
for (int i = 0; type[i]; i++)
|
for (int i = 0; type[i]; i++)
|
||||||
|
@ -309,43 +309,43 @@ const TOKEN *TOKEN::findtoken(const TOKEN *tok1, const char *tokenstr[])
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int TOKEN::varId() const
|
unsigned int TOKEN::varId() const
|
||||||
{
|
{
|
||||||
return _varId;
|
return _varId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TOKEN::varId( unsigned int id )
|
void TOKEN::varId( unsigned int id )
|
||||||
{
|
{
|
||||||
_varId = id;
|
_varId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOKEN *TOKEN::next() const
|
TOKEN *TOKEN::next() const
|
||||||
{
|
{
|
||||||
return _next;
|
return _next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TOKEN::next( TOKEN *next )
|
void TOKEN::next( TOKEN *next )
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int TOKEN::fileIndex() const
|
unsigned int TOKEN::fileIndex() const
|
||||||
{
|
{
|
||||||
return _fileIndex;
|
return _fileIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TOKEN::fileIndex( unsigned int fileIndex )
|
void TOKEN::fileIndex( unsigned int fileIndex )
|
||||||
{
|
{
|
||||||
_fileIndex = fileIndex;
|
_fileIndex = fileIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int TOKEN::linenr() const
|
unsigned int TOKEN::linenr() const
|
||||||
{
|
{
|
||||||
return _linenr;
|
return _linenr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TOKEN::linenr( unsigned int linenr )
|
void TOKEN::linenr( unsigned int linenr )
|
||||||
{
|
{
|
||||||
_linenr = linenr;
|
_linenr = linenr;
|
||||||
}
|
}
|
||||||
|
|
276
token.h
276
token.h
|
@ -1,138 +1,138 @@
|
||||||
/*
|
/*
|
||||||
* c++check - c/c++ syntax checking
|
* c++check - c/c++ syntax checking
|
||||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TOKEN_H
|
#ifndef TOKEN_H
|
||||||
#define TOKEN_H
|
#define TOKEN_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class TOKEN
|
class TOKEN
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TOKEN();
|
TOKEN();
|
||||||
~TOKEN();
|
~TOKEN();
|
||||||
void setstr( const char s[] );
|
void setstr( const char s[] );
|
||||||
|
|
||||||
const std::string &str() const
|
const std::string &str() const
|
||||||
{ return _str; }
|
{ return _str; }
|
||||||
|
|
||||||
const char *aaaa() const
|
const char *aaaa() const
|
||||||
{ return _cstr; }
|
{ return _cstr; }
|
||||||
|
|
||||||
char aaaa0() const
|
char aaaa0() const
|
||||||
{ return _cstr[0]; }
|
{ return _cstr[0]; }
|
||||||
|
|
||||||
char aaaa1() const
|
char aaaa1() const
|
||||||
{ return _cstr[1]; }
|
{ return _cstr[1]; }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine two tokens that belong to each other.
|
* Combine two tokens that belong to each other.
|
||||||
* Ex: "<" and "=" may become "<="
|
* Ex: "<" and "=" may become "<="
|
||||||
*/
|
*/
|
||||||
void combineWithNext(const char str1[], const char str2[]);
|
void combineWithNext(const char str1[], const char str2[]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlink and delete next token.
|
* Unlink and delete next token.
|
||||||
*/
|
*/
|
||||||
void deleteNext();
|
void deleteNext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns token in given index, related to this token.
|
* Returns token in given index, related to this token.
|
||||||
* For example index 1 would return next token, and 2
|
* For example index 1 would return next token, and 2
|
||||||
* would return next from that one.
|
* would return next from that one.
|
||||||
*/
|
*/
|
||||||
const TOKEN *tokAt(int index) const;
|
const TOKEN *tokAt(int index) const;
|
||||||
|
|
||||||
const char *strAt(int index) const;
|
const char *strAt(int index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Match given token (or list of tokens) to a pattern list.
|
* Match given token (or list of tokens) to a pattern list.
|
||||||
*
|
*
|
||||||
* Possible patterns
|
* Possible patterns
|
||||||
* "%any%" any token
|
* "%any%" any token
|
||||||
* "%var%" any token which is a name or type e.g. "hello" or "int"
|
* "%var%" any token which is a name or type e.g. "hello" or "int"
|
||||||
* "%num%" Any numeric token, e.g. "23"
|
* "%num%" Any numeric token, e.g. "23"
|
||||||
* "%str%" Any token starting with "-character (C-string).
|
* "%str%" Any token starting with "-character (C-string).
|
||||||
* "[abc]" Any of the characters 'a' or 'b' or 'c'
|
* "[abc]" Any of the characters 'a' or 'b' or 'c'
|
||||||
* "int|void|char" Any of the strings, int, void or char
|
* "int|void|char" Any of the strings, int, void or char
|
||||||
* "int|void|char|" Any of the strings, int, void or char or empty string
|
* "int|void|char|" Any of the strings, int, void or char or empty string
|
||||||
* "someRandomText" If token contains "someRandomText".
|
* "someRandomText" If token contains "someRandomText".
|
||||||
*
|
*
|
||||||
* The patterns can be also combined to compare to multiple tokens at once
|
* The patterns can be also combined to compare to multiple tokens at once
|
||||||
* by separating tokens with a space, e.g.
|
* by separating tokens with a space, e.g.
|
||||||
* ") const|void {" will return true if first token is ')' next token is either
|
* ") const|void {" will return true if first token is ')' next token is either
|
||||||
* "const" or "void" and token after that is '{'. If even one of the tokens does not
|
* "const" or "void" and token after that is '{'. If even one of the tokens does not
|
||||||
* match its pattern, false is returned.
|
* match its pattern, false is returned.
|
||||||
*
|
*
|
||||||
* @param tok List of tokens to be compared to the pattern
|
* @param tok List of tokens to be compared to the pattern
|
||||||
* @param pattern The pattern where tokens are compared, e.g. "const"
|
* @param pattern The pattern where tokens are compared, e.g. "const"
|
||||||
* or ") const|volatile| {".
|
* or ") const|volatile| {".
|
||||||
* @param varname1 Used with pattern "%var1%" and "%var2%"
|
* @param varname1 Used with pattern "%var1%" and "%var2%"
|
||||||
* @param varname2 Used with pattern "%var1%" and "%var2%"
|
* @param varname2 Used with pattern "%var1%" and "%var2%"
|
||||||
* @return true if given token matches with given pattern
|
* @return true if given token matches with given pattern
|
||||||
* false if given token does not match with given pattern
|
* false if given token does not match with given pattern
|
||||||
*/
|
*/
|
||||||
static bool Match(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0);
|
static bool Match(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0);
|
||||||
|
|
||||||
bool isName() const;
|
bool isName() const;
|
||||||
bool isNumber() const;
|
bool isNumber() const;
|
||||||
bool isStandardType() const;
|
bool isStandardType() const;
|
||||||
static const TOKEN *findmatch(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0);
|
static const TOKEN *findmatch(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0);
|
||||||
static const TOKEN *findtoken(const TOKEN *tok1, const char *tokenstr[]);
|
static const TOKEN *findtoken(const TOKEN *tok1, const char *tokenstr[]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Needle is build from multiple alternatives. If one of
|
* Needle is build from multiple alternatives. If one of
|
||||||
* them is equal to haystack, return value is 1. If there
|
* them is equal to haystack, return value is 1. If there
|
||||||
* are no matches, but one alternative to needle is empty
|
* are no matches, but one alternative to needle is empty
|
||||||
* string, return value is 0. If needle was not found, return
|
* string, return value is 0. If needle was not found, return
|
||||||
* value is -1.
|
* value is -1.
|
||||||
*
|
*
|
||||||
* @param needle e.g. "one|two" or "|one|two"
|
* @param needle e.g. "one|two" or "|one|two"
|
||||||
* @param haystack e.g. "one", "two" or "invalid"
|
* @param haystack e.g. "one", "two" or "invalid"
|
||||||
* @return 1 if needle is found from the haystack
|
* @return 1 if needle is found from the haystack
|
||||||
* 0 if needle was empty string
|
* 0 if needle was empty string
|
||||||
* -1 if needle was not found
|
* -1 if needle was not found
|
||||||
*/
|
*/
|
||||||
static int multiCompare( const char *needle, const char *haystack );
|
static int multiCompare( const char *needle, const char *haystack );
|
||||||
|
|
||||||
|
|
||||||
unsigned int linenr() const;
|
unsigned int linenr() const;
|
||||||
void linenr( unsigned int linenr );
|
void linenr( unsigned int linenr );
|
||||||
|
|
||||||
unsigned int fileIndex() const;
|
unsigned int fileIndex() const;
|
||||||
void fileIndex( unsigned int fileIndex );
|
void fileIndex( unsigned int fileIndex );
|
||||||
|
|
||||||
TOKEN *next() const;
|
TOKEN *next() const;
|
||||||
void next( TOKEN *next );
|
void next( TOKEN *next );
|
||||||
|
|
||||||
unsigned int varId() const;
|
unsigned int varId() const;
|
||||||
void varId( unsigned int id );
|
void varId( unsigned int id );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _str;
|
std::string _str;
|
||||||
char * _cstr;
|
char * _cstr;
|
||||||
bool _isName;
|
bool _isName;
|
||||||
bool _isNumber;
|
bool _isNumber;
|
||||||
unsigned int _varId;
|
unsigned int _varId;
|
||||||
TOKEN *_next;
|
TOKEN *_next;
|
||||||
unsigned int _fileIndex;
|
unsigned int _fileIndex;
|
||||||
unsigned int _linenr;
|
unsigned int _linenr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TOKEN_H
|
#endif // TOKEN_H
|
||||||
|
|
250
tokenize.cpp
250
tokenize.cpp
|
@ -72,8 +72,8 @@ TOKEN *Tokenizer::_gettok(TOKEN *tok, int index)
|
||||||
index--;
|
index--;
|
||||||
}
|
}
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
const TOKEN *Tokenizer::tokens() const
|
const TOKEN *Tokenizer::tokens() const
|
||||||
|
@ -454,9 +454,9 @@ void Tokenizer::tokenizeCode(std::istream &code, const unsigned int FileIndex)
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Append token..
|
// Append token..
|
||||||
CurrentToken += c;
|
CurrentToken += c;
|
||||||
|
|
||||||
if ( c == '\n' )
|
if ( c == '\n' )
|
||||||
++lineno;
|
++lineno;
|
||||||
|
|
||||||
// Special sequence '\.'
|
// Special sequence '\.'
|
||||||
|
@ -599,77 +599,77 @@ void Tokenizer::tokenizeCode(std::istream &code, const unsigned int FileIndex)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove "volatile"
|
// Remove "volatile"
|
||||||
while ( TOKEN::Match(_tokens, "volatile") )
|
while ( TOKEN::Match(_tokens, "volatile") )
|
||||||
{
|
{
|
||||||
TOKEN *tok = _tokens;
|
TOKEN *tok = _tokens;
|
||||||
_tokens = _tokens->next();
|
_tokens = _tokens->next();
|
||||||
delete tok;
|
delete tok;
|
||||||
}
|
}
|
||||||
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
||||||
{
|
{
|
||||||
while ( TOKEN::Match(tok->next(), "volatile") )
|
while ( TOKEN::Match(tok->next(), "volatile") )
|
||||||
{
|
{
|
||||||
tok->deleteNext();
|
tok->deleteNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
void Tokenizer::setVarId()
|
void Tokenizer::setVarId()
|
||||||
{
|
{
|
||||||
// Clear all variable ids
|
// Clear all variable ids
|
||||||
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
||||||
tok->varId( 0 );
|
tok->varId( 0 );
|
||||||
|
|
||||||
// Set variable ids..
|
// Set variable ids..
|
||||||
unsigned int _varId = 0;
|
unsigned int _varId = 0;
|
||||||
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
||||||
{
|
{
|
||||||
if ( ! TOKEN::Match(tok, "[;{}(] %type% %var%") )
|
if ( ! TOKEN::Match(tok, "[;{}(] %type% %var%") )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Determine name of declared variable..
|
// Determine name of declared variable..
|
||||||
const char *varname = 0;
|
const char *varname = 0;
|
||||||
TOKEN *tok2 = tok->next();
|
TOKEN *tok2 = tok->next();
|
||||||
while ( ! TOKEN::Match( tok2, "[;[=(]" ) )
|
while ( ! TOKEN::Match( tok2, "[;[=(]" ) )
|
||||||
{
|
{
|
||||||
if ( tok2->isName() )
|
if ( tok2->isName() )
|
||||||
varname = tok2->strAt(0);
|
varname = tok2->strAt(0);
|
||||||
else if ( tok2->str() != "*" )
|
else if ( tok2->str() != "*" )
|
||||||
break;
|
break;
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variable declaration found => Set variable ids
|
// Variable declaration found => Set variable ids
|
||||||
if ( TOKEN::Match(tok2, "[;[=]") && varname )
|
if ( TOKEN::Match(tok2, "[;[=]") && varname )
|
||||||
{
|
{
|
||||||
++_varId;
|
++_varId;
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
int parlevel = 0;
|
int parlevel = 0;
|
||||||
for ( tok2 = tok->next(); tok2 && indentlevel >= 0; tok2 = tok2->next() )
|
for ( tok2 = tok->next(); tok2 && indentlevel >= 0; tok2 = tok2->next() )
|
||||||
{
|
{
|
||||||
if ( tok2->str() == varname )
|
if ( tok2->str() == varname )
|
||||||
tok2->varId( _varId );
|
tok2->varId( _varId );
|
||||||
else if ( tok2->str() == "{" )
|
else if ( tok2->str() == "{" )
|
||||||
++indentlevel;
|
++indentlevel;
|
||||||
else if ( tok2->str() == "}" )
|
else if ( tok2->str() == "}" )
|
||||||
--indentlevel;
|
--indentlevel;
|
||||||
else if ( tok2->str() == "(" )
|
else if ( tok2->str() == "(" )
|
||||||
++parlevel;
|
++parlevel;
|
||||||
else if ( tok2->str() == ")" )
|
else if ( tok2->str() == ")" )
|
||||||
--parlevel;
|
--parlevel;
|
||||||
else if ( parlevel < 0 && tok2->str() == ";" )
|
else if ( parlevel < 0 && tok2->str() == ";" )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Simplify token list
|
// Simplify token list
|
||||||
|
@ -682,7 +682,7 @@ void Tokenizer::simplifyTokenList()
|
||||||
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
for ( TOKEN *tok = _tokens; tok; tok = tok->next() )
|
||||||
{
|
{
|
||||||
if (tok->next() && (tok->next()->str() == "unsigned"))
|
if (tok->next() && (tok->next()->str() == "unsigned"))
|
||||||
{
|
{
|
||||||
tok->deleteNext();
|
tok->deleteNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -834,7 +834,7 @@ void Tokenizer::simplifyTokenList()
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (1-2)
|
// (1-2)
|
||||||
if (TOKEN::Match(tok, "[[,(=<>] %num% [+-*/] %num% [],);=<>]"))
|
if (TOKEN::Match(tok, "[[,(=<>] %num% [+-*/] %num% [],);=<>]"))
|
||||||
{
|
{
|
||||||
int i1 = atoi(tok->strAt(1));
|
int i1 = atoi(tok->strAt(1));
|
||||||
|
@ -911,20 +911,20 @@ void Tokenizer::simplifyTokenList()
|
||||||
unsigned int typelen = 0;
|
unsigned int typelen = 0;
|
||||||
|
|
||||||
if ( TOKEN::Match(type0, "%type% %var% ,|=") )
|
if ( TOKEN::Match(type0, "%type% %var% ,|=") )
|
||||||
{
|
{
|
||||||
if ( type0->next()->str() != "operator" )
|
if ( type0->next()->str() != "operator" )
|
||||||
{
|
{
|
||||||
tok2 = _gettok(type0, 2); // The ',' or '=' token
|
tok2 = _gettok(type0, 2); // The ',' or '=' token
|
||||||
typelen = 1;
|
typelen = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( TOKEN::Match(type0, "%type% * %var% ,|=") )
|
else if ( TOKEN::Match(type0, "%type% * %var% ,|=") )
|
||||||
{
|
{
|
||||||
if ( type0->next()->next()->str() != "operator" )
|
if ( type0->next()->next()->str() != "operator" )
|
||||||
{
|
{
|
||||||
tok2 = _gettok(type0, 3); // The ',' token
|
tok2 = _gettok(type0, 3); // The ',' token
|
||||||
typelen = 1;
|
typelen = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,42 +1058,42 @@ bool Tokenizer::simplifyConditions()
|
||||||
{
|
{
|
||||||
tok->next()->setstr((tok->next()->str() != "0") ? "true" : "false");
|
tok->next()->setstr((tok->next()->str() != "0") ? "true" : "false");
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce "(%num% == %num%)" => "(true)"/"(false)"
|
// Reduce "(%num% == %num%)" => "(true)"/"(false)"
|
||||||
if ( (TOKEN::Match(tok, "&&") || TOKEN::Match(tok, "||") || TOKEN::Match(tok, "(")) &&
|
if ( (TOKEN::Match(tok, "&&") || TOKEN::Match(tok, "||") || TOKEN::Match(tok, "(")) &&
|
||||||
TOKEN::Match(tok->tokAt(1), "%num% %any% %num%") &&
|
TOKEN::Match(tok->tokAt(1), "%num% %any% %num%") &&
|
||||||
(TOKEN::Match(tok->tokAt(4), "&&") || TOKEN::Match(tok->tokAt(4), "||") || TOKEN::Match(tok->tokAt(4), ")")) )
|
(TOKEN::Match(tok->tokAt(4), "&&") || TOKEN::Match(tok->tokAt(4), "||") || TOKEN::Match(tok->tokAt(4), ")")) )
|
||||||
{
|
{
|
||||||
double op1 = (strstr(tok->strAt(1), "0x")) ? strtol(tok->strAt(1),0,16) : atof( tok->strAt(1) );
|
double op1 = (strstr(tok->strAt(1), "0x")) ? strtol(tok->strAt(1),0,16) : atof( tok->strAt(1) );
|
||||||
double op2 = (strstr(tok->strAt(3), "0x")) ? strtol(tok->strAt(3),0,16) : atof( tok->strAt(3) );
|
double op2 = (strstr(tok->strAt(3), "0x")) ? strtol(tok->strAt(3),0,16) : atof( tok->strAt(3) );
|
||||||
std::string cmp = tok->strAt(2);
|
std::string cmp = tok->strAt(2);
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if ( cmp == "==" )
|
if ( cmp == "==" )
|
||||||
result = (op1 == op2);
|
result = (op1 == op2);
|
||||||
else if ( cmp == "!=" )
|
else if ( cmp == "!=" )
|
||||||
result = (op1 != op2);
|
result = (op1 != op2);
|
||||||
else if ( cmp == ">=" )
|
else if ( cmp == ">=" )
|
||||||
result = (op1 >= op2);
|
result = (op1 >= op2);
|
||||||
else if ( cmp == ">" )
|
else if ( cmp == ">" )
|
||||||
result = (op1 > op2);
|
result = (op1 > op2);
|
||||||
else if ( cmp == "<=" )
|
else if ( cmp == "<=" )
|
||||||
result = (op1 <= op2);
|
result = (op1 <= op2);
|
||||||
else if ( cmp == "<" )
|
else if ( cmp == "<" )
|
||||||
result = (op1 < op2);
|
result = (op1 < op2);
|
||||||
else
|
else
|
||||||
cmp = "";
|
cmp = "";
|
||||||
|
|
||||||
if ( ! cmp.empty() )
|
if ( ! cmp.empty() )
|
||||||
{
|
{
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
tok->deleteNext();
|
tok->deleteNext();
|
||||||
tok->deleteNext();
|
tok->deleteNext();
|
||||||
|
|
||||||
tok->setstr( result ? "true" : "false" );
|
tok->setstr( result ? "true" : "false" );
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1169,12 +1169,12 @@ void Tokenizer::fillFunctionList()
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( tok2->str() == ")" )
|
else if ( tok2->str() == ")" )
|
||||||
{
|
{
|
||||||
if ( TOKEN::Match(tok2, ") const| {") )
|
if ( TOKEN::Match(tok2, ") const| {") )
|
||||||
{
|
{
|
||||||
_functionList.push_back( tok );
|
_functionList.push_back( tok );
|
||||||
tok = tok2;
|
tok = tok2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tok = tok2;
|
tok = tok2;
|
||||||
|
@ -1190,7 +1190,7 @@ void Tokenizer::fillFunctionList()
|
||||||
// If the _functionList functions with duplicate names, remove them
|
// If the _functionList functions with duplicate names, remove them
|
||||||
// TODO this will need some better handling
|
// TODO this will need some better handling
|
||||||
for ( unsigned int func1 = 0; func1 < _functionList.size(); )
|
for ( unsigned int func1 = 0; func1 < _functionList.size(); )
|
||||||
{
|
{
|
||||||
bool hasDuplicates = false;
|
bool hasDuplicates = false;
|
||||||
for ( unsigned int func2 = func1 + 1; func2 < _functionList.size(); )
|
for ( unsigned int func2 = func1 + 1; func2 < _functionList.size(); )
|
||||||
{
|
{
|
||||||
|
@ -1213,7 +1213,7 @@ void Tokenizer::fillFunctionList()
|
||||||
{
|
{
|
||||||
_functionList.erase( _functionList.begin() + func1 );
|
_functionList.erase( _functionList.begin() + func1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -1245,7 +1245,7 @@ void Tokenizer::deleteTokens(TOKEN *tok)
|
||||||
delete tok;
|
delete tok;
|
||||||
tok = next;
|
tok = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
30
tokenize.h
30
tokenize.h
|
@ -26,7 +26,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "errorlogger.h"
|
#include "errorlogger.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
|
||||||
class Tokenizer
|
class Tokenizer
|
||||||
|
@ -35,23 +35,23 @@ private:
|
||||||
// Deallocate lists..
|
// Deallocate lists..
|
||||||
void DeallocateTokens();
|
void DeallocateTokens();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for "tokenize". This recursively parses into included header files.
|
* Helper function for "tokenize". This recursively parses into included header files.
|
||||||
*/
|
*/
|
||||||
void tokenizeCode(std::istream &code, const unsigned int FileIndex=0);
|
void tokenizeCode(std::istream &code, const unsigned int FileIndex=0);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Tokenizer();
|
Tokenizer();
|
||||||
~Tokenizer();
|
~Tokenizer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tokenize code
|
* Tokenize code
|
||||||
* @param code input stream for code
|
* @param code input stream for code
|
||||||
* @param FileName The filename
|
* @param FileName The filename
|
||||||
*/
|
*/
|
||||||
void tokenize(std::istream &code, const char FileName[]);
|
void tokenize(std::istream &code, const char FileName[]);
|
||||||
|
|
||||||
/** Set variable id */
|
/** Set variable id */
|
||||||
void setVarId();
|
void setVarId();
|
||||||
|
|
||||||
/** Simplify tokenlist */
|
/** Simplify tokenlist */
|
||||||
|
@ -110,4 +110,4 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue