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 "preprocessor.h" // preprocessor.
#include "tokenize.h" // <- Tokenizer
#include "CheckMemoryLeak.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()
@ -53,6 +51,8 @@ void CppCheck::check(int argc, char* argv[])
std::vector<std::string> pathnames;
bool Recursive = false;
Settings _settings;
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i],"--debug") == 0)
@ -76,8 +76,6 @@ void CppCheck::check(int argc, char* argv[])
pathnames.push_back( argv[i] );
}
_tokenizer.settings( _settings );
std::vector<std::string> filenames;
// --recursive was used
if ( Recursive )
@ -140,7 +138,7 @@ void CppCheck::check(int argc, char* argv[])
Preprocessor preprocessor( this );
preprocessor.preprocess(fin, code, fname);
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)
{
@ -164,7 +162,7 @@ void CppCheck::check(int argc, char* argv[])
{
errout.str("");
std::cout << "Checking usage of global functions (this may take several minutes)..\n";
_tokenizer.CheckGlobalFunctionUsage(filenames);
//_tokenizer.CheckGlobalFunctionUsage(filenames);
if ( ! errout.str().empty() )
{
std::cerr << "\n";
@ -179,8 +177,11 @@ void CppCheck::check(int argc, char* argv[])
// 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
{
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
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)
{
/*
std::string message = _tokenizer.fileLine( token ) + errmsg;
reportErr( message );
*/
reportErr( errmsg );
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,12 +48,11 @@
//---------------------------------------------------------------------------
Tokenizer::Tokenizer(ErrorLogger *errorLogger)
Tokenizer::Tokenizer()
{
_tokens = 0;
tokens_back = 0;
dsymlist = 0;
_errorLogger = errorLogger;
}
Tokenizer::~Tokenizer()
@ -1155,12 +1154,6 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
{
FunctionList.clear();
std::list<const char *> _usedfunc;
if ( file_id == 0 )
{
GlobalFunctions.clear();
}
bool staticfunc = false;
bool classfunc = false;
@ -1173,23 +1166,8 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
else if ( tok->str[0] == '}' )
indentlevel--;
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;
}
@ -1222,8 +1200,6 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
{
if ( Tokenizer::Match(tok2, ") {") )
{
if (_settings._checkCodingStyle && !staticfunc && !classfunc && tok->FileIndex==0)
GlobalFunctions.push_back( GlobalFunction(file_id, tok->str) );
FunctionList.push_back( tok );
tok = tok2;
}
@ -1266,87 +1242,8 @@ void Tokenizer::FillFunctionList(const unsigned int file_id)
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 )

View File

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