Revert revisions 627 and 628

This commit is contained in:
Nicolas Le Cam 2008-12-08 23:41:34 +00:00
parent e8d2c7cfb3
commit eb80c9786f
36 changed files with 2439 additions and 2439 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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() );
} }

View File

@ -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();
} }

View File

@ -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;

View File

@ -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| {" );
} }
} }

View File

@ -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[] );

View File

@ -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" );

View File

@ -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
}; };

View File

@ -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.
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View File

@ -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..

View File

@ -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;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -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()
{ {
} }

View File

@ -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

View File

@ -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();

View File

@ -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() );
} }
}; };

View File

@ -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() );
} }
}; };

View File

@ -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() );
} }
}; };

View File

@ -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..

View File

@ -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;
} }

View File

@ -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 )

View File

@ -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
} }

View File

@ -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() { }

View File

@ -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() );
} }
} }
}; };

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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;
} }
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -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