Added style checks to check for unused global functions

This commit is contained in:
Daniel Marjamäki 2008-03-29 09:44:23 +00:00
parent f8569f0db4
commit 69d33444d4
6 changed files with 141 additions and 13 deletions

View File

@ -6,9 +6,31 @@
#include <list>
#include <algorithm>
//---------------------------------------------------------------------------
extern bool CheckCodingStyle;
bool OnlyReportUniqueErrors;
std::ostringstream errout;
static std::list<const TOKEN *> FunctionList;
class clGlobalFunction
{
private:
unsigned int _FileId;
std::string _FuncName;
public:
clGlobalFunction( const unsigned int FileId, const char FuncName[] )
{
_FileId = FileId;
_FuncName = FuncName;
}
const unsigned int file_id() const { return _FileId; }
const std::string &name() const { return _FuncName; }
};
static std::list< clGlobalFunction > GlobalFunctions;
static std::list< clGlobalFunction > UsedGlobalFunctions;
//---------------------------------------------------------------------------
std::string FileLine(const TOKEN *tok)
@ -57,10 +79,19 @@ bool IsStandardType(const char str[])
}
//---------------------------------------------------------------------------
void FillFunctionList()
void 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;
int indentlevel = 0;
for ( const TOKEN *tok = tokens; tok; tok = tok->next )
{
@ -70,7 +101,35 @@ void FillFunctionList()
else if ( tok->str[0] == '}' )
indentlevel--;
else if (indentlevel==0 && Match(tok, "%var% ("))
if (indentlevel > 0)
{
if ( CheckCodingStyle )
{
const char *funcname = 0;
if ( Match(tok,"%var% (") )
funcname = tok->str;
else if ( Match(tok, "= %var% ;") )
funcname = tok->next->str;
if ( std::find(_usedfunc.begin(), _usedfunc.end(), funcname) == _usedfunc.end() )
_usedfunc.push_back( funcname );
}
continue;
}
if (strchr("};", tok->str[0]))
staticfunc = classfunc = false;
else if ( strcmp( tok->str, "static" ) == 0 )
staticfunc = true;
else if ( strcmp( tok->str, "::" ) == 0 )
classfunc = true;
else if (Match(tok, "%var% ("))
{
// Check if this is the first token of a function implementation..
for ( const TOKEN *tok2 = tok; tok2; tok2 = tok2->next )
@ -90,6 +149,8 @@ void FillFunctionList()
{
if ( Match(tok2, ") {") )
{
if (CheckCodingStyle && !staticfunc && !classfunc && tok->FileIndex==0)
GlobalFunctions.push_back( clGlobalFunction(file_id, tok->str) );
FunctionList.push_back( tok );
tok = tok2;
}
@ -104,6 +165,14 @@ void FillFunctionList()
}
}
}
for (std::list<const char *>::const_iterator it = _usedfunc.begin(); it != _usedfunc.end(); ++it)
{
if ( *it != 0 )
{
UsedGlobalFunctions.push_back( clGlobalFunction(file_id, *it) );
}
}
}
//---------------------------------------------------------------------------
@ -121,6 +190,50 @@ const TOKEN *GetFunctionTokenByName( const char funcname[] )
}
//---------------------------------------------------------------------------
void CheckGlobalFunctionUsage(const std::vector<std::string> &filenames)
{
// Iterator for GlobalFunctions
std::list<clGlobalFunction>::const_iterator func;
// Iterator for UsedGlobalFunctions
std::list<clGlobalFunction>::const_iterator usedfunc;
// Check that every function in GlobalFunctions are used
for ( func = GlobalFunctions.begin(); func != GlobalFunctions.end(); func++ )
{
if ( func->name() == "main" )
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 ( func->name() == usedfunc->name() )
{
UsedAnyFile = true;
UsedOtherFile |= (func->file_id() != usedfunc->file_id());
}
}
std::string file = "[" + filenames[func->file_id()] + "]: ";
if ( ! UsedAnyFile )
{
std::ostringstream errmsg;
errmsg << file << "The function '" << func->name() << "' is never used.";
ReportErr( errmsg.str() );
}
else if ( ! UsedOtherFile )
{
std::ostringstream errmsg;
errmsg << file << "The linkage of the function '" << func->name() << "' can be local (static) instead of global";
ReportErr( errmsg.str() );
}
}
}
//---------------------------------------------------------------------------
bool Match(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[])
{
if (!tok)

View File

@ -6,6 +6,7 @@
#include <list>
#include <string>
#include <sstream>
#include <vector>
struct TOKEN;
@ -22,9 +23,9 @@ bool IsNumber(const char str[]);
bool IsStandardType(const char str[]);
void FillFunctionList();
void FillFunctionList(const unsigned int file_id);
const TOKEN *GetFunctionTokenByName( const char funcname[] );
void CheckGlobalFunctionUsage(const std::vector<std::string> &filenames);
bool Match(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0);

View File

@ -52,7 +52,7 @@ static void AppendStatement(STATEMENT::etype Type, TOKEN *tok, std::string Var="
Statements.push_back(NewStatement);
}
TOKEN *GotoNextStatement(TOKEN *tok)
static TOKEN *GotoNextStatement(TOKEN *tok)
{
if (tok && (tok->str[0]=='{' || tok->str[0]=='}'))
return tok->next;
@ -79,7 +79,7 @@ TOKEN *GotoNextStatement(TOKEN *tok)
}
void GetVariableName(TOKEN * &Token, std::string &varname)
static void GetVariableName(TOKEN * &Token, std::string &varname)
{
varname = "";

View File

@ -25,7 +25,7 @@ bool ShowAll = false;
bool CheckCodingStyle = false;
//---------------------------------------------------------------------------
static void CppCheck(const char FileName[]);
static void CppCheck(const char FileName[], unsigned int FileId);
static void AddFiles( std::vector<std::string> &filenames, const char path[], const char pattern[] )
@ -153,10 +153,21 @@ int main(int argc, char* argv[])
for (unsigned int c = 0; c < filenames.size(); c++)
{
errout.str("");
CppCheck(filenames[c].c_str());
CppCheck(filenames[c].c_str(), c);
std::cerr << errout.str();
}
if ( CheckCodingStyle && filenames.size() > 1 )
{
errout.str("");
CheckGlobalFunctionUsage(filenames);
if ( ! errout.str().empty() )
{
std::cerr << "\n";
std::cerr << errout.str();
}
}
return 0;
}
@ -164,7 +175,7 @@ int main(int argc, char* argv[])
// CppCheck - A function that checks a specified file
//---------------------------------------------------------------------------
static void CppCheck(const char FileName[])
static void CppCheck(const char FileName[], unsigned int FileId)
{
OnlyReportUniqueErrors = true;
@ -175,7 +186,7 @@ static void CppCheck(const char FileName[])
Files.clear();
Tokenize(FileName);
FillFunctionList();
FillFunctionList(FileId);
// Check that the memsets are valid.
// The 'memset' function can do dangerous things if used wrong.

View File

@ -86,7 +86,7 @@ static void check(void (chk)(),
if ( chk != CheckUnsignedDivision )
SimplifyTokenList();
FillFunctionList();
FillFunctionList(0);
// Check for buffer overruns..
errout.str("");
@ -579,7 +579,7 @@ static void constructors()
}
//---------------------------------------------------------------------------
void operator_eq()
static void operator_eq()
{
const char test1[] = "class Fred\n"
"{\n"

View File

@ -230,7 +230,7 @@ static void DeleteNextToken(TOKEN *tok)
// InsertTokens - Copy and insert tokens
//---------------------------------------------------------------------------
void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n)
static void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n)
{
while (n > 0)
{
@ -1095,3 +1095,6 @@ void DeallocateTokens()
}