Refactoring: The Tokenizer::FillFunctionList has no use of its parameter. Enabled the CheckFunctionUsage

This commit is contained in:
Daniel Marjamäki 2008-11-23 06:21:44 +00:00
parent b8c7543149
commit 0c9784fc0c
12 changed files with 179 additions and 171 deletions

View File

@ -19,7 +19,7 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "CheckFunctionUsage.h" #include "CheckFunctionUsage.h"
#include "tokenize.h" #include "tokenize.h"
#include <sstream> #include <sstream>
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -29,102 +29,109 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// FUNCTION USAGE - Check for unused functions etc // FUNCTION USAGE - Check for unused functions etc
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
CheckFunctionUsage::CheckFunctionUsage( const Tokenizer *tokenizer, ErrorLogger *errorLogger ) CheckFunctionUsage::CheckFunctionUsage( ErrorLogger *errorLogger )
{ {
_tokenizer = tokenizer; _errorLogger = errorLogger;
_errorLogger = errorLogger; functions.clear();
functions.clear(); }
}
CheckFunctionUsage::~CheckFunctionUsage()
CheckFunctionUsage::~CheckFunctionUsage() {
{
}
}
void CheckFunctionUsage::parseTokens( const Tokenizer &tokenizer )
void CheckFunctionUsage::parseTokens( const std::string &filename ) {
{ // Function declarations..
// Function declarations.. for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next )
for ( const TOKEN *tok = _tokenizer->tokens(); tok; tok = tok->next ) {
{ if ( tok->FileIndex != 0 )
if ( tok->FileIndex != 0 ) continue;
continue;
const TOKEN *funcname = 0;
const TOKEN *funcname = 0;
if ( TOKEN::Match( tok, "%type% %var% (" ) )
if ( TOKEN::Match( tok, "%type% %var% (" ) ) funcname = tok->at(1);
funcname = tok->at(1); else if ( TOKEN::Match(tok, "%type% * %var% (") )
else if ( TOKEN::Match(tok, "%type% * %var% (") ) funcname = tok->at(2);
funcname = tok->at(2);
// Check that ") {" is found..
if ( TOKEN::Match(funcname, "%var% ( )") || TOKEN::Match(funcname, "%var% ( %type%") ) for (const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next)
{ {
FunctionUsage &func = functions[ funcname->str ]; if ( TOKEN::Match(tok2, ")") )
{
// No filename set yet.. if ( ! TOKEN::Match(tok2, ") {") )
if (func.filename.empty()) funcname = NULL;
func.filename = filename; break;
}
// Multiple files => filename = "+" }
else if (func.filename != filename)
{ if ( TOKEN::Match(funcname, "%var% ( )") || TOKEN::Match(funcname, "%var% ( %type%") )
func.filename = "+"; {
func.usedOtherFile |= func.usedSameFile; FunctionUsage &func = functions[ funcname->str ];
}
} // No filename set yet..
} if (func.filename.empty())
func.filename = tokenizer.getFiles()->at(0);
// Function usage..
for ( const TOKEN *tok = _tokenizer->tokens(); tok; tok = tok->next ) // Multiple files => filename = "+"
{ else if (func.filename != tokenizer.getFiles()->at(0))
const TOKEN *funcname = 0; {
func.filename = "+";
if ( TOKEN::Match( tok, "[;{}.)[=] %var% (" ) ) func.usedOtherFile |= func.usedSameFile;
funcname = tok; }
}
else if ( TOKEN::Match(tok, "= %var% ;") ) }
funcname = tok->next;
// Function usage..
if ( funcname ) for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next )
{ {
FunctionUsage &func = functions[ funcname->str ]; const TOKEN *funcname = 0;
if ( func.filename.empty() || func.filename == "+" ) if ( TOKEN::Match( tok, "[;{}.,()[=] %var% [(),;]" ) )
func.usedOtherFile = true; funcname = tok->next;
else if ( funcname )
func.usedSameFile = true; {
} FunctionUsage &func = functions[ funcname->str ];
}
} if ( func.filename.empty() || func.filename == "+" )
func.usedOtherFile = true;
else
func.usedSameFile = true;
void CheckFunctionUsage::check() }
{ }
for ( std::map<std::string, FunctionUsage>::const_iterator it = functions.begin(); it != functions.end(); ++it ) }
{
const FunctionUsage &func = it->second;
if ( func.usedOtherFile || func.filename.empty() )
continue;
if ( ! func.usedSameFile ) void CheckFunctionUsage::check()
{ {
std::ostringstream errmsg; for ( std::map<std::string, FunctionUsage>::const_iterator it = functions.begin(); it != functions.end(); ++it )
errmsg << "The function '" << it->first << "' is never used."; {
_errorLogger->reportErr( errmsg.str() ); const FunctionUsage &func = it->second;
} if ( func.usedOtherFile || func.filename.empty() )
else if ( ! func.usedOtherFile ) continue;
{ if ( ! func.usedSameFile )
/* {
std::ostringstream errmsg; std::ostringstream errmsg;
errmsg << "The function '" << it->first << "' is only used in the file it was declared in so it should have local linkage."; errmsg << "The function '" << it->first << "' is never used.";
_errorLogger->reportErr( errmsg.str() ); _errorLogger->reportErr( errmsg.str() );
*/ }
} else if ( ! func.usedOtherFile )
} {
} /*
std::ostringstream errmsg;
errmsg << "The function '" << it->first << "' is only used in the file it was declared in so it should have local linkage.";
_errorLogger->reportErr( errmsg.str() );
*/
}
}
}

View File

@ -21,44 +21,43 @@
#ifndef CheckFunctionUsageH #ifndef CheckFunctionUsageH
#define CheckFunctionUsageH #define CheckFunctionUsageH
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "tokenize.h" #include "tokenize.h"
#include "errorlogger.h" #include "errorlogger.h"
class CheckFunctionUsage class CheckFunctionUsage
{ {
public: public:
CheckFunctionUsage( const Tokenizer *tokenizer, ErrorLogger *errorLogger ); CheckFunctionUsage( ErrorLogger *errorLogger );
~CheckFunctionUsage(); ~CheckFunctionUsage();
// Parse current tokens and determine.. // Parse current tokens and determine..
// * Check what functions are used // * Check what functions are used
// * What functions are declared // * What functions are declared
void parseTokens( const std::string &filename ); void parseTokens( const Tokenizer &tokenizer );
void check(); void check();
private: private:
const Tokenizer *_tokenizer; ErrorLogger *_errorLogger;
ErrorLogger *_errorLogger;
class FunctionUsage
class FunctionUsage {
{ public:
public: FunctionUsage()
FunctionUsage() {
{ filename = "";
filename = ""; usedOtherFile = false;
usedOtherFile = false; usedSameFile = false;
usedSameFile = false; }
}
std::string filename;
std::string filename; bool usedSameFile;
bool usedSameFile; bool usedOtherFile;
bool usedOtherFile; };
};
std::map<std::string, FunctionUsage> functions; std::map<std::string, FunctionUsage> functions;
}; };

View File

@ -25,6 +25,7 @@
#include "CheckClass.h" #include "CheckClass.h"
#include "CheckHeaders.h" #include "CheckHeaders.h"
#include "CheckOther.h" #include "CheckOther.h"
#include "CheckFunctionUsage.h"
#include "FileLister.h" #include "FileLister.h"
#include <algorithm> #include <algorithm>
@ -124,6 +125,11 @@ void CppCheck::check(int argc, char* argv[])
std::sort( filenames.begin(), filenames.end() ); std::sort( filenames.begin(), filenames.end() );
// Check function usage if "--recursive", "--style" and "--all" was given.
CheckFunctionUsage *checkFunctionUsage = NULL;
if ( Recursive && _settings._showAll && _settings._checkCodingStyle )
checkFunctionUsage = new CheckFunctionUsage( this );
for (unsigned int c = 0; c < filenames.size(); c++) for (unsigned int c = 0; c < filenames.size(); c++)
{ {
errout.str(""); errout.str("");
@ -138,7 +144,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, _settings); checkFile(it->second, filenames[c].c_str(), _settings, checkFunctionUsage);
if (_settings._errorsOnly) if (_settings._errorsOnly)
{ {
@ -158,11 +164,11 @@ void CppCheck::check(int argc, char* argv[])
} }
// This generates false positives - especially for libraries // This generates false positives - especially for libraries
if ( _settings._showAll && _settings._checkCodingStyle && filenames.size() > 1 ) if ( checkFunctionUsage )
{ {
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); checkFunctionUsage->check();
if ( ! errout.str().empty() ) if ( ! errout.str().empty() )
{ {
std::cerr << "\n"; std::cerr << "\n";
@ -170,6 +176,7 @@ void CppCheck::check(int argc, char* argv[])
} }
} }
delete checkFunctionUsage;
} }
@ -177,7 +184,7 @@ 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, Settings &_settings) void CppCheck::checkFile(const std::string &code, const char FileName[], Settings &_settings, CheckFunctionUsage *checkFunctionUsage)
{ {
Tokenizer _tokenizer; Tokenizer _tokenizer;
_tokenizer.settings( _settings ); _tokenizer.settings( _settings );
@ -188,7 +195,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[], unsigne
_tokenizer.Tokenize(istr, FileName); _tokenizer.Tokenize(istr, FileName);
} }
_tokenizer.FillFunctionList(FileId); _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.
@ -219,6 +226,10 @@ void CppCheck::checkFile(const std::string &code, const char FileName[], unsigne
_tokenizer.SimplifyTokenList(); _tokenizer.SimplifyTokenList();
if ( checkFunctionUsage )
checkFunctionUsage->parseTokens(_tokenizer);
// Memory leak // Memory leak
CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this ); CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this );
checkMemoryLeak.CheckMemoryLeak(); checkMemoryLeak.CheckMemoryLeak();

View File

@ -25,6 +25,8 @@
#include "settings.h" #include "settings.h"
#include "errorlogger.h" #include "errorlogger.h"
class CheckFunctionUsage;
/** /**
* 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
@ -38,7 +40,7 @@ class CppCheck : public ErrorLogger
void check(int argc, char* argv[]); void check(int argc, char* argv[]);
private: private:
void checkFile(const std::string &code, const char FileName[], unsigned int FileId, Settings &_settings); void checkFile(const std::string &code, const char FileName[], Settings &_settings, CheckFunctionUsage *checkFunctionUsage);
std::list<std::string> _errorList; std::list<std::string> _errorList;
std::ostringstream errout; std::ostringstream errout;

View File

@ -49,7 +49,7 @@ private:
Settings settings; Settings settings;
settings._checkCodingStyle = true; settings._checkCodingStyle = true;
tokenizer.settings( settings ); tokenizer.settings( settings );
tokenizer.FillFunctionList(0); tokenizer.FillFunctionList();
// Clear the error buffer.. // Clear the error buffer..
errout.str(""); errout.str("");

View File

@ -53,7 +53,7 @@ private:
Settings settings; Settings settings;
settings._checkCodingStyle = true; settings._checkCodingStyle = true;
tokenizer.settings( settings ); tokenizer.settings( settings );
tokenizer.FillFunctionList(0); tokenizer.FillFunctionList();
// Clear the error buffer.. // Clear the error buffer..
errout.str(""); errout.str("");

View File

@ -52,7 +52,7 @@ private:
settings._checkCodingStyle = true; settings._checkCodingStyle = true;
settings._showAll = false; settings._showAll = false;
tokenizer.settings( settings ); tokenizer.settings( settings );
tokenizer.FillFunctionList(0); tokenizer.FillFunctionList();
CheckMemoryLeakClass checkMemoryLeak( &tokenizer, settings, this ); CheckMemoryLeakClass checkMemoryLeak( &tokenizer, settings, this );
checkMemoryLeak.CheckMemoryLeak(); checkMemoryLeak.CheckMemoryLeak();
} }

View File

@ -31,8 +31,6 @@
<Unit filename="CheckMemoryLeak.h" /> <Unit filename="CheckMemoryLeak.h" />
<Unit filename="CheckOther.cpp" /> <Unit filename="CheckOther.cpp" />
<Unit filename="CheckOther.h" /> <Unit filename="CheckOther.h" />
<Unit filename="CommonCheck.cpp" />
<Unit filename="CommonCheck.h" />
<Unit filename="FileLister.cpp" /> <Unit filename="FileLister.cpp" />
<Unit filename="FileLister.h" /> <Unit filename="FileLister.h" />
<Unit filename="cppcheck.cpp" /> <Unit filename="cppcheck.cpp" />
@ -56,6 +54,8 @@
<Unit filename="testtokenize.cpp" /> <Unit filename="testtokenize.cpp" />
<Unit filename="testunusedprivfunc.cpp" /> <Unit filename="testunusedprivfunc.cpp" />
<Unit filename="testunusedvar.cpp" /> <Unit filename="testunusedvar.cpp" />
<Unit filename="token.cpp" />
<Unit filename="token.h" />
<Unit filename="tokenize.cpp" /> <Unit filename="tokenize.cpp" />
<Unit filename="tokenize.h" /> <Unit filename="tokenize.h" />
<Extensions> <Extensions>

View File

@ -48,11 +48,6 @@ public:
_tests.push_back( t ); _tests.push_back( t );
} }
void removeTest( TestFixture *t )
{
_tests.remove( t );
}
const std::list<TestFixture *> &tests() const const std::list<TestFixture *> &tests() const
{ {
return _tests; return _tests;
@ -74,12 +69,6 @@ TestFixture::TestFixture(const std::string &_name) : classname(_name)
TestRegistry::theInstance().addTest(this); TestRegistry::theInstance().addTest(this);
} }
/*
TestFixture::~TestFixture()
{
TestRegistry::theInstance().removeTest(this);
}
*/
bool TestFixture::runTest(const char testname[]) bool TestFixture::runTest(const char testname[])
{ {
@ -130,13 +119,13 @@ void TestFixture::runTests(const char cmd[])
} }
void TestFixture::reportErr( const std::string &errmsg) void TestFixture::reportErr( const std::string &errmsg)
{ {
errout << errmsg << std::endl; errout << errmsg << std::endl;
} }
void TestFixture::reportErr( const TOKEN *token, const std::string &errmsg) void TestFixture::reportErr( const TOKEN *token, const std::string &errmsg)
{ {
reportErr( errmsg ); reportErr( errmsg );
} }

View File

@ -146,7 +146,7 @@ private:
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.TokenizeCode(istr, 0); tokenizer.TokenizeCode(istr, 0);
tokenizer.FillFunctionList(0); tokenizer.FillFunctionList();
ASSERT_EQUALS( 1, tokenizer.FunctionList.size() ); ASSERT_EQUALS( 1, tokenizer.FunctionList.size() );
ASSERT_EQUALS( std::string("b"), tokenizer.FunctionList[0]->str ); ASSERT_EQUALS( std::string("b"), tokenizer.FunctionList[0]->str );

View File

@ -1032,7 +1032,7 @@ const TOKEN *Tokenizer::GetFunctionTokenByName( const char funcname[] ) const
} }
void Tokenizer::FillFunctionList(const unsigned int file_id) void Tokenizer::FillFunctionList()
{ {
FunctionList.clear(); FunctionList.clear();

View File

@ -64,7 +64,7 @@ public:
const std::vector<std::string> *getFiles() const; const std::vector<std::string> *getFiles() const;
void FillFunctionList(const unsigned int file_id); void FillFunctionList();
const TOKEN *GetFunctionTokenByName( const char funcname[] ) const; const TOKEN *GetFunctionTokenByName( const char funcname[] ) const;
void settings( const Settings &settings ); void settings( const Settings &settings );
const TOKEN *tokens() const; const TOKEN *tokens() const;