Check Function Usage: Removed much of the old checking and made some refactoring

This commit is contained in:
Daniel Marjamäki 2008-11-22 19:39:12 +00:00
parent 6687bc7b9a
commit 07b5ebe72b
15 changed files with 45 additions and 168 deletions

View File

@ -18,6 +18,7 @@
#include "cppcheck.h" #include "cppcheck.h"
#include "preprocessor.h" // preprocessor. #include "preprocessor.h" // preprocessor.
#include "tokenize.h" // <- Tokenizer
#include "CheckMemoryLeak.h" #include "CheckMemoryLeak.h"
#include "CheckBufferOverrun.h" #include "CheckBufferOverrun.h"
@ -35,12 +36,9 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
CppCheck::CppCheck() : _tokenizer( this ) CppCheck::CppCheck()
{ {
_settings._debug = false;
_settings._showAll = false;
_settings._checkCodingStyle = false;
_settings._errorsOnly = false;
} }
CppCheck::~CppCheck() CppCheck::~CppCheck()
@ -53,6 +51,8 @@ void CppCheck::check(int argc, char* argv[])
std::vector<std::string> pathnames; std::vector<std::string> pathnames;
bool Recursive = false; bool Recursive = false;
Settings _settings;
for (int i = 1; i < argc; i++) for (int i = 1; i < argc; i++)
{ {
if (strcmp(argv[i],"--debug") == 0) if (strcmp(argv[i],"--debug") == 0)
@ -76,8 +76,6 @@ void CppCheck::check(int argc, char* argv[])
pathnames.push_back( argv[i] ); pathnames.push_back( argv[i] );
} }
_tokenizer.settings( _settings );
std::vector<std::string> filenames; std::vector<std::string> filenames;
// --recursive was used // --recursive was used
if ( Recursive ) if ( Recursive )
@ -140,7 +138,7 @@ void CppCheck::check(int argc, char* argv[])
Preprocessor preprocessor( this ); Preprocessor preprocessor( this );
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 )
checkFile(it->second, filenames[c].c_str(), c); checkFile(it->second, filenames[c].c_str(), c, _settings);
if (_settings._errorsOnly) if (_settings._errorsOnly)
{ {
@ -164,7 +162,7 @@ void CppCheck::check(int argc, char* argv[])
{ {
errout.str(""); errout.str("");
std::cout << "Checking usage of global functions (this may take several minutes)..\n"; std::cout << "Checking usage of global functions (this may take several minutes)..\n";
_tokenizer.CheckGlobalFunctionUsage(filenames); //_tokenizer.CheckGlobalFunctionUsage(filenames);
if ( ! errout.str().empty() ) if ( ! errout.str().empty() )
{ {
std::cerr << "\n"; std::cerr << "\n";
@ -179,8 +177,11 @@ void CppCheck::check(int argc, char* argv[])
// 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[], unsigned int FileId) void CppCheck::checkFile(const std::string &code, const char FileName[], unsigned int FileId, Settings &_settings)
{ {
Tokenizer _tokenizer;
_tokenizer.settings( _settings );
// Tokenize the file // Tokenize the file
{ {
std::istringstream istr(code); std::istringstream istr(code);
@ -288,10 +289,6 @@ void CppCheck::checkFile(const std::string &code, const char FileName[], unsigne
// mean that an ';' has been added by accident // mean that an ';' has been added by accident
checkOther.CheckIncompleteStatement(); checkOther.CheckIncompleteStatement();
} }
// Clean up tokens..
_tokenizer.DeallocateTokens();
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -308,6 +305,12 @@ void CppCheck::reportErr( const std::string &errmsg)
void CppCheck::reportErr( const TOKEN *token, const std::string &errmsg) void CppCheck::reportErr( const TOKEN *token, const std::string &errmsg)
{ {
/*
std::string message = _tokenizer.fileLine( token ) + errmsg; std::string message = _tokenizer.fileLine( token ) + errmsg;
reportErr( message ); reportErr( message );
*/
reportErr( errmsg );
} }

View File

@ -23,7 +23,6 @@
#include <list> #include <list>
#include <sstream> #include <sstream>
#include "settings.h" #include "settings.h"
#include "tokenize.h" // <- Tokenizer
#include "errorlogger.h" #include "errorlogger.h"
/** /**
@ -38,15 +37,13 @@ class CppCheck : public ErrorLogger
virtual ~CppCheck(); virtual ~CppCheck();
void check(int argc, char* argv[]); void check(int argc, char* argv[]);
virtual void reportErr( const TOKEN *token, const std::string &errmsg);
virtual void reportErr( const std::string &errmsg);
private: private:
void checkFile(const std::string &code, const char FileName[], unsigned int FileId); void checkFile(const std::string &code, const char FileName[], unsigned int FileId, Settings &_settings);
Settings _settings;
Tokenizer _tokenizer;
std::list<std::string> _errorList; std::list<std::string> _errorList;
std::ostringstream errout; std::ostringstream errout;
void reportErr( const std::string &errmsg);
void reportErr( const TOKEN *token, const std::string &errmsg);
}; };
#endif // CPPCHECK_H #endif // CPPCHECK_H

View File

@ -39,7 +39,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -43,7 +43,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -37,7 +37,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -39,7 +39,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -38,7 +38,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -37,7 +37,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -23,6 +23,8 @@
<Unit filename="CheckBufferOverrun.h" /> <Unit filename="CheckBufferOverrun.h" />
<Unit filename="CheckClass.cpp" /> <Unit filename="CheckClass.cpp" />
<Unit filename="CheckClass.h" /> <Unit filename="CheckClass.h" />
<Unit filename="CheckFunctionUsage.cpp" />
<Unit filename="CheckFunctionUsage.h" />
<Unit filename="CheckHeaders.cpp" /> <Unit filename="CheckHeaders.cpp" />
<Unit filename="CheckHeaders.h" /> <Unit filename="CheckHeaders.h" />
<Unit filename="CheckMemoryLeak.cpp" /> <Unit filename="CheckMemoryLeak.cpp" />
@ -35,6 +37,7 @@
<Unit filename="FileLister.h" /> <Unit filename="FileLister.h" />
<Unit filename="cppcheck.cpp" /> <Unit filename="cppcheck.cpp" />
<Unit filename="cppcheck.h" /> <Unit filename="cppcheck.h" />
<Unit filename="errorlogger.h" />
<Unit filename="preprocessor.cpp" /> <Unit filename="preprocessor.cpp" />
<Unit filename="preprocessor.h" /> <Unit filename="preprocessor.h" />
<Unit filename="settings.cpp" /> <Unit filename="settings.cpp" />

View File

@ -42,7 +42,7 @@ private:
std::string tok(const char code[]) std::string tok(const char code[])
{ {
std::istringstream istr(code); std::istringstream istr(code);
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );
tokenizer.SimplifyTokenList(); tokenizer.SimplifyTokenList();

View File

@ -65,7 +65,7 @@ private:
" \"def\"\n"; " \"def\"\n";
// tokenize.. // tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(filedata); std::istringstream istr(filedata);
tokenizer.TokenizeCode(istr, 0); tokenizer.TokenizeCode(istr, 0);
@ -89,7 +89,7 @@ private:
std::string filedata(10000,'a'); std::string filedata(10000,'a');
// tokenize.. // tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(filedata); std::istringstream istr(filedata);
tokenizer.TokenizeCode(istr, 0); tokenizer.TokenizeCode(istr, 0);
@ -111,7 +111,7 @@ private:
"}\n"; "}\n";
// tokenize.. // tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(filedata); std::istringstream istr(filedata);
tokenizer.TokenizeCode(istr, 0); tokenizer.TokenizeCode(istr, 0);
@ -142,7 +142,7 @@ private:
"void b()\n" "void b()\n"
"{ }\n"; "{ }\n";
// tokenize.. // tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode(istr, 0); tokenizer.TokenizeCode(istr, 0);

View File

@ -44,7 +44,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -37,7 +37,7 @@ private:
void check( const char code[] ) void check( const char code[] )
{ {
// Tokenize.. // Tokenize..
Tokenizer tokenizer( this ); Tokenizer tokenizer;
tokenizer.getFiles()->push_back( "test.cpp" ); tokenizer.getFiles()->push_back( "test.cpp" );
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode( istr ); tokenizer.TokenizeCode( istr );

View File

@ -48,12 +48,11 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
Tokenizer::Tokenizer(ErrorLogger *errorLogger) Tokenizer::Tokenizer()
{ {
_tokens = 0; _tokens = 0;
tokens_back = 0; tokens_back = 0;
dsymlist = 0; dsymlist = 0;
_errorLogger = errorLogger;
} }
Tokenizer::~Tokenizer() Tokenizer::~Tokenizer()
@ -1155,12 +1154,6 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
{ {
FunctionList.clear(); FunctionList.clear();
std::list<const char *> _usedfunc;
if ( file_id == 0 )
{
GlobalFunctions.clear();
}
bool staticfunc = false; bool staticfunc = false;
bool classfunc = false; bool classfunc = false;
@ -1173,23 +1166,8 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
else if ( tok->str[0] == '}' ) else if ( tok->str[0] == '}' )
indentlevel--; indentlevel--;
if (indentlevel > 0) if (indentlevel > 0)
{ {
if ( _settings._checkCodingStyle )
{
const char *funcname = 0;
if ( Tokenizer::Match(tok,"%var% (") )
funcname = tok->str;
else if ( Tokenizer::Match(tok, "= %var% ;") ||
Tokenizer::Match(tok, "= %var% ,") )
funcname = tok->next->str;
if ( std::find(_usedfunc.begin(), _usedfunc.end(), funcname) == _usedfunc.end() )
_usedfunc.push_back( funcname );
}
continue; continue;
} }
@ -1222,8 +1200,6 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
{ {
if ( Tokenizer::Match(tok2, ") {") ) if ( Tokenizer::Match(tok2, ") {") )
{ {
if (_settings._checkCodingStyle && !staticfunc && !classfunc && tok->FileIndex==0)
GlobalFunctions.push_back( GlobalFunction(file_id, tok->str) );
FunctionList.push_back( tok ); FunctionList.push_back( tok );
tok = tok2; tok = tok2;
} }
@ -1266,87 +1242,8 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
FunctionList.erase( FunctionList.begin() + func1 ); FunctionList.erase( FunctionList.begin() + func1 );
} }
} }
for (std::list<const char *>::const_iterator it = _usedfunc.begin(); it != _usedfunc.end(); ++it)
{
if ( *it != 0 )
{
UsedGlobalFunctions.push_back( GlobalFunction(file_id, *it) );
}
}
} }
//--------------------------------------------------------------------------
void Tokenizer::CheckGlobalFunctionUsage(const std::vector<std::string> &filenames)
{
// Iterator for GlobalFunctions
std::list<GlobalFunction>::const_iterator func;
// Iterator for UsedGlobalFunctions
std::list<GlobalFunction>::const_iterator usedfunc;
unsigned int i1 = 0;
unsigned int i2 = 1;
// Check that every function in GlobalFunctions are used
for ( func = GlobalFunctions.begin(); func != GlobalFunctions.end(); func++ )
{
if ( GlobalFunctions.size() > 100 )
{
++i1;
if ( i1 > (i2 * GlobalFunctions.size()) / 100 )
{
if ( (i2 % 10) == 0 )
std::cout << i2 << "%";
else
std::cout << ".";
std::cout.flush();
++i2;
}
}
const std::string &funcname = func->name();
if ( funcname == "main" || funcname == "WinMain" )
continue;
// Check if this global function is used in any of the other files..
bool UsedOtherFile = false;
bool UsedAnyFile = false;
for ( usedfunc = UsedGlobalFunctions.begin(); usedfunc != UsedGlobalFunctions.end(); usedfunc++ )
{
if ( funcname == usedfunc->name() )
{
UsedAnyFile = true;
if (func->file_id() != usedfunc->file_id())
{
UsedOtherFile = true;
break;
}
}
}
if ( ! UsedAnyFile )
{
std::ostringstream errmsg;
errmsg << "[" << filenames[func->file_id()] << "]: "
<< "The function '" << func->name() << "' is never used.";
_errorLogger->reportErr( errmsg.str() );
}
else if ( ! UsedOtherFile )
{
std::ostringstream errmsg;
errmsg << "[" << filenames[func->file_id()] << "]: "
<< "The linkage of the function '" << func->name() << "' can be local (static) instead of global";
_errorLogger->reportErr( errmsg.str() );
}
}
std::cout << "\n";
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void Tokenizer::settings( const Settings &settings ) void Tokenizer::settings( const Settings &settings )

View File

@ -62,15 +62,16 @@ public:
class Tokenizer class Tokenizer
{ {
private:
// Deallocate lists..
void DeallocateTokens();
public: public:
Tokenizer(ErrorLogger *errorLogger); Tokenizer();
~Tokenizer(); ~Tokenizer();
void Tokenize(std::istream &code, const char FileName[]); void Tokenize(std::istream &code, const char FileName[]);
// Deallocate lists..
void DeallocateTokens();
// Simplify tokenlist // Simplify tokenlist
// ----------------------------- // -----------------------------
void SimplifyTokenList(); void SimplifyTokenList();
@ -99,16 +100,12 @@ public:
std::vector<std::string> *getFiles(); std::vector<std::string> *getFiles();
void FillFunctionList(const unsigned int file_id); void FillFunctionList(const unsigned int file_id);
const TOKEN *GetFunctionTokenByName( const char funcname[] ) const; const TOKEN *GetFunctionTokenByName( const char funcname[] ) const;
void CheckGlobalFunctionUsage(const std::vector<std::string> &filenames);
void settings( const Settings &settings ); void settings( const Settings &settings );
const TOKEN *tokens() const; const TOKEN *tokens() const;
#ifndef UNIT_TESTING #ifndef UNIT_TESTING
private: private:
#endif #endif
@ -120,23 +117,6 @@ private:
struct DefineSymbol *next; struct DefineSymbol *next;
}; };
class GlobalFunction
{
private:
unsigned int _FileId;
std::string _FuncName;
public:
GlobalFunction( const unsigned int FileId, const char FuncName[] )
{
_FileId = FileId;
_FuncName = FuncName;
}
unsigned int file_id() const { return _FileId; }
const std::string &name() const { return _FuncName; }
};
void Define(const char Name[], const char Value[]); void Define(const char Name[], const char Value[]);
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno); void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno);
@ -154,15 +134,12 @@ private:
TOKEN *tokens_back; TOKEN *tokens_back;
std::map<std::string, unsigned int> TypeSize; std::map<std::string, unsigned int> TypeSize;
std::vector<const TOKEN *> FunctionList; std::vector<const TOKEN *> FunctionList;
std::list< GlobalFunction > GlobalFunctions;
std::list< GlobalFunction > UsedGlobalFunctions;
std::vector<std::string> Files; std::vector<std::string> Files;
Settings _settings; Settings _settings;
struct DefineSymbol * dsymlist; struct DefineSymbol * dsymlist;
TOKEN *_tokens; TOKEN *_tokens;
ErrorLogger *_errorLogger;
}; };