Formatting: uniformize end of lines.

This commit is contained in:
Nicolas Le Cam 2008-12-18 21:28:57 +00:00
parent c56779c9ae
commit a5fa323a0b
47 changed files with 12239 additions and 12239 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +1,54 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckBufferOverrunH
#define CheckBufferOverrunH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckBufferOverrunClass
{
public:
CheckBufferOverrunClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
~CheckBufferOverrunClass();
// Buffer overrun..
void CheckBufferOverrun();
// Dangerous functions that can cause buffer overruns
void WarningDangerousFunctions();
private:
void CheckBufferOverrun_StructVariable();
void CheckBufferOverrun_LocalVariable();
void CheckBufferOverrun_CheckScope( const TOKEN *tok, const char *varname[], const int size, const int total_size, unsigned int varid );
void ReportError(const TOKEN *tok, const char errmsg[]);
const Tokenizer *_tokenizer;
const Settings _settings;
ErrorLogger *_errorLogger;
std::list<const TOKEN *> _callStack;
};
//---------------------------------------------------------------------------
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckBufferOverrunH
#define CheckBufferOverrunH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckBufferOverrunClass
{
public:
CheckBufferOverrunClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
~CheckBufferOverrunClass();
// Buffer overrun..
void CheckBufferOverrun();
// Dangerous functions that can cause buffer overruns
void WarningDangerousFunctions();
private:
void CheckBufferOverrun_StructVariable();
void CheckBufferOverrun_LocalVariable();
void CheckBufferOverrun_CheckScope( const TOKEN *tok, const char *varname[], const int size, const int total_size, unsigned int varid );
void ReportError(const TOKEN *tok, const char errmsg[]);
const Tokenizer *_tokenizer;
const Settings _settings;
ErrorLogger *_errorLogger;
std::list<const TOKEN *> _callStack;
};
//---------------------------------------------------------------------------
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +1,67 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckClassH
#define CheckClassH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "settings.h"
#include "errorlogger.h"
class CheckClass
{
public:
CheckClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
~CheckClass();
void CheckConstructors();
void CheckUnusedPrivateFunctions();
void CheckMemset();
void CheckOperatorEq1(); // Warning upon "void operator=(.."
// The destructor in a base class should be virtual
void virtualDestructor();
private:
struct VAR
{
const char *name;
bool init;
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 InitVar(struct VAR *varlist, const char varname[]);
const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel );
struct VAR *ClassChecking_GetVarList(const TOKEN *tok1);
// Check constructors for a specified class
void CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[]);
const Tokenizer *_tokenizer;
Settings _settings;
ErrorLogger *_errorLogger;
};
//---------------------------------------------------------------------------
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckClassH
#define CheckClassH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "settings.h"
#include "errorlogger.h"
class CheckClass
{
public:
CheckClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
~CheckClass();
void CheckConstructors();
void CheckUnusedPrivateFunctions();
void CheckMemset();
void CheckOperatorEq1(); // Warning upon "void operator=(.."
// The destructor in a base class should be virtual
void virtualDestructor();
private:
struct VAR
{
const char *name;
bool init;
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 InitVar(struct VAR *varlist, const char varname[]);
const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel );
struct VAR *ClassChecking_GetVarList(const TOKEN *tok1);
// Check constructors for a specified class
void CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[]);
const Tokenizer *_tokenizer;
Settings _settings;
ErrorLogger *_errorLogger;
};
//---------------------------------------------------------------------------
#endif

View File

@ -1,167 +1,167 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#include "checkfunctionusage.h"
#include "tokenize.h"
#include <sstream>
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// FUNCTION USAGE - Check for unused functions etc
//---------------------------------------------------------------------------
CheckFunctionUsage::CheckFunctionUsage( ErrorLogger *errorLogger )
{
_errorLogger = errorLogger;
}
CheckFunctionUsage::~CheckFunctionUsage()
{
}
void CheckFunctionUsage::parseTokens( const Tokenizer &tokenizer )
{
// Function declarations..
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
{
if ( tok->fileIndex() != 0 )
continue;
const TOKEN *funcname = 0;
if ( TOKEN::Match( tok, "%type% %var% (" ) )
funcname = tok->tokAt(1);
else if ( TOKEN::Match(tok, "%type% * %var% (") )
funcname = tok->tokAt(2);
else if ( TOKEN::Match(tok, "%type% :: %var% (") && !TOKEN::Match(tok, tok->strAt(2)) )
funcname = tok->tokAt(2);
// Check that ") {" is found..
for (const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next())
{
if ( TOKEN::Match(tok2, ")") )
{
if ( ! TOKEN::Match(tok2, ") {") && ! TOKEN::Match(tok2, ") const {") )
funcname = NULL;
break;
}
}
if ( funcname )
{
FunctionUsage &func = _functions[ funcname->str() ];
// No filename set yet..
if (func.filename.empty())
func.filename = tokenizer.getFiles()->at(0);
// Multiple files => filename = "+"
else if (func.filename != tokenizer.getFiles()->at(0))
{
func.filename = "+";
func.usedOtherFile |= func.usedSameFile;
}
}
}
// Function usage..
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
{
const TOKEN *funcname = 0;
if ( 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, "return %var% (") )
funcname = tok->next();
// funcname ( => Assert that the end paranthesis isn't followed by {
if ( TOKEN::Match(funcname, "%var% (") )
{
int parlevel = 0;
for ( const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next() )
{
if (tok2->str() == "(")
++parlevel;
else if (tok2->str() == ")")
{
--parlevel;
if (parlevel == 0 && (TOKEN::Match(tok2, ") {") || TOKEN::Match(tok2, ") const")))
funcname = NULL;
if ( parlevel <= 0 )
break;
}
}
}
if ( funcname )
{
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 )
{
std::ostringstream errmsg;
if ( func.filename != "+" )
errmsg << "[" << func.filename << "] ";
errmsg << "The function '" << it->first << "' is never used.";
_errorLogger->reportErr( errmsg.str() );
}
else if ( ! func.usedOtherFile )
{
/* TODO - add error message "function is only used in <file> it can be static"
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() );
*/
}
}
}
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#include "checkfunctionusage.h"
#include "tokenize.h"
#include <sstream>
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// FUNCTION USAGE - Check for unused functions etc
//---------------------------------------------------------------------------
CheckFunctionUsage::CheckFunctionUsage( ErrorLogger *errorLogger )
{
_errorLogger = errorLogger;
}
CheckFunctionUsage::~CheckFunctionUsage()
{
}
void CheckFunctionUsage::parseTokens( const Tokenizer &tokenizer )
{
// Function declarations..
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
{
if ( tok->fileIndex() != 0 )
continue;
const TOKEN *funcname = 0;
if ( TOKEN::Match( tok, "%type% %var% (" ) )
funcname = tok->tokAt(1);
else if ( TOKEN::Match(tok, "%type% * %var% (") )
funcname = tok->tokAt(2);
else if ( TOKEN::Match(tok, "%type% :: %var% (") && !TOKEN::Match(tok, tok->strAt(2)) )
funcname = tok->tokAt(2);
// Check that ") {" is found..
for (const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next())
{
if ( TOKEN::Match(tok2, ")") )
{
if ( ! TOKEN::Match(tok2, ") {") && ! TOKEN::Match(tok2, ") const {") )
funcname = NULL;
break;
}
}
if ( funcname )
{
FunctionUsage &func = _functions[ funcname->str() ];
// No filename set yet..
if (func.filename.empty())
func.filename = tokenizer.getFiles()->at(0);
// Multiple files => filename = "+"
else if (func.filename != tokenizer.getFiles()->at(0))
{
func.filename = "+";
func.usedOtherFile |= func.usedSameFile;
}
}
}
// Function usage..
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
{
const TOKEN *funcname = 0;
if ( 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, "return %var% (") )
funcname = tok->next();
// funcname ( => Assert that the end paranthesis isn't followed by {
if ( TOKEN::Match(funcname, "%var% (") )
{
int parlevel = 0;
for ( const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next() )
{
if (tok2->str() == "(")
++parlevel;
else if (tok2->str() == ")")
{
--parlevel;
if (parlevel == 0 && (TOKEN::Match(tok2, ") {") || TOKEN::Match(tok2, ") const")))
funcname = NULL;
if ( parlevel <= 0 )
break;
}
}
}
if ( funcname )
{
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 )
{
std::ostringstream errmsg;
if ( func.filename != "+" )
errmsg << "[" << func.filename << "] ";
errmsg << "The function '" << it->first << "' is never used.";
_errorLogger->reportErr( errmsg.str() );
}
else if ( ! func.usedOtherFile )
{
/* TODO - add error message "function is only used in <file> it can be static"
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

@ -1,66 +1,66 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckFunctionUsageH
#define CheckFunctionUsageH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckFunctionUsage
{
public:
CheckFunctionUsage( ErrorLogger *errorLogger );
~CheckFunctionUsage();
// Parse current tokens and determine..
// * Check what functions are used
// * What functions are declared
void parseTokens( const Tokenizer &tokenizer );
void check();
private:
ErrorLogger *_errorLogger;
class FunctionUsage
{
public:
FunctionUsage()
{
filename = "";
usedOtherFile = false;
usedSameFile = false;
}
std::string filename;
bool usedSameFile;
bool usedOtherFile;
};
std::map<std::string, FunctionUsage> _functions;
};
//---------------------------------------------------------------------------
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckFunctionUsageH
#define CheckFunctionUsageH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckFunctionUsage
{
public:
CheckFunctionUsage( ErrorLogger *errorLogger );
~CheckFunctionUsage();
// Parse current tokens and determine..
// * Check what functions are used
// * What functions are declared
void parseTokens( const Tokenizer &tokenizer );
void check();
private:
ErrorLogger *_errorLogger;
class FunctionUsage
{
public:
FunctionUsage()
{
filename = "";
usedOtherFile = false;
usedSameFile = false;
}
std::string filename;
bool usedSameFile;
bool usedOtherFile;
};
std::map<std::string, FunctionUsage> _functions;
};
//---------------------------------------------------------------------------
#endif

View File

@ -1,256 +1,256 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#include "checkheaders.h"
#include "tokenize.h"
#include <algorithm>
#include <list>
#include <sstream>
#include <string>
#include <cstring>
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// HEADERS - No implementation in a header
//---------------------------------------------------------------------------
CheckHeaders::CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger )
{
_tokenizer = tokenizer;
_errorLogger = errorLogger;
}
CheckHeaders::~CheckHeaders()
{
}
void CheckHeaders::WarningHeaderWithImplementation()
{
for ( const TOKEN *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// Only interested in included file
if (tok->fileIndex() == 0)
continue;
if (TOKEN::Match(tok, ") {"))
{
std::ostringstream ostr;
ostr << _tokenizer->fileLine(tok) << ": Found implementation in header";
_errorLogger->reportErr(ostr.str());
// Goto next file..
unsigned int fileindex = tok->fileIndex();
while ( tok->next() && tok->fileIndex() == fileindex )
tok = tok->next();
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// HEADERS - Unneeded include
//---------------------------------------------------------------------------
void CheckHeaders::WarningIncludeHeader()
{
// Including..
for ( const TOKEN *includetok = _tokenizer->tokens(); includetok; includetok = includetok->next())
{
if (includetok->str() != "#include")
continue;
// Get fileindex of included file..
unsigned int hfile = 0;
const char *includefile = includetok->next()->aaaa();
while (hfile < _tokenizer->getFiles()->size())
{
if ( Tokenizer::SameFileName( _tokenizer->getFiles()->at(hfile).c_str(), includefile ) )
break;
hfile++;
}
if (hfile == _tokenizer->getFiles()->size())
continue;
// This header is needed if:
// * It contains some needed class declaration
// * It contains some needed function declaration
// * It contains some needed constant value
// * It contains some needed variable
// * It contains some needed enum
std::list<std::string> classlist;
std::list<std::string> namelist;
// Extract classes and names in the header..
int indentlevel = 0;
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next() )
{
if ( tok1->fileIndex() != hfile )
continue;
// I'm only interested in stuff that is declared at indentlevel 0
if (tok1->str() == "{")
++indentlevel;
else if (tok1->str() == "}")
--indentlevel;
if (indentlevel != 0)
continue;
// Class or namespace declaration..
// --------------------------------------
if (TOKEN::Match(tok1,"class %var% {") || TOKEN::Match(tok1,"class %var% :") || TOKEN::Match(tok1,"namespace %var% {"))
classlist.push_back(tok1->strAt(1));
// Variable declaration..
// --------------------------------------
else if (TOKEN::Match(tok1, "%type% %var% ;") || TOKEN::Match(tok1, "%type% %var% ["))
namelist.push_back(tok1->strAt(1));
else if (TOKEN::Match(tok1, "%type% * %var% ;") || TOKEN::Match(tok1, "%type% * %var% ["))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1, "const %type% %var% =") || TOKEN::Match(tok1, "const %type% %var% ["))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1, "const %type% * %var% =") || TOKEN::Match(tok1, "const %type% * %var% ["))
namelist.push_back(tok1->strAt(3));
// enum..
// --------------------------------------
else if (tok1->str() == "enum")
{
tok1 = tok1->next();
while ( ! TOKEN::Match( tok1, "; %any%" ) )
{
if ( tok1->isName() )
namelist.push_back(tok1->str());
tok1 = tok1->next();
}
}
// function..
// --------------------------------------
else if (TOKEN::Match(tok1,"%type% %var% ("))
namelist.push_back(tok1->strAt(1));
else if (TOKEN::Match(tok1,"%type% * %var% ("))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1,"const %type% %var% ("))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1,"const %type% * %var% ("))
namelist.push_back(tok1->strAt(3));
// typedef..
// --------------------------------------
else if (tok1->str() == "typedef")
{
if (strcmp(tok1->strAt(1),"enum")==0)
continue;
int parlevel = 0;
while (tok1->next())
{
if ( TOKEN::Match(tok1, "[({]") )
parlevel++;
else if ( TOKEN::Match(tok1, "[)}]") )
parlevel--;
else if (parlevel == 0)
{
if ( tok1->str() == ";" )
break;
if ( TOKEN::Match(tok1, "%var% ;") )
namelist.push_back(tok1->str());
}
tok1 = tok1->next();
}
}
}
// Check if the extracted names are used...
bool Needed = false;
bool NeedDeclaration = false;
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next())
{
if (tok1->fileIndex() != includetok->fileIndex())
continue;
if ( TOKEN::Match(tok1, ": %var% {") || TOKEN::Match(tok1, ": %type% %var% {") )
{
std::string classname = tok1->strAt((strcmp(tok1->strAt(2),"{")) ? 2 : 1);
if (std::find(classlist.begin(),classlist.end(),classname)!=classlist.end())
{
Needed = true;
break;
}
}
if ( ! tok1->isName() )
continue;
if (std::find(namelist.begin(),namelist.end(),tok1->aaaa() ) != namelist.end())
{
Needed = true;
break;
}
if ( ! NeedDeclaration )
NeedDeclaration = (std::find(classlist.begin(),classlist.end(),tok1->aaaa() ) != classlist.end());
}
// Not a header file?
if (includetok->fileIndex() == 0)
Needed |= NeedDeclaration;
// Not needed!
if (!Needed)
{
std::ostringstream ostr;
ostr << _tokenizer->fileLine(includetok) << ": The included header '" << includefile << "' is not needed";
if (NeedDeclaration)
ostr << " (but a forward declaration is needed)";
_errorLogger->reportErr(ostr.str());
}
}
}
//---------------------------------------------------------------------------
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#include "checkheaders.h"
#include "tokenize.h"
#include <algorithm>
#include <list>
#include <sstream>
#include <string>
#include <cstring>
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// HEADERS - No implementation in a header
//---------------------------------------------------------------------------
CheckHeaders::CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger )
{
_tokenizer = tokenizer;
_errorLogger = errorLogger;
}
CheckHeaders::~CheckHeaders()
{
}
void CheckHeaders::WarningHeaderWithImplementation()
{
for ( const TOKEN *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// Only interested in included file
if (tok->fileIndex() == 0)
continue;
if (TOKEN::Match(tok, ") {"))
{
std::ostringstream ostr;
ostr << _tokenizer->fileLine(tok) << ": Found implementation in header";
_errorLogger->reportErr(ostr.str());
// Goto next file..
unsigned int fileindex = tok->fileIndex();
while ( tok->next() && tok->fileIndex() == fileindex )
tok = tok->next();
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// HEADERS - Unneeded include
//---------------------------------------------------------------------------
void CheckHeaders::WarningIncludeHeader()
{
// Including..
for ( const TOKEN *includetok = _tokenizer->tokens(); includetok; includetok = includetok->next())
{
if (includetok->str() != "#include")
continue;
// Get fileindex of included file..
unsigned int hfile = 0;
const char *includefile = includetok->next()->aaaa();
while (hfile < _tokenizer->getFiles()->size())
{
if ( Tokenizer::SameFileName( _tokenizer->getFiles()->at(hfile).c_str(), includefile ) )
break;
hfile++;
}
if (hfile == _tokenizer->getFiles()->size())
continue;
// This header is needed if:
// * It contains some needed class declaration
// * It contains some needed function declaration
// * It contains some needed constant value
// * It contains some needed variable
// * It contains some needed enum
std::list<std::string> classlist;
std::list<std::string> namelist;
// Extract classes and names in the header..
int indentlevel = 0;
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next() )
{
if ( tok1->fileIndex() != hfile )
continue;
// I'm only interested in stuff that is declared at indentlevel 0
if (tok1->str() == "{")
++indentlevel;
else if (tok1->str() == "}")
--indentlevel;
if (indentlevel != 0)
continue;
// Class or namespace declaration..
// --------------------------------------
if (TOKEN::Match(tok1,"class %var% {") || TOKEN::Match(tok1,"class %var% :") || TOKEN::Match(tok1,"namespace %var% {"))
classlist.push_back(tok1->strAt(1));
// Variable declaration..
// --------------------------------------
else if (TOKEN::Match(tok1, "%type% %var% ;") || TOKEN::Match(tok1, "%type% %var% ["))
namelist.push_back(tok1->strAt(1));
else if (TOKEN::Match(tok1, "%type% * %var% ;") || TOKEN::Match(tok1, "%type% * %var% ["))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1, "const %type% %var% =") || TOKEN::Match(tok1, "const %type% %var% ["))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1, "const %type% * %var% =") || TOKEN::Match(tok1, "const %type% * %var% ["))
namelist.push_back(tok1->strAt(3));
// enum..
// --------------------------------------
else if (tok1->str() == "enum")
{
tok1 = tok1->next();
while ( ! TOKEN::Match( tok1, "; %any%" ) )
{
if ( tok1->isName() )
namelist.push_back(tok1->str());
tok1 = tok1->next();
}
}
// function..
// --------------------------------------
else if (TOKEN::Match(tok1,"%type% %var% ("))
namelist.push_back(tok1->strAt(1));
else if (TOKEN::Match(tok1,"%type% * %var% ("))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1,"const %type% %var% ("))
namelist.push_back(tok1->strAt(2));
else if (TOKEN::Match(tok1,"const %type% * %var% ("))
namelist.push_back(tok1->strAt(3));
// typedef..
// --------------------------------------
else if (tok1->str() == "typedef")
{
if (strcmp(tok1->strAt(1),"enum")==0)
continue;
int parlevel = 0;
while (tok1->next())
{
if ( TOKEN::Match(tok1, "[({]") )
parlevel++;
else if ( TOKEN::Match(tok1, "[)}]") )
parlevel--;
else if (parlevel == 0)
{
if ( tok1->str() == ";" )
break;
if ( TOKEN::Match(tok1, "%var% ;") )
namelist.push_back(tok1->str());
}
tok1 = tok1->next();
}
}
}
// Check if the extracted names are used...
bool Needed = false;
bool NeedDeclaration = false;
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next())
{
if (tok1->fileIndex() != includetok->fileIndex())
continue;
if ( TOKEN::Match(tok1, ": %var% {") || TOKEN::Match(tok1, ": %type% %var% {") )
{
std::string classname = tok1->strAt((strcmp(tok1->strAt(2),"{")) ? 2 : 1);
if (std::find(classlist.begin(),classlist.end(),classname)!=classlist.end())
{
Needed = true;
break;
}
}
if ( ! tok1->isName() )
continue;
if (std::find(namelist.begin(),namelist.end(),tok1->aaaa() ) != namelist.end())
{
Needed = true;
break;
}
if ( ! NeedDeclaration )
NeedDeclaration = (std::find(classlist.begin(),classlist.end(),tok1->aaaa() ) != classlist.end());
}
// Not a header file?
if (includetok->fileIndex() == 0)
Needed |= NeedDeclaration;
// Not needed!
if (!Needed)
{
std::ostringstream ostr;
ostr << _tokenizer->fileLine(includetok) << ": The included header '" << includefile << "' is not needed";
if (NeedDeclaration)
ostr << " (but a forward declaration is needed)";
_errorLogger->reportErr(ostr.str());
}
}
}
//---------------------------------------------------------------------------

View File

@ -1,43 +1,43 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckHeadersH
#define CheckHeadersH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckHeaders
{
public:
CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
~CheckHeaders();
void WarningHeaderWithImplementation();
void WarningIncludeHeader();
private:
const Tokenizer *_tokenizer;
ErrorLogger *_errorLogger;
};
//---------------------------------------------------------------------------
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckHeadersH
#define CheckHeadersH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckHeaders
{
public:
CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
~CheckHeaders();
void WarningHeaderWithImplementation();
void WarningIncludeHeader();
private:
const Tokenizer *_tokenizer;
ErrorLogger *_errorLogger;
};
//---------------------------------------------------------------------------
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,108 +1,108 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckMemoryLeakH
#define CheckMemoryLeakH
//---------------------------------------------------------------------------
/** \brief Check for memory leaks */
#include "tokenize.h"
#include "settings.h"
#include "errorlogger.h"
#include <list>
#include <vector>
class CheckMemoryLeakClass
{
public:
CheckMemoryLeakClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
~CheckMemoryLeakClass();
void CheckMemoryLeak();
private:
enum AllocType { No, Malloc, gMalloc, New, NewA, FOPEN, POPEN };
// Extra allocation..
class AllocFunc
{
public:
const char *funcname;
AllocType alloctype;
AllocFunc(const char f[], AllocType a)
{
funcname = f;
alloctype = a;
}
};
void CheckMemoryLeak_ClassMembers_Variable( const std::vector<const char *> &classname, const char varname[] );
void CheckMemoryLeak_ClassMembers_ParseClass( const TOKEN *tok1, std::vector<const char *> &classname );
void CheckMemoryLeak_ClassMembers();
void CheckMemoryLeak_InFunction();
void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] );
/**
* Simplify code e.g. by replacing empty "{ }" with ";"
* @param tok first token. The tokens list can be modified.
*/
void simplifycode(TOKEN *tok);
/**
* Delete tokens between begin and end. E.g. if begin = 1
* and end = 5, tokens 2,3 and 4 would be erased.
*
* @param begin Tokens after this will be erased.
* @param end Tokens before this will be erased.
*/
void erase(TOKEN *begin, const TOKEN *end);
/**
* Extract a new tokens list that is easier to parse than the "tokens"
* @param tok start parse token
* @param callstack callstack
* @param varname name of variable
* @param alloctype
* @param dealloctype
* @return Newly allocated token array. Caller needs to release reserved
* memory by calling Tokenizer::deleteTokens(returnValue);
*/
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[]);
void instoken(TOKEN *tok, const char str[]);
void MemoryLeak( const TOKEN *tok, const char varname[], AllocType alloctype );
void MismatchError( const TOKEN *Tok1, const std::list<const TOKEN *> &callstack, const char varname[] );
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 GetAllocationType( const TOKEN *tok2 );
AllocType GetReallocationType( const TOKEN *tok2 );
bool isclass( const TOKEN *typestr );
const Tokenizer *_tokenizer;
ErrorLogger *_errorLogger;
const Settings _settings;
std::list<AllocFunc> _listAllocFunc;
};
//---------------------------------------------------------------------------
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckMemoryLeakH
#define CheckMemoryLeakH
//---------------------------------------------------------------------------
/** \brief Check for memory leaks */
#include "tokenize.h"
#include "settings.h"
#include "errorlogger.h"
#include <list>
#include <vector>
class CheckMemoryLeakClass
{
public:
CheckMemoryLeakClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
~CheckMemoryLeakClass();
void CheckMemoryLeak();
private:
enum AllocType { No, Malloc, gMalloc, New, NewA, FOPEN, POPEN };
// Extra allocation..
class AllocFunc
{
public:
const char *funcname;
AllocType alloctype;
AllocFunc(const char f[], AllocType a)
{
funcname = f;
alloctype = a;
}
};
void CheckMemoryLeak_ClassMembers_Variable( const std::vector<const char *> &classname, const char varname[] );
void CheckMemoryLeak_ClassMembers_ParseClass( const TOKEN *tok1, std::vector<const char *> &classname );
void CheckMemoryLeak_ClassMembers();
void CheckMemoryLeak_InFunction();
void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] );
/**
* Simplify code e.g. by replacing empty "{ }" with ";"
* @param tok first token. The tokens list can be modified.
*/
void simplifycode(TOKEN *tok);
/**
* Delete tokens between begin and end. E.g. if begin = 1
* and end = 5, tokens 2,3 and 4 would be erased.
*
* @param begin Tokens after this will be erased.
* @param end Tokens before this will be erased.
*/
void erase(TOKEN *begin, const TOKEN *end);
/**
* Extract a new tokens list that is easier to parse than the "tokens"
* @param tok start parse token
* @param callstack callstack
* @param varname name of variable
* @param alloctype
* @param dealloctype
* @return Newly allocated token array. Caller needs to release reserved
* memory by calling Tokenizer::deleteTokens(returnValue);
*/
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[]);
void instoken(TOKEN *tok, const char str[]);
void MemoryLeak( const TOKEN *tok, const char varname[], AllocType alloctype );
void MismatchError( const TOKEN *Tok1, const std::list<const TOKEN *> &callstack, const char varname[] );
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 GetAllocationType( const TOKEN *tok2 );
AllocType GetReallocationType( const TOKEN *tok2 );
bool isclass( const TOKEN *typestr );
const Tokenizer *_tokenizer;
ErrorLogger *_errorLogger;
const Settings _settings;
std::list<AllocFunc> _listAllocFunc;
};
//---------------------------------------------------------------------------
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +1,90 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckOtherH
#define CheckOtherH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckOther
{
public:
CheckOther( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
~CheckOther();
// Casting
void WarningOldStylePointerCast();
// Redundant code
void WarningRedundantCode();
// Warning upon: if (condition);
void WarningIf();
// Assignment in condition
void CheckIfAssignment();
// Invalid function usage..
void InvalidFunctionUsage();
// Check for unsigned division that might create bad results
void CheckUnsignedDivision();
// Check scope of variables
void CheckVariableScope();
// Check for constant function parameter
void CheckConstantFunctionParameter();
// Check that all struct members are used
void CheckStructMemberUsage();
// Using char variable as array index / as operand in bit operation
void CheckCharVariable();
// Incomplete statement. A statement that only contains a constant or variable
void CheckIncompleteStatement();
/** Unreachable code below a 'return' */
void unreachableCode();
/** Unused function variables */
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef CheckOtherH
#define CheckOtherH
//---------------------------------------------------------------------------
#include "tokenize.h"
#include "errorlogger.h"
class CheckOther
{
public:
CheckOther( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
~CheckOther();
// Casting
void WarningOldStylePointerCast();
// Redundant code
void WarningRedundantCode();
// Warning upon: if (condition);
void WarningIf();
// Assignment in condition
void CheckIfAssignment();
// Invalid function usage..
void InvalidFunctionUsage();
// Check for unsigned division that might create bad results
void CheckUnsignedDivision();
// Check scope of variables
void CheckVariableScope();
// Check for constant function parameter
void CheckConstantFunctionParameter();
// Check that all struct members are used
void CheckStructMemberUsage();
// Using char variable as array index / as operand in bit operation
void CheckCharVariable();
// Incomplete statement. A statement that only contains a constant or variable
void CheckIncompleteStatement();
/** Unreachable code below a 'return' */
void unreachableCode();
/** Unused function variables */
void functionVariableUsage();
#ifndef UNIT_TESTING
#ifndef UNIT_TESTING
private:
#endif
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
#endif
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
// Redundant condition
// if (haystack.find(needle) != haystack.end())
// Redundant condition
// if (haystack.find(needle) != haystack.end())
// haystack.remove(needle);
void redundantCondition2();
const Tokenizer *_tokenizer;
ErrorLogger *_errorLogger;
};
//---------------------------------------------------------------------------
#endif
const Tokenizer *_tokenizer;
ErrorLogger *_errorLogger;
};
//---------------------------------------------------------------------------
#endif

View File

@ -1,360 +1,360 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "cppcheck.h"
#include "preprocessor.h" // preprocessor.
#include "tokenize.h" // <- Tokenizer
#include "checkmemoryleak.h"
#include "checkbufferoverrun.h"
#include "checkclass.h"
#include "checkheaders.h"
#include "checkother.h"
#include "checkfunctionusage.h"
#include "filelister.h"
#include <algorithm>
#include <sstream>
#include <cstring>
#include <fstream>
#include <map>
//---------------------------------------------------------------------------
CppCheck::CppCheck( ErrorLogger &errorLogger ) : _checkFunctionUsage( this )
{
_errorLogger = &errorLogger;
}
CppCheck::~CppCheck()
{
}
void CppCheck::settings( const Settings &settings )
{
_settings = settings;
}
void CppCheck::addFile( const std::string &path )
{
_filenames.push_back( path );
}
void CppCheck::addFile( const std::string &path, const std::string &content )
{
_filenames.push_back( path );
_fileContents[ path ] = content;
}
std::string CppCheck::parseFromArgs( int argc, const char* const argv[] )
{
std::vector<std::string> pathnames;
bool Recursive = false;
for (int i = 1; i < argc; i++)
{
// Flag used for various purposes during debugging
if (strcmp(argv[i],"--debug") == 0)
_settings._debug = true;
// Show all messages
else if (strcmp(argv[i],"--all") == 0)
_settings._showAll = true;
// Only print something when there are errors
else if (strcmp(argv[i],"--errorsonly")==0)
_settings._errorsOnly = true;
// Checking coding style
else if (strcmp(argv[i],"--style")==0)
_settings._checkCodingStyle = true;
// Recursively check source files
else if (strcmp(argv[i],"--recursive")==0)
Recursive = true;
// Verbose error messages (configuration info)
else if (strcmp(argv[i],"--verbose")==0)
_settings._verbose = true;
else
pathnames.push_back( argv[i] );
}
// --recursive was used
if ( Recursive )
{
if( pathnames.size() == 0 )
{
// Handle situation: cppcheck --recursive
FileLister::RecursiveAddFiles( _filenames, "", true );
}
else
{
// Handle situation: cppcheck --recursive path1 path2
// Execute RecursiveAddFiles() to each given file parameter
std::vector<std::string>::const_iterator iter;
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), true );
}
}
else
{
std::vector<std::string>::const_iterator iter;
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), false );
}
if (_filenames.empty())
{
std::ostringstream oss;
oss << "c++check 1.26\n"
"\n"
"C/C++ code checking\n"
"\n"
"Syntax:\n"
" cppcheck [--all] [--errorsonly] [--recursive] [--style] [--verbose] [filename1] [filename2]\n"
"\n"
"Options:\n"
" --all Make the checking more sensitive. More bugs are detected,\n"
" but there are also more false positives\n"
" --errorsonly Only print error messages\n"
" --recursive Recursively check all *.cpp, *.cxx, *.cc and *.c files\n"
" --style Check coding style\n"
" --verbose More detailed error reports\n";
return oss.str();
}
// Check function usage if "--style" and "--all" was given.
// There will be false positives for exported library functions
if ( _settings._showAll && _settings._checkCodingStyle )
_settings._checkFunctionUsage = true;
return "";
}
void CppCheck::check()
{
std::sort( _filenames.begin(), _filenames.end() );
for (unsigned int c = 0; c < _filenames.size(); c++)
{
_errout.str("");
std::string fname = _filenames[c];
// If only errors are printed, print filename after the check
if ( _settings._errorsOnly == false )
_errorLogger->reportOut( std::string( "Checking " ) + fname + std::string( "..." ) );
Preprocessor preprocessor;
std::map<std::string, std::string> code;
if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() )
{
// File content was given as a string
std::istringstream iss( _fileContents[ _filenames[c] ] );
preprocessor.preprocess(iss, code, fname);
}
else
{
// Only file name was given, read the content from file
std::ifstream fin( fname.c_str() );
preprocessor.preprocess(fin, code, fname);
}
for ( std::map<std::string,std::string>::const_iterator it = code.begin(); it != code.end(); ++it )
{
cfg = it->first;
checkFile(it->second, _filenames[c].c_str());
}
if ( _settings._errorsOnly == false && _errout.str().empty() )
_errorLogger->reportOut( "No errors found" );
}
// This generates false positives - especially for libraries
_settings._verbose = false;
if ( _settings._checkFunctionUsage )
{
_errout.str("");
if( _settings._errorsOnly == false )
_errorLogger->reportOut( "Checking usage of global functions (this may take several minutes).." );
_checkFunctionUsage.check();
}
_errorList.clear();
}
//---------------------------------------------------------------------------
// CppCheck - A function that checks a specified file
//---------------------------------------------------------------------------
void CppCheck::checkFile(const std::string &code, const char FileName[])
{
Tokenizer _tokenizer;
// Tokenize the file
{
std::istringstream istr(code);
_tokenizer.tokenize(istr, FileName);
}
// Set variable id
_tokenizer.setVarId();
_tokenizer.fillFunctionList();
// Check that the memsets are valid.
// The 'memset' function can do dangerous things if used wrong.
// Important: The checking doesn't work on simplified tokens list.
CheckClass checkClass( &_tokenizer, _settings, this );
checkClass.CheckMemset();
// Check for unsigned divisions where one operand is signed
// Very important to run it before 'SimplifyTokenList'
CheckOther checkOther( &_tokenizer, this );
if ( _settings._checkCodingStyle )
checkOther.CheckUnsignedDivision();
// Give warning when using char variable as array index
// Doesn't work on simplified token list ('unsigned')
if ( _settings._checkCodingStyle )
checkOther.CheckCharVariable();
// Including header which is not needed (too many false positives)
// if ( _settings._checkCodingStyle )
// {
// CheckHeaders checkHeaders( &tokenizer );
// checkHeaders.WarningIncludeHeader();
// }
_tokenizer.simplifyTokenList();
if ( _settings._checkFunctionUsage )
_checkFunctionUsage.parseTokens(_tokenizer);
// Memory leak
CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this );
checkMemoryLeak.CheckMemoryLeak();
// Buffer overruns..
CheckBufferOverrunClass checkBufferOverrun( &_tokenizer, _settings, this );
checkBufferOverrun.CheckBufferOverrun();
// Check that all class constructors are ok.
checkClass.CheckConstructors();
// Check that all base classes have virtual destructors
checkClass.virtualDestructor();
if (_settings._showAll)
{
// Check for "if (a=b)"
checkOther.CheckIfAssignment();
// Check for case without break
// Disabled because it generates many false positives
// CheckCaseWithoutBreak();
// Dangerous usage of strtok
// Disabled because it generates false positives
//WarningStrTok();
}
// Dangerous functions, such as 'gets' and 'scanf'
checkBufferOverrun.WarningDangerousFunctions();
// Invalid function usage..
checkOther.InvalidFunctionUsage();
if (_settings._checkCodingStyle)
{
// Check that all private functions are called.
checkClass.CheckUnusedPrivateFunctions();
// Warning upon c-style pointer casts
const char *ext = strrchr(FileName, '.');
if (ext && strcmp(ext,".cpp")==0)
checkOther.WarningOldStylePointerCast();
checkClass.CheckOperatorEq1();
// if (a) delete a;
checkOther.WarningRedundantCode();
// if (condition);
checkOther.WarningIf();
// Variable scope (check if the scope could be limited)
//CheckVariableScope();
// Check if a constant function parameter is passed by value
checkOther.CheckConstantFunctionParameter();
// Unused struct members..
checkOther.CheckStructMemberUsage();
// Check for various types of incomplete statements that could for example
// mean that an ';' has been added by accident
checkOther.CheckIncompleteStatement();
// Unreachable code below a 'return' statement
checkOther.unreachableCode();
// Usage of local functions
checkOther.functionVariableUsage();
}
}
//---------------------------------------------------------------------------
void CppCheck::reportErr( const std::string &errmsg)
{
if ( /*OnlyReportUniqueErrors*/ true )
{
if ( std::find( _errorList.begin(), _errorList.end(), errmsg ) != _errorList.end() )
return;
_errorList.push_back( errmsg );
}
std::string errmsg2( errmsg );
if ( _settings._verbose )
{
errmsg2 += "\n Defines=\'" + cfg + "\'\n";
}
_errorLogger->reportErr( errmsg2 );
_errout << errmsg2 << std::endl;
}
void CppCheck::reportOut( const std::string &outmsg)
{
// This is currently never called. It is here just to comply with
// the interface.
}
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "cppcheck.h"
#include "preprocessor.h" // preprocessor.
#include "tokenize.h" // <- Tokenizer
#include "checkmemoryleak.h"
#include "checkbufferoverrun.h"
#include "checkclass.h"
#include "checkheaders.h"
#include "checkother.h"
#include "checkfunctionusage.h"
#include "filelister.h"
#include <algorithm>
#include <sstream>
#include <cstring>
#include <fstream>
#include <map>
//---------------------------------------------------------------------------
CppCheck::CppCheck( ErrorLogger &errorLogger ) : _checkFunctionUsage( this )
{
_errorLogger = &errorLogger;
}
CppCheck::~CppCheck()
{
}
void CppCheck::settings( const Settings &settings )
{
_settings = settings;
}
void CppCheck::addFile( const std::string &path )
{
_filenames.push_back( path );
}
void CppCheck::addFile( const std::string &path, const std::string &content )
{
_filenames.push_back( path );
_fileContents[ path ] = content;
}
std::string CppCheck::parseFromArgs( int argc, const char* const argv[] )
{
std::vector<std::string> pathnames;
bool Recursive = false;
for (int i = 1; i < argc; i++)
{
// Flag used for various purposes during debugging
if (strcmp(argv[i],"--debug") == 0)
_settings._debug = true;
// Show all messages
else if (strcmp(argv[i],"--all") == 0)
_settings._showAll = true;
// Only print something when there are errors
else if (strcmp(argv[i],"--errorsonly")==0)
_settings._errorsOnly = true;
// Checking coding style
else if (strcmp(argv[i],"--style")==0)
_settings._checkCodingStyle = true;
// Recursively check source files
else if (strcmp(argv[i],"--recursive")==0)
Recursive = true;
// Verbose error messages (configuration info)
else if (strcmp(argv[i],"--verbose")==0)
_settings._verbose = true;
else
pathnames.push_back( argv[i] );
}
// --recursive was used
if ( Recursive )
{
if( pathnames.size() == 0 )
{
// Handle situation: cppcheck --recursive
FileLister::RecursiveAddFiles( _filenames, "", true );
}
else
{
// Handle situation: cppcheck --recursive path1 path2
// Execute RecursiveAddFiles() to each given file parameter
std::vector<std::string>::const_iterator iter;
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), true );
}
}
else
{
std::vector<std::string>::const_iterator iter;
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), false );
}
if (_filenames.empty())
{
std::ostringstream oss;
oss << "c++check 1.26\n"
"\n"
"C/C++ code checking\n"
"\n"
"Syntax:\n"
" cppcheck [--all] [--errorsonly] [--recursive] [--style] [--verbose] [filename1] [filename2]\n"
"\n"
"Options:\n"
" --all Make the checking more sensitive. More bugs are detected,\n"
" but there are also more false positives\n"
" --errorsonly Only print error messages\n"
" --recursive Recursively check all *.cpp, *.cxx, *.cc and *.c files\n"
" --style Check coding style\n"
" --verbose More detailed error reports\n";
return oss.str();
}
// Check function usage if "--style" and "--all" was given.
// There will be false positives for exported library functions
if ( _settings._showAll && _settings._checkCodingStyle )
_settings._checkFunctionUsage = true;
return "";
}
void CppCheck::check()
{
std::sort( _filenames.begin(), _filenames.end() );
for (unsigned int c = 0; c < _filenames.size(); c++)
{
_errout.str("");
std::string fname = _filenames[c];
// If only errors are printed, print filename after the check
if ( _settings._errorsOnly == false )
_errorLogger->reportOut( std::string( "Checking " ) + fname + std::string( "..." ) );
Preprocessor preprocessor;
std::map<std::string, std::string> code;
if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() )
{
// File content was given as a string
std::istringstream iss( _fileContents[ _filenames[c] ] );
preprocessor.preprocess(iss, code, fname);
}
else
{
// Only file name was given, read the content from file
std::ifstream fin( fname.c_str() );
preprocessor.preprocess(fin, code, fname);
}
for ( std::map<std::string,std::string>::const_iterator it = code.begin(); it != code.end(); ++it )
{
cfg = it->first;
checkFile(it->second, _filenames[c].c_str());
}
if ( _settings._errorsOnly == false && _errout.str().empty() )
_errorLogger->reportOut( "No errors found" );
}
// This generates false positives - especially for libraries
_settings._verbose = false;
if ( _settings._checkFunctionUsage )
{
_errout.str("");
if( _settings._errorsOnly == false )
_errorLogger->reportOut( "Checking usage of global functions (this may take several minutes).." );
_checkFunctionUsage.check();
}
_errorList.clear();
}
//---------------------------------------------------------------------------
// CppCheck - A function that checks a specified file
//---------------------------------------------------------------------------
void CppCheck::checkFile(const std::string &code, const char FileName[])
{
Tokenizer _tokenizer;
// Tokenize the file
{
std::istringstream istr(code);
_tokenizer.tokenize(istr, FileName);
}
// Set variable id
_tokenizer.setVarId();
_tokenizer.fillFunctionList();
// Check that the memsets are valid.
// The 'memset' function can do dangerous things if used wrong.
// Important: The checking doesn't work on simplified tokens list.
CheckClass checkClass( &_tokenizer, _settings, this );
checkClass.CheckMemset();
// Check for unsigned divisions where one operand is signed
// Very important to run it before 'SimplifyTokenList'
CheckOther checkOther( &_tokenizer, this );
if ( _settings._checkCodingStyle )
checkOther.CheckUnsignedDivision();
// Give warning when using char variable as array index
// Doesn't work on simplified token list ('unsigned')
if ( _settings._checkCodingStyle )
checkOther.CheckCharVariable();
// Including header which is not needed (too many false positives)
// if ( _settings._checkCodingStyle )
// {
// CheckHeaders checkHeaders( &tokenizer );
// checkHeaders.WarningIncludeHeader();
// }
_tokenizer.simplifyTokenList();
if ( _settings._checkFunctionUsage )
_checkFunctionUsage.parseTokens(_tokenizer);
// Memory leak
CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this );
checkMemoryLeak.CheckMemoryLeak();
// Buffer overruns..
CheckBufferOverrunClass checkBufferOverrun( &_tokenizer, _settings, this );
checkBufferOverrun.CheckBufferOverrun();
// Check that all class constructors are ok.
checkClass.CheckConstructors();
// Check that all base classes have virtual destructors
checkClass.virtualDestructor();
if (_settings._showAll)
{
// Check for "if (a=b)"
checkOther.CheckIfAssignment();
// Check for case without break
// Disabled because it generates many false positives
// CheckCaseWithoutBreak();
// Dangerous usage of strtok
// Disabled because it generates false positives
//WarningStrTok();
}
// Dangerous functions, such as 'gets' and 'scanf'
checkBufferOverrun.WarningDangerousFunctions();
// Invalid function usage..
checkOther.InvalidFunctionUsage();
if (_settings._checkCodingStyle)
{
// Check that all private functions are called.
checkClass.CheckUnusedPrivateFunctions();
// Warning upon c-style pointer casts
const char *ext = strrchr(FileName, '.');
if (ext && strcmp(ext,".cpp")==0)
checkOther.WarningOldStylePointerCast();
checkClass.CheckOperatorEq1();
// if (a) delete a;
checkOther.WarningRedundantCode();
// if (condition);
checkOther.WarningIf();
// Variable scope (check if the scope could be limited)
//CheckVariableScope();
// Check if a constant function parameter is passed by value
checkOther.CheckConstantFunctionParameter();
// Unused struct members..
checkOther.CheckStructMemberUsage();
// Check for various types of incomplete statements that could for example
// mean that an ';' has been added by accident
checkOther.CheckIncompleteStatement();
// Unreachable code below a 'return' statement
checkOther.unreachableCode();
// Usage of local functions
checkOther.functionVariableUsage();
}
}
//---------------------------------------------------------------------------
void CppCheck::reportErr( const std::string &errmsg)
{
if ( /*OnlyReportUniqueErrors*/ true )
{
if ( std::find( _errorList.begin(), _errorList.end(), errmsg ) != _errorList.end() )
return;
_errorList.push_back( errmsg );
}
std::string errmsg2( errmsg );
if ( _settings._verbose )
{
errmsg2 += "\n Defines=\'" + cfg + "\'\n";
}
_errorLogger->reportErr( errmsg2 );
_errout << errmsg2 << std::endl;
}
void CppCheck::reportOut( const std::string &outmsg)
{
// This is currently never called. It is here just to comply with
// the interface.
}

View File

@ -1,126 +1,126 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef CPPCHECK_H
#define CPPCHECK_H
#include <string>
#include <list>
#include <sstream>
#include <vector>
#include <map>
#include "settings.h"
#include "errorlogger.h"
#include "checkfunctionusage.h"
/**
* This is the base class which will use other classes to do
* static code analysis for C and C++ code to find possible
* errors or places that could be improved.
* Usage: See check() for more info.
*/
class CppCheck : public ErrorLogger
{
public:
/**
* Constructor.
*/
CppCheck( ErrorLogger &errorLogger );
/**
* Destructor.
*/
virtual ~CppCheck();
/**
* This starts the actual checking. Note that you must call
* parseFromArgs() or settings() and addFile() before calling this.
*/
void check();
/**
* Adjust the settings before doing the check. E.g. show only
* actual bugs or also coding style issues.
*
* @param settings New settings which will overwrite the old.
*/
void settings( const Settings &settings );
/**
* Add new 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)
* should be added to the list. Include filese are gathered automatically.
*/
void addFile( const std::string &path );
/**
* Add new unreal file to be checked.
*
* @param path File name (used for error reporting).
* @param content If the file would be a real file, this should be
* the content of the file.
*/
void addFile( const std::string &path, const std::string &content );
/**
* Parse command line args and get settings and file lists
* from there.
*
* @param argc argc from main()
* @param argv argv from main()
* @return Empty string if parameters were accepted, or
* string containing "help" text if no files were found to be
* checked.
*/
std::string parseFromArgs( int argc, const char* const argv[] );
private:
void checkFile(const std::string &code, const char FileName[]);
/**
* Errors and warnings are directed here.
*
* @param errmsg Errors messages are normally in format
* "[filepath:line number] Message", e.g.
* "[main.cpp:4] Uninitialized member variable"
*/
virtual void reportErr( const std::string &errmsg);
/**
* Information about progress is directed here.
*
* @param outmsg, E.g. "Checking main.cpp..."
*/
virtual void reportOut( const std::string &outmsg);
std::list<std::string> _errorList;
std::ostringstream _errout;
Settings _settings;
std::vector<std::string> _filenames;
/** Key is file name, and value is the content of the file */
std::map<std::string,std::string> _fileContents;
CheckFunctionUsage _checkFunctionUsage;
ErrorLogger *_errorLogger;
/** Current configuration */
std::string cfg;
};
#endif // CPPCHECK_H
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef CPPCHECK_H
#define CPPCHECK_H
#include <string>
#include <list>
#include <sstream>
#include <vector>
#include <map>
#include "settings.h"
#include "errorlogger.h"
#include "checkfunctionusage.h"
/**
* This is the base class which will use other classes to do
* static code analysis for C and C++ code to find possible
* errors or places that could be improved.
* Usage: See check() for more info.
*/
class CppCheck : public ErrorLogger
{
public:
/**
* Constructor.
*/
CppCheck( ErrorLogger &errorLogger );
/**
* Destructor.
*/
virtual ~CppCheck();
/**
* This starts the actual checking. Note that you must call
* parseFromArgs() or settings() and addFile() before calling this.
*/
void check();
/**
* Adjust the settings before doing the check. E.g. show only
* actual bugs or also coding style issues.
*
* @param settings New settings which will overwrite the old.
*/
void settings( const Settings &settings );
/**
* Add new 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)
* should be added to the list. Include filese are gathered automatically.
*/
void addFile( const std::string &path );
/**
* Add new unreal file to be checked.
*
* @param path File name (used for error reporting).
* @param content If the file would be a real file, this should be
* the content of the file.
*/
void addFile( const std::string &path, const std::string &content );
/**
* Parse command line args and get settings and file lists
* from there.
*
* @param argc argc from main()
* @param argv argv from main()
* @return Empty string if parameters were accepted, or
* string containing "help" text if no files were found to be
* checked.
*/
std::string parseFromArgs( int argc, const char* const argv[] );
private:
void checkFile(const std::string &code, const char FileName[]);
/**
* Errors and warnings are directed here.
*
* @param errmsg Errors messages are normally in format
* "[filepath:line number] Message", e.g.
* "[main.cpp:4] Uninitialized member variable"
*/
virtual void reportErr( const std::string &errmsg);
/**
* Information about progress is directed here.
*
* @param outmsg, E.g. "Checking main.cpp..."
*/
virtual void reportOut( const std::string &outmsg);
std::list<std::string> _errorList;
std::ostringstream _errout;
Settings _settings;
std::vector<std::string> _filenames;
/** Key is file name, and value is the content of the file */
std::map<std::string,std::string> _fileContents;
CheckFunctionUsage _checkFunctionUsage;
ErrorLogger *_errorLogger;
/** Current configuration */
std::string cfg;
};
#endif // CPPCHECK_H

View File

@ -1,51 +1,51 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "cppcheckexecutor.h"
#include "cppcheck.h"
#include <iostream>
CppCheckExecutor::CppCheckExecutor()
{
//ctor
}
CppCheckExecutor::~CppCheckExecutor()
{
//dtor
}
void CppCheckExecutor::check( int argc, const char* const argv[] )
{
CppCheck cppCheck( *this );
std::string result = cppCheck.parseFromArgs( argc, argv );
if( result.length() == 0 )
cppCheck.check();
else
std::cout << result;
}
void CppCheckExecutor::reportErr( const std::string &errmsg)
{
std::cerr << errmsg << std::endl;
}
void CppCheckExecutor::reportOut( const std::string &outmsg)
{
std::cout << outmsg << std::endl;
}
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "cppcheckexecutor.h"
#include "cppcheck.h"
#include <iostream>
CppCheckExecutor::CppCheckExecutor()
{
//ctor
}
CppCheckExecutor::~CppCheckExecutor()
{
//dtor
}
void CppCheckExecutor::check( int argc, const char* const argv[] )
{
CppCheck cppCheck( *this );
std::string result = cppCheck.parseFromArgs( argc, argv );
if( result.length() == 0 )
cppCheck.check();
else
std::cout << result;
}
void CppCheckExecutor::reportErr( const std::string &errmsg)
{
std::cerr << errmsg << std::endl;
}
void CppCheckExecutor::reportOut( const std::string &outmsg)
{
std::cout << outmsg << std::endl;
}

View File

@ -1,71 +1,71 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef CPPCHECKEXECUTOR_H
#define CPPCHECKEXECUTOR_H
#include "errorlogger.h"
/**
* 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
* 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
* from CppCheck class instead the ones used here.
*/
class CppCheckExecutor : public ErrorLogger
{
public:
/**
* Constructor
*/
CppCheckExecutor();
/**
* Destructor
*/
virtual ~CppCheckExecutor();
/**
* Starts the checking.
*
* @param argc from main()
* @param argv from main()
*/
void check( int argc, const char* const argv[] );
/**
* Errors and warnings are directed here. This should be
* called by the CppCheck class only.
*
* @param errmsg Errors messages are normally in format
* "[filepath:line number] Message", e.g.
* "[main.cpp:4] Uninitialized member variable"
*/
virtual void reportErr( const std::string &errmsg);
/**
* Information about progress is directed here. This should be
* called by the CppCheck class only.
*
* @param outmsg, E.g. "Checking main.cpp..."
*/
virtual void reportOut( const std::string &outmsg);
};
#endif // CPPCHECKEXECUTOR_H
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef CPPCHECKEXECUTOR_H
#define CPPCHECKEXECUTOR_H
#include "errorlogger.h"
/**
* 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
* 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
* from CppCheck class instead the ones used here.
*/
class CppCheckExecutor : public ErrorLogger
{
public:
/**
* Constructor
*/
CppCheckExecutor();
/**
* Destructor
*/
virtual ~CppCheckExecutor();
/**
* Starts the checking.
*
* @param argc from main()
* @param argv from main()
*/
void check( int argc, const char* const argv[] );
/**
* Errors and warnings are directed here. This should be
* called by the CppCheck class only.
*
* @param errmsg Errors messages are normally in format
* "[filepath:line number] Message", e.g.
* "[main.cpp:4] Uninitialized member variable"
*/
virtual void reportErr( const std::string &errmsg);
/**
* Information about progress is directed here. This should be
* called by the CppCheck class only.
*
* @param outmsg, E.g. "Checking main.cpp..."
*/
virtual void reportOut( const std::string &outmsg);
};
#endif // CPPCHECKEXECUTOR_H

View File

@ -1,50 +1,50 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef ERRORLOGGER_H
#define ERRORLOGGER_H
#include <string>
/**
* This is an interface, which the class responsible of error logging
* should implement.
*/
class ErrorLogger
{
public:
virtual ~ErrorLogger() {}
/**
* Errors and warnings are directed here.
*
* @param errmsg Errors messages are normally in format
* "[filepath:line number] Message", e.g.
* "[main.cpp:4] Uninitialized member variable"
*/
virtual void reportErr( const std::string &errmsg) = 0;
/**
* Information about progress is directed here.
*
* @param outmsg, E.g. "Checking main.cpp..."
*/
virtual void reportOut( const std::string &outmsg) = 0;
};
#endif // #ifndef ERRORLOGGER_H
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef ERRORLOGGER_H
#define ERRORLOGGER_H
#include <string>
/**
* This is an interface, which the class responsible of error logging
* should implement.
*/
class ErrorLogger
{
public:
virtual ~ErrorLogger() {}
/**
* Errors and warnings are directed here.
*
* @param errmsg Errors messages are normally in format
* "[filepath:line number] Message", e.g.
* "[main.cpp:4] Uninitialized member variable"
*/
virtual void reportErr( const std::string &errmsg) = 0;
/**
* Information about progress is directed here.
*
* @param outmsg, E.g. "Checking main.cpp..."
*/
virtual void reportOut( const std::string &outmsg) = 0;
};
#endif // #ifndef ERRORLOGGER_H

View File

@ -1,210 +1,210 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "filelister.h"
#include <sstream>
#include <vector>
#include <string>
#ifdef __GNUC__
#include <glob.h>
#include <unistd.h>
#endif
#if defined(__BORLANDC__) || defined(_MSC_VER)
#include <windows.h>
#endif
std::string FileLister::simplifyPath( const char *originalPath )
{
std::string subPath = "";
std::vector<std::string> pathParts;
for( ; *originalPath; ++originalPath )
{
if( *originalPath == '/' )
{
if( subPath.length() > 0 )
{
pathParts.push_back( subPath );
subPath = "";
}
pathParts.push_back( "/" );
}
else
subPath.append( 1, *originalPath );
}
if( subPath.length() > 0 )
pathParts.push_back( subPath );
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
{
if( pathParts[i] == ".." && i > 1 )
{
pathParts.erase( pathParts.begin() + i );
pathParts.erase( pathParts.begin()+i-1 );
pathParts.erase( pathParts.begin()+i-2 );
i = 0;
}
else if( i > 0 && pathParts[i] == "." )
{
pathParts.erase( pathParts.begin()+i );
i = 0;
}
else if( pathParts[i] == "/" && i > 0 && pathParts[i-1] == "/" )
{
pathParts.erase( pathParts.begin()+i-1 );
i = 0;
}
}
std::ostringstream oss;
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
{
oss << pathParts[i];
}
return oss.str();
}
bool FileLister::AcceptFile( const std::string &filename )
{
std::string::size_type dotLocation = filename.find_last_of ( '.' );
if ( dotLocation == std::string::npos )
return false;
std::string extension = filename.substr( dotLocation );
if( extension == ".cpp" ||
extension == ".cxx" ||
extension == ".cc" ||
extension == ".c" )
{
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
////// This code is for __GNUC__ only /////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef __GNUC__
// gcc / cygwin..
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
{
std::ostringstream oss;
oss << path;
if( recursive )
{
if ( path.length() > 0 && path[path.length()-1] != '/' )
oss << "/";
oss << "*";
}
glob_t glob_results;
glob( oss.str().c_str(), GLOB_MARK, 0, &glob_results);
for ( unsigned int i = 0; i < glob_results.gl_pathc; i++ )
{
std::string filename = glob_results.gl_pathv[i];
if ( filename == "." || filename == ".." || filename.length() == 0 )
continue;
if ( filename[filename.length()-1] != '/' )
{
// File
// If recursive is not used, accept all files given by user
if( !recursive || FileLister::AcceptFile( filename ) )
filenames.push_back( filename );
}
else if( recursive )
{
// Directory
FileLister::RecursiveAddFiles( filenames, filename, recursive );
}
}
globfree(&glob_results);
}
#endif
///////////////////////////////////////////////////////////////////////////////
////// This code is for Borland C++ and Visual C++ ////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#if defined(__BORLANDC__) || defined(_MSC_VER)
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
{
std::ostringstream bdir, oss;
oss << path;
if (recursive)
{
bdir << path;
if ( path.length() > 0 && path[path.length()-1] != '/' )
{
bdir << "/";
oss << "/";
}
oss << "*";
}
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(oss.str().c_str(), &ffd);
if ( INVALID_HANDLE_VALUE == hFind )
return;
do
{
std::ostringstream fname;
fname << bdir.str().c_str() << ffd.cFileName;
if ( ffd.cFileName[0] == '.' || ffd.cFileName[0] == '\0' )
continue;
if ( ( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
{
// File
// If recursive is not used, accept all files given by user
if ( !recursive || FileLister::AcceptFile( ffd.cFileName ) )
filenames.push_back( fname.str() );
}
else if ( recursive )
{
// Directory
fname << "/";
FileLister::RecursiveAddFiles( filenames, fname.str().c_str(), recursive );
}
}
while (FindNextFile(hFind, &ffd) != FALSE);
FindClose(hFind);
}
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "filelister.h"
#include <sstream>
#include <vector>
#include <string>
#ifdef __GNUC__
#include <glob.h>
#include <unistd.h>
#endif
#if defined(__BORLANDC__) || defined(_MSC_VER)
#include <windows.h>
#endif
std::string FileLister::simplifyPath( const char *originalPath )
{
std::string subPath = "";
std::vector<std::string> pathParts;
for( ; *originalPath; ++originalPath )
{
if( *originalPath == '/' )
{
if( subPath.length() > 0 )
{
pathParts.push_back( subPath );
subPath = "";
}
pathParts.push_back( "/" );
}
else
subPath.append( 1, *originalPath );
}
if( subPath.length() > 0 )
pathParts.push_back( subPath );
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
{
if( pathParts[i] == ".." && i > 1 )
{
pathParts.erase( pathParts.begin() + i );
pathParts.erase( pathParts.begin()+i-1 );
pathParts.erase( pathParts.begin()+i-2 );
i = 0;
}
else if( i > 0 && pathParts[i] == "." )
{
pathParts.erase( pathParts.begin()+i );
i = 0;
}
else if( pathParts[i] == "/" && i > 0 && pathParts[i-1] == "/" )
{
pathParts.erase( pathParts.begin()+i-1 );
i = 0;
}
}
std::ostringstream oss;
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
{
oss << pathParts[i];
}
return oss.str();
}
bool FileLister::AcceptFile( const std::string &filename )
{
std::string::size_type dotLocation = filename.find_last_of ( '.' );
if ( dotLocation == std::string::npos )
return false;
std::string extension = filename.substr( dotLocation );
if( extension == ".cpp" ||
extension == ".cxx" ||
extension == ".cc" ||
extension == ".c" )
{
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
////// This code is for __GNUC__ only /////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef __GNUC__
// gcc / cygwin..
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
{
std::ostringstream oss;
oss << path;
if( recursive )
{
if ( path.length() > 0 && path[path.length()-1] != '/' )
oss << "/";
oss << "*";
}
glob_t glob_results;
glob( oss.str().c_str(), GLOB_MARK, 0, &glob_results);
for ( unsigned int i = 0; i < glob_results.gl_pathc; i++ )
{
std::string filename = glob_results.gl_pathv[i];
if ( filename == "." || filename == ".." || filename.length() == 0 )
continue;
if ( filename[filename.length()-1] != '/' )
{
// File
// If recursive is not used, accept all files given by user
if( !recursive || FileLister::AcceptFile( filename ) )
filenames.push_back( filename );
}
else if( recursive )
{
// Directory
FileLister::RecursiveAddFiles( filenames, filename, recursive );
}
}
globfree(&glob_results);
}
#endif
///////////////////////////////////////////////////////////////////////////////
////// This code is for Borland C++ and Visual C++ ////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#if defined(__BORLANDC__) || defined(_MSC_VER)
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
{
std::ostringstream bdir, oss;
oss << path;
if (recursive)
{
bdir << path;
if ( path.length() > 0 && path[path.length()-1] != '/' )
{
bdir << "/";
oss << "/";
}
oss << "*";
}
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(oss.str().c_str(), &ffd);
if ( INVALID_HANDLE_VALUE == hFind )
return;
do
{
std::ostringstream fname;
fname << bdir.str().c_str() << ffd.cFileName;
if ( ffd.cFileName[0] == '.' || ffd.cFileName[0] == '\0' )
continue;
if ( ( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
{
// File
// If recursive is not used, accept all files given by user
if ( !recursive || FileLister::AcceptFile( ffd.cFileName ) )
filenames.push_back( fname.str() );
}
else if ( recursive )
{
// Directory
fname << "/";
FileLister::RecursiveAddFiles( filenames, fname.str().c_str(), recursive );
}
}
while (FindNextFile(hFind, &ffd) != FALSE);
FindClose(hFind);
}
#endif

View File

@ -1,47 +1,47 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef FileListerH
#define FileListerH
#include <vector>
#include <string>
// Check that the compiler are supported
// This program should be compiled with either GCC/BORLAND/MSC to work..
#ifndef __GNUC__
#ifndef __BORLANDC__
#ifndef _MSC_VER
#error "C++Check must be compiled by either GCC/BORLAND/MSC to work fully.\n"
#error "Please report that you couldn't compile c++check through the web page:\n"
#error " https://sourceforge.net/projects/cppcheck/"
#endif
#endif
#endif
class FileLister
{
public:
static void RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive );
static std::string simplifyPath( const char *originalPath );
private:
static bool AcceptFile( const std::string &filename );
};
#endif // #ifndef FILELISTER_H
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef FileListerH
#define FileListerH
#include <vector>
#include <string>
// Check that the compiler are supported
// This program should be compiled with either GCC/BORLAND/MSC to work..
#ifndef __GNUC__
#ifndef __BORLANDC__
#ifndef _MSC_VER
#error "C++Check must be compiled by either GCC/BORLAND/MSC to work fully.\n"
#error "Please report that you couldn't compile c++check through the web page:\n"
#error " https://sourceforge.net/projects/cppcheck/"
#endif
#endif
#endif
class FileLister
{
public:
static void RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive );
static std::string simplifyPath( const char *originalPath );
private:
static bool AcceptFile( const std::string &filename );
};
#endif // #ifndef FILELISTER_H

View File

@ -1,33 +1,33 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "cppcheckexecutor.h"
/**
* Main function of cppcheck
*
* @param argc Passed to CppCheck::parseFromArgs()
* @param argv Passed to CppCheck::parseFromArgs()
* @return 0
*/
int main(int argc, char* argv[])
{
CppCheckExecutor exec;
exec.check( argc, argv );
return 0;
}
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "cppcheckexecutor.h"
/**
* Main function of cppcheck
*
* @param argc Passed to CppCheck::parseFromArgs()
* @param argv Passed to CppCheck::parseFromArgs()
* @return 0
*/
int main(int argc, char* argv[])
{
CppCheckExecutor exec;
exec.check( argc, argv );
return 0;
}

View File

@ -1,375 +1,375 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "preprocessor.h"
#include <algorithm>
#include <sstream>
#ifdef __BORLANDC__
#include <ctype>
#endif
Preprocessor::Preprocessor()
{
}
/** Just read the code into a string. Perform simple cleanup of the code */
std::string Preprocessor::read(std::istream &istr, const std::string &filename)
{
// Get filedata from stream..
bool ignoreSpace = true;
// For the error report
int lineno = 1;
std::ostringstream code;
for (char ch = (char)istr.get(); istr.good(); ch = (char)istr.get())
{
if ( ch < 0 )
continue;
if ( ch == '\n' )
++lineno;
// Replace assorted special chars with spaces..
if ( (ch != '\n') && (isspace(ch) || iscntrl(ch)) )
ch = ' ';
// Skip spaces after ' ' and after '#'
if ( ch == ' ' && ignoreSpace )
continue;
ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/');
// Remove comments..
if ( ch == '/' )
{
char chNext = (char)istr.get();
if ( chNext == '/' )
{
while (istr.good() && ch!='\n')
ch = (char)istr.get();
code << "\n";
++lineno;
}
else if ( chNext == '*' )
{
char chPrev = 0;
while (istr.good() && (chPrev!='*' || ch!='/'))
{
chPrev = ch;
ch = (char)istr.get();
if (ch == '\n')
{
code << "\n";
++lineno;
}
}
}
else
{
if ( chNext == '\n' )
++lineno;
code << std::string(1,ch) << std::string(1,chNext);
}
}
// String constants..
else if ( ch == '\"' )
{
code << "\"";
do
{
ch = (char)istr.get();
code << std::string(1,ch);
if ( ch == '\\' )
{
ch = (char)istr.get();
code << std::string(1,ch);
// Avoid exiting loop if string contains "-characters
ch = 0;
}
} while ( istr.good() && ch != '\"' );
}
// char constants..
else if ( ch == '\'' )
{
code << "\'";
ch = (char)istr.get();
code << std::string(1,ch);
if ( ch == '\\' )
{
ch = (char)istr.get();
code << std::string(1,ch);
}
ch = (char)istr.get();
code << "\'";
}
// Just some code..
else
{
code << std::string(1, ch);
}
}
return code.str();
}
/**
* Extract the code for each configuration
* \param istr The (file/string) stream to read from.
* \param result The map that will get the results
*/
void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename)
{
std::string codestr( read(istr, filename) );
// Replace all tabs with spaces..
std::string::size_type loc = 0;
while ( (loc = codestr.find("\t", loc)) != std::string::npos )
codestr[loc] = ' ';
// Remove all indentation..
if ( !codestr.empty() && codestr[0] == ' ' )
codestr.erase( 0, codestr.find_first_not_of(" ") );
loc = 0;
while ( (loc = codestr.find("\n ", loc)) != std::string::npos )
codestr.erase( 1 + loc, 1 );
// Remove all trailing spaces..
loc = 0;
while ( (loc = codestr.find(" \n", loc)) != std::string::npos )
{
codestr.erase( loc, 1 );
if ( loc > 0 )
--loc;
}
// Using the backslash at the end of a line..
while ( (loc = codestr.rfind("\\\n")) != std::string::npos )
{
codestr.erase(loc, 2);
if (loc > 0 && codestr[loc-1] != ' ')
codestr.insert(loc, " ");
if ( (loc = codestr.find("\n", loc)) != std::string::npos)
codestr.insert( loc, "\n" );
}
// Get all possible configurations..
std::list<std::string> cfgs = getcfgs( codestr );
// Extract the code for each possible configuration..
result.clear();
for ( std::list<std::string>::const_iterator it = cfgs.begin(); it != cfgs.end(); ++it )
{
result[ *it ] = getcode( codestr, *it );
}
}
// Get the DEF in this line: "#ifdef DEF"
std::string Preprocessor::getdef(std::string line, bool def)
{
// If def is true, the line must start with "#ifdef"
if ( def && line.find("#ifdef ") != 0 && line.find("#if ") != 0 && line.find("#elif ") != 0 )
{
return "";
}
// If def is false, the line must start with "#ifndef"
if ( !def && line.find("#ifndef ") != 0 )
{
return "";
}
// Remove the "#ifdef" or "#ifndef"
line.erase( 0, line.find(" ") );
// Remove all spaces.
while ( line.find(" ") != std::string::npos )
line.erase( line.find(" "), 1 );
// The remaining string is our result.
return line;
}
std::list<std::string> Preprocessor::getcfgs( const std::string &filedata )
{
std::list<std::string> ret;
ret.push_back("");
std::list<std::string> deflist;
std::istringstream istr(filedata);
std::string line;
while ( getline(istr, line) )
{
std::string def = getdef(line, true) + getdef(line, false);
if (!def.empty())
{
if ( ! deflist.empty() && line.find("#elif ") == 0 )
deflist.pop_back();
deflist.push_back(def);
def = "";
for ( std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)
{
if ( *it == "0" )
break;
if ( *it == "1" )
continue;
if ( ! def.empty() )
def += ";";
def += *it;
}
if (std::find(ret.begin(), ret.end(), def) == ret.end())
ret.push_back( def );
}
if ( line.find("#else") == 0 && ! deflist.empty() )
{
std::string def( ( deflist.back() == "1" ) ? "0" : "1" );
deflist.pop_back();
deflist.push_back( def );
}
if ( line.find("#endif") == 0 && ! deflist.empty() )
deflist.pop_back();
}
return ret;
}
bool Preprocessor::match_cfg_def( std::string cfg, const std::string &def )
{
if ( def == "0" )
return false;
if ( def == "1" )
return true;
if ( cfg.empty() )
return false;
while ( ! cfg.empty() )
{
if ( cfg.find(";") == std::string::npos )
return bool(cfg == def);
std::string _cfg = cfg.substr( 0, cfg.find(";") );
if ( _cfg == def )
return true;
cfg.erase( 0, cfg.find(";") + 1 );
}
return false;
}
std::string Preprocessor::getcode(const std::string &filedata, std::string cfg)
{
std::ostringstream ret;
bool match = true;
std::list<bool> matching_ifdef;
std::list<bool> matched_ifdef;
std::istringstream istr(filedata);
std::string line;
while ( getline(istr, line) )
{
std::string def = getdef( line, true );
std::string ndef = getdef( line, false );
if ( line.find("#elif ") == 0 )
{
if ( matched_ifdef.back() )
{
matching_ifdef.back() = false;
}
else
{
if ( match_cfg_def(cfg, def) )
{
matching_ifdef.back() = true;
matched_ifdef.back() = true;
}
}
}
else if ( ! def.empty() )
{
matching_ifdef.push_back( match_cfg_def(cfg, def) );
matched_ifdef.push_back( matching_ifdef.back() );
}
else if ( ! ndef.empty() )
{
matching_ifdef.push_back( ! match_cfg_def(cfg, ndef) );
matched_ifdef.push_back( matching_ifdef.back() );
}
else if ( line == "#else" )
{
if ( ! matched_ifdef.empty() )
matching_ifdef.back() = ! matched_ifdef.back();
}
else if ( line == "#endif" )
{
if ( ! matched_ifdef.empty() )
matched_ifdef.pop_back();
if ( ! matching_ifdef.empty() )
matching_ifdef.pop_back();
}
if ( !line.empty() && line[0] == '#' )
{
match = true;
for ( std::list<bool>::const_iterator it = matching_ifdef.begin(); it != matching_ifdef.end(); ++it )
match &= bool(*it);
}
if ( ! match )
line = "";
if ( line.find("#if") == 0 ||
line.find("#else") == 0 ||
line.find("#elif") == 0 ||
line.find("#endif") == 0 )
line = "";
ret << line << "\n";
}
return ret.str();
}
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "preprocessor.h"
#include <algorithm>
#include <sstream>
#ifdef __BORLANDC__
#include <ctype>
#endif
Preprocessor::Preprocessor()
{
}
/** Just read the code into a string. Perform simple cleanup of the code */
std::string Preprocessor::read(std::istream &istr, const std::string &filename)
{
// Get filedata from stream..
bool ignoreSpace = true;
// For the error report
int lineno = 1;
std::ostringstream code;
for (char ch = (char)istr.get(); istr.good(); ch = (char)istr.get())
{
if ( ch < 0 )
continue;
if ( ch == '\n' )
++lineno;
// Replace assorted special chars with spaces..
if ( (ch != '\n') && (isspace(ch) || iscntrl(ch)) )
ch = ' ';
// Skip spaces after ' ' and after '#'
if ( ch == ' ' && ignoreSpace )
continue;
ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/');
// Remove comments..
if ( ch == '/' )
{
char chNext = (char)istr.get();
if ( chNext == '/' )
{
while (istr.good() && ch!='\n')
ch = (char)istr.get();
code << "\n";
++lineno;
}
else if ( chNext == '*' )
{
char chPrev = 0;
while (istr.good() && (chPrev!='*' || ch!='/'))
{
chPrev = ch;
ch = (char)istr.get();
if (ch == '\n')
{
code << "\n";
++lineno;
}
}
}
else
{
if ( chNext == '\n' )
++lineno;
code << std::string(1,ch) << std::string(1,chNext);
}
}
// String constants..
else if ( ch == '\"' )
{
code << "\"";
do
{
ch = (char)istr.get();
code << std::string(1,ch);
if ( ch == '\\' )
{
ch = (char)istr.get();
code << std::string(1,ch);
// Avoid exiting loop if string contains "-characters
ch = 0;
}
} while ( istr.good() && ch != '\"' );
}
// char constants..
else if ( ch == '\'' )
{
code << "\'";
ch = (char)istr.get();
code << std::string(1,ch);
if ( ch == '\\' )
{
ch = (char)istr.get();
code << std::string(1,ch);
}
ch = (char)istr.get();
code << "\'";
}
// Just some code..
else
{
code << std::string(1, ch);
}
}
return code.str();
}
/**
* Extract the code for each configuration
* \param istr The (file/string) stream to read from.
* \param result The map that will get the results
*/
void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename)
{
std::string codestr( read(istr, filename) );
// Replace all tabs with spaces..
std::string::size_type loc = 0;
while ( (loc = codestr.find("\t", loc)) != std::string::npos )
codestr[loc] = ' ';
// Remove all indentation..
if ( !codestr.empty() && codestr[0] == ' ' )
codestr.erase( 0, codestr.find_first_not_of(" ") );
loc = 0;
while ( (loc = codestr.find("\n ", loc)) != std::string::npos )
codestr.erase( 1 + loc, 1 );
// Remove all trailing spaces..
loc = 0;
while ( (loc = codestr.find(" \n", loc)) != std::string::npos )
{
codestr.erase( loc, 1 );
if ( loc > 0 )
--loc;
}
// Using the backslash at the end of a line..
while ( (loc = codestr.rfind("\\\n")) != std::string::npos )
{
codestr.erase(loc, 2);
if (loc > 0 && codestr[loc-1] != ' ')
codestr.insert(loc, " ");
if ( (loc = codestr.find("\n", loc)) != std::string::npos)
codestr.insert( loc, "\n" );
}
// Get all possible configurations..
std::list<std::string> cfgs = getcfgs( codestr );
// Extract the code for each possible configuration..
result.clear();
for ( std::list<std::string>::const_iterator it = cfgs.begin(); it != cfgs.end(); ++it )
{
result[ *it ] = getcode( codestr, *it );
}
}
// Get the DEF in this line: "#ifdef DEF"
std::string Preprocessor::getdef(std::string line, bool def)
{
// If def is true, the line must start with "#ifdef"
if ( def && line.find("#ifdef ") != 0 && line.find("#if ") != 0 && line.find("#elif ") != 0 )
{
return "";
}
// If def is false, the line must start with "#ifndef"
if ( !def && line.find("#ifndef ") != 0 )
{
return "";
}
// Remove the "#ifdef" or "#ifndef"
line.erase( 0, line.find(" ") );
// Remove all spaces.
while ( line.find(" ") != std::string::npos )
line.erase( line.find(" "), 1 );
// The remaining string is our result.
return line;
}
std::list<std::string> Preprocessor::getcfgs( const std::string &filedata )
{
std::list<std::string> ret;
ret.push_back("");
std::list<std::string> deflist;
std::istringstream istr(filedata);
std::string line;
while ( getline(istr, line) )
{
std::string def = getdef(line, true) + getdef(line, false);
if (!def.empty())
{
if ( ! deflist.empty() && line.find("#elif ") == 0 )
deflist.pop_back();
deflist.push_back(def);
def = "";
for ( std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)
{
if ( *it == "0" )
break;
if ( *it == "1" )
continue;
if ( ! def.empty() )
def += ";";
def += *it;
}
if (std::find(ret.begin(), ret.end(), def) == ret.end())
ret.push_back( def );
}
if ( line.find("#else") == 0 && ! deflist.empty() )
{
std::string def( ( deflist.back() == "1" ) ? "0" : "1" );
deflist.pop_back();
deflist.push_back( def );
}
if ( line.find("#endif") == 0 && ! deflist.empty() )
deflist.pop_back();
}
return ret;
}
bool Preprocessor::match_cfg_def( std::string cfg, const std::string &def )
{
if ( def == "0" )
return false;
if ( def == "1" )
return true;
if ( cfg.empty() )
return false;
while ( ! cfg.empty() )
{
if ( cfg.find(";") == std::string::npos )
return bool(cfg == def);
std::string _cfg = cfg.substr( 0, cfg.find(";") );
if ( _cfg == def )
return true;
cfg.erase( 0, cfg.find(";") + 1 );
}
return false;
}
std::string Preprocessor::getcode(const std::string &filedata, std::string cfg)
{
std::ostringstream ret;
bool match = true;
std::list<bool> matching_ifdef;
std::list<bool> matched_ifdef;
std::istringstream istr(filedata);
std::string line;
while ( getline(istr, line) )
{
std::string def = getdef( line, true );
std::string ndef = getdef( line, false );
if ( line.find("#elif ") == 0 )
{
if ( matched_ifdef.back() )
{
matching_ifdef.back() = false;
}
else
{
if ( match_cfg_def(cfg, def) )
{
matching_ifdef.back() = true;
matched_ifdef.back() = true;
}
}
}
else if ( ! def.empty() )
{
matching_ifdef.push_back( match_cfg_def(cfg, def) );
matched_ifdef.push_back( matching_ifdef.back() );
}
else if ( ! ndef.empty() )
{
matching_ifdef.push_back( ! match_cfg_def(cfg, ndef) );
matched_ifdef.push_back( matching_ifdef.back() );
}
else if ( line == "#else" )
{
if ( ! matched_ifdef.empty() )
matching_ifdef.back() = ! matched_ifdef.back();
}
else if ( line == "#endif" )
{
if ( ! matched_ifdef.empty() )
matched_ifdef.pop_back();
if ( ! matching_ifdef.empty() )
matching_ifdef.pop_back();
}
if ( !line.empty() && line[0] == '#' )
{
match = true;
for ( std::list<bool>::const_iterator it = matching_ifdef.begin(); it != matching_ifdef.end(); ++it )
match &= bool(*it);
}
if ( ! match )
line = "";
if ( line.find("#if") == 0 ||
line.find("#else") == 0 ||
line.find("#elif") == 0 ||
line.find("#endif") == 0 )
line = "";
ret << line << "\n";
}
return ret.str();
}

View File

@ -1,58 +1,58 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef preprocessorH
#define preprocessorH
//---------------------------------------------------------------------------
#include <map>
#include <istream>
#include <string>
#include <list>
class Preprocessor
{
public:
Preprocessor();
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 */
std::string read(std::istream &istr, const std::string &filename);
private:
/**
* Get preprocessed code for a given configuration
*/
std::string getcode(const std::string &filedata, std::string cfg);
/**
* Get all possible configurations. By looking at the ifdefs and ifndefs in filedata
*/
std::list<std::string> getcfgs( const std::string &filedata );
std::string getdef(std::string line, bool def);
bool match_cfg_def( std::string cfg, const std::string &def );
};
//---------------------------------------------------------------------------
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef preprocessorH
#define preprocessorH
//---------------------------------------------------------------------------
#include <map>
#include <istream>
#include <string>
#include <list>
class Preprocessor
{
public:
Preprocessor();
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 */
std::string read(std::istream &istr, const std::string &filename);
private:
/**
* Get preprocessed code for a given configuration
*/
std::string getcode(const std::string &filedata, std::string cfg);
/**
* Get all possible configurations. By looking at the ifdefs and ifndefs in filedata
*/
std::list<std::string> getcfgs( const std::string &filedata );
std::string getdef(std::string line, bool def);
bool match_cfg_def( std::string cfg, const std::string &def );
};
//---------------------------------------------------------------------------
#endif

View File

@ -1,34 +1,34 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "settings.h"
Settings::Settings()
{
_debug = false;
_showAll = false;
_checkCodingStyle = false;
_errorsOnly = false;
_checkFunctionUsage = false;
_verbose = false;
}
Settings::~Settings()
{
}
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "settings.h"
Settings::Settings()
{
_debug = false;
_showAll = false;
_checkCodingStyle = false;
_errorsOnly = false;
_checkFunctionUsage = false;
_verbose = false;
}
Settings::~Settings()
{
}

View File

@ -1,41 +1,41 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef SETTINGS_H
#define SETTINGS_H
/**
* 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
* future when we might have even more detailed settings.
*/
class Settings
{
public:
Settings();
virtual ~Settings();
bool _debug;
bool _showAll;
bool _checkCodingStyle;
bool _errorsOnly;
bool _checkFunctionUsage;
bool _verbose;
};
#endif // SETTINGS_H
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef SETTINGS_H
#define SETTINGS_H
/**
* 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
* future when we might have even more detailed settings.
*/
class Settings
{
public:
Settings();
virtual ~Settings();
bool _debug;
bool _showAll;
bool _checkCodingStyle;
bool _errorsOnly;
bool _checkFunctionUsage;
bool _verbose;
};
#endif // SETTINGS_H

View File

@ -1,397 +1,397 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkbufferoverrun.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestBufferOverrun : public TestFixture
{
public:
TestBufferOverrun() : TestFixture("TestBufferOverrun")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Assign variable ids
tokenizer.setVarId();
// Fill function list
tokenizer.fillFunctionList();
// Clear the error buffer..
errout.str("");
// Check for buffer overruns..
Settings settings;
settings._showAll = true;
CheckBufferOverrunClass checkBufferOverrun( &tokenizer, settings, this );
checkBufferOverrun.CheckBufferOverrun();
}
void run()
{
TEST_CASE( noerr1 );
TEST_CASE( noerr2 );
TEST_CASE( noerr3 );
TEST_CASE( noerr4 );
TEST_CASE( array_index_1 );
TEST_CASE( array_index_2 );
TEST_CASE( array_index_3 );
TEST_CASE( array_index_4 );
TEST_CASE( array_index_5 );
TEST_CASE( array_index_6 );
TEST_CASE( array_index_7 );
TEST_CASE( array_index_8 );
TEST_CASE( array_index_9 );
TEST_CASE( array_index_10 );
TEST_CASE( array_index_11 );
TEST_CASE( array_index_12 );
TEST_CASE( buffer_overrun_1 );
TEST_CASE( buffer_overrun_2 );
TEST_CASE( varid1 );
TEST_CASE( varid2 );
}
void noerr1()
{
check( "void f()\n"
"{\n"
" if (ab)\n"
" {\n"
" char str[50];\n"
" }\n"
" if (ab)\n"
" {\n"
" char str[50];\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void noerr2()
{
check( "void f1(char *str)\n"
"{\n"
" strcpy(buf,str);\n"
"}\n"
"void f2(char *str)\n"
"{\n"
" strcat(buf,str);\n"
"}\n"
"void f3(char *str)\n"
"{\n"
" sprintf(buf,\"%s\",str);\n"
"}\n"
"void f4(const char str[])\n"
"{\n"
" strcpy(buf, str);\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void noerr3()
{
check( "static void f()\n"
"{\n"
" char data[1];\n"
" return abc.data[1];\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void noerr4()
{
// The memory isn't read or written and therefore there is no error.
check( "static void f()\n"
"{\n"
" char data[100];\n"
" const char *p = &data[100];\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void array_index_1()
{
check("void f()\n"
"{\n"
" char str[0x10];\n"
" str[15] = 0;\n"
" str[16] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
}
void array_index_2()
{
check("void f()\n"
"{\n"
" char *str = new char[0x10];\n"
" str[15] = 0;\n"
" str[16] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
}
void array_index_3()
{
check( "void f()\n"
"{\n"
" int val[50];\n"
" for (i = 0; i < 100; i++)\n"
" sum += val[i];\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Buffer overrun\n"), errout.str() );
}
void array_index_4()
{
check( "const int SIZE = 10;\n"
"void f()\n"
"{\n"
" int i[SIZE];\n"
" i[SIZE] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
}
void array_index_5()
{
check( "void f()\n"
"{\n"
" int i[10];\n"
" i[ sizeof(i) - 1 ] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Array index out of bounds\n"), errout.str() );
}
void array_index_6()
{
check( "struct ABC\n"
"{\n"
" char str[10];\n"
"};\n"
"\n"
"static void f()\n"
"{\n"
" struct ABC abc;\n"
" abc.str[10] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:9]: Array index out of bounds\n"), errout.str() );
}
void array_index_7()
{
check( "struct ABC\n"
"{\n"
" char str[10];\n"
"};\n"
"\n"
"static void f(ABC *abc)\n"
"{\n"
" abc->str[10] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:8]: Array index out of bounds\n"), errout.str() );
}
void array_index_8()
{
check( "const int SIZE = 10;\n"
"\n"
"struct ABC\n"
"{\n"
" char str[SIZE];\n"
"};\n"
"\n"
"static void f()\n"
"{\n"
" struct ABC abc;\n"
" abc.str[SIZE] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:11]: Array index out of bounds\n"), errout.str() );
}
void array_index_9()
{
check( "static void memclr( char *data )\n"
"{\n"
" data[10] = 0;\n"
"}\n"
"\n"
"static void f()\n"
"{\n"
" char str[5];\n"
" memclr( str ); // ERROR\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:9] -> [test.cpp:3]: Array index out of bounds\n"), errout.str() );
}
void array_index_10()
{
check( "struct ABC\n"
"{\n"
" char str[10];\n"
"};\n"
"\n"
"static void memclr( char *data )\n"
"{\n"
" data[10] = 0;\n"
"}\n"
"\n"
"static void f(ABC *abc)\n"
"{\n"
" memclr(abc->str);\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:13] -> [test.cpp:8]: Array index out of bounds\n"), errout.str() );
}
void array_index_11()
{
check( "class ABC\n"
"{\n"
"public:\n"
" ABC();\n"
" char *str[10];\n"
" struct ABC *next;"
"};\n"
"\n"
"static void f()\n"
"{\n"
" for ( ABC *abc = abc1; abc; abc = abc->next() )\n"
" {\n"
" abc->str[10] = 0;\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:12]: Array index out of bounds\n"), errout.str() );
}
void array_index_12()
{
check( "class Fred\n"
"{\n"
"private:\n"
" char str[10];\n"
"public:\n"
" Fred();\n"
"};\n"
"Fred::Fred()\n"
"{\n"
" str[10] = 0;\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string("[test.cpp:10]: Array index out of bounds\n"), err );
}
void buffer_overrun_1()
{
check( "void f()\n"
"{\n"
" char str[3];\n"
" strcpy(str, \"abc\");\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Buffer overrun\n"), errout.str() );
}
void buffer_overrun_2()
{
check( "struct ABC\n"
"{\n"
" char str[5];\n"
"};\n"
"\n"
"static void f(ABC *abc)\n"
"{\n"
" strcpy( abc->str, \"abcdef\" );\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:8]: Buffer overrun\n"), errout.str() );
}
void varid1()
{
check( "void foo()\n"
"{\n"
" char str[10];\n"
" if (str[0])\n"
" {\n"
" char str[50];\n"
" str[30] = 0;\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void varid2()
{
check( "void foo()\n"
"{\n"
" char str[10];\n"
" if (str[0])\n"
" {\n"
" char str[50];\n"
" memset(str,0,50);\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestBufferOverrun )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkbufferoverrun.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestBufferOverrun : public TestFixture
{
public:
TestBufferOverrun() : TestFixture("TestBufferOverrun")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Assign variable ids
tokenizer.setVarId();
// Fill function list
tokenizer.fillFunctionList();
// Clear the error buffer..
errout.str("");
// Check for buffer overruns..
Settings settings;
settings._showAll = true;
CheckBufferOverrunClass checkBufferOverrun( &tokenizer, settings, this );
checkBufferOverrun.CheckBufferOverrun();
}
void run()
{
TEST_CASE( noerr1 );
TEST_CASE( noerr2 );
TEST_CASE( noerr3 );
TEST_CASE( noerr4 );
TEST_CASE( array_index_1 );
TEST_CASE( array_index_2 );
TEST_CASE( array_index_3 );
TEST_CASE( array_index_4 );
TEST_CASE( array_index_5 );
TEST_CASE( array_index_6 );
TEST_CASE( array_index_7 );
TEST_CASE( array_index_8 );
TEST_CASE( array_index_9 );
TEST_CASE( array_index_10 );
TEST_CASE( array_index_11 );
TEST_CASE( array_index_12 );
TEST_CASE( buffer_overrun_1 );
TEST_CASE( buffer_overrun_2 );
TEST_CASE( varid1 );
TEST_CASE( varid2 );
}
void noerr1()
{
check( "void f()\n"
"{\n"
" if (ab)\n"
" {\n"
" char str[50];\n"
" }\n"
" if (ab)\n"
" {\n"
" char str[50];\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void noerr2()
{
check( "void f1(char *str)\n"
"{\n"
" strcpy(buf,str);\n"
"}\n"
"void f2(char *str)\n"
"{\n"
" strcat(buf,str);\n"
"}\n"
"void f3(char *str)\n"
"{\n"
" sprintf(buf,\"%s\",str);\n"
"}\n"
"void f4(const char str[])\n"
"{\n"
" strcpy(buf, str);\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void noerr3()
{
check( "static void f()\n"
"{\n"
" char data[1];\n"
" return abc.data[1];\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void noerr4()
{
// The memory isn't read or written and therefore there is no error.
check( "static void f()\n"
"{\n"
" char data[100];\n"
" const char *p = &data[100];\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void array_index_1()
{
check("void f()\n"
"{\n"
" char str[0x10];\n"
" str[15] = 0;\n"
" str[16] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
}
void array_index_2()
{
check("void f()\n"
"{\n"
" char *str = new char[0x10];\n"
" str[15] = 0;\n"
" str[16] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
}
void array_index_3()
{
check( "void f()\n"
"{\n"
" int val[50];\n"
" for (i = 0; i < 100; i++)\n"
" sum += val[i];\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Buffer overrun\n"), errout.str() );
}
void array_index_4()
{
check( "const int SIZE = 10;\n"
"void f()\n"
"{\n"
" int i[SIZE];\n"
" i[SIZE] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
}
void array_index_5()
{
check( "void f()\n"
"{\n"
" int i[10];\n"
" i[ sizeof(i) - 1 ] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Array index out of bounds\n"), errout.str() );
}
void array_index_6()
{
check( "struct ABC\n"
"{\n"
" char str[10];\n"
"};\n"
"\n"
"static void f()\n"
"{\n"
" struct ABC abc;\n"
" abc.str[10] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:9]: Array index out of bounds\n"), errout.str() );
}
void array_index_7()
{
check( "struct ABC\n"
"{\n"
" char str[10];\n"
"};\n"
"\n"
"static void f(ABC *abc)\n"
"{\n"
" abc->str[10] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:8]: Array index out of bounds\n"), errout.str() );
}
void array_index_8()
{
check( "const int SIZE = 10;\n"
"\n"
"struct ABC\n"
"{\n"
" char str[SIZE];\n"
"};\n"
"\n"
"static void f()\n"
"{\n"
" struct ABC abc;\n"
" abc.str[SIZE] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:11]: Array index out of bounds\n"), errout.str() );
}
void array_index_9()
{
check( "static void memclr( char *data )\n"
"{\n"
" data[10] = 0;\n"
"}\n"
"\n"
"static void f()\n"
"{\n"
" char str[5];\n"
" memclr( str ); // ERROR\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:9] -> [test.cpp:3]: Array index out of bounds\n"), errout.str() );
}
void array_index_10()
{
check( "struct ABC\n"
"{\n"
" char str[10];\n"
"};\n"
"\n"
"static void memclr( char *data )\n"
"{\n"
" data[10] = 0;\n"
"}\n"
"\n"
"static void f(ABC *abc)\n"
"{\n"
" memclr(abc->str);\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:13] -> [test.cpp:8]: Array index out of bounds\n"), errout.str() );
}
void array_index_11()
{
check( "class ABC\n"
"{\n"
"public:\n"
" ABC();\n"
" char *str[10];\n"
" struct ABC *next;"
"};\n"
"\n"
"static void f()\n"
"{\n"
" for ( ABC *abc = abc1; abc; abc = abc->next() )\n"
" {\n"
" abc->str[10] = 0;\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:12]: Array index out of bounds\n"), errout.str() );
}
void array_index_12()
{
check( "class Fred\n"
"{\n"
"private:\n"
" char str[10];\n"
"public:\n"
" Fred();\n"
"};\n"
"Fred::Fred()\n"
"{\n"
" str[10] = 0;\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string("[test.cpp:10]: Array index out of bounds\n"), err );
}
void buffer_overrun_1()
{
check( "void f()\n"
"{\n"
" char str[3];\n"
" strcpy(str, \"abc\");\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Buffer overrun\n"), errout.str() );
}
void buffer_overrun_2()
{
check( "struct ABC\n"
"{\n"
" char str[5];\n"
"};\n"
"\n"
"static void f(ABC *abc)\n"
"{\n"
" strcpy( abc->str, \"abcdef\" );\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:8]: Buffer overrun\n"), errout.str() );
}
void varid1()
{
check( "void foo()\n"
"{\n"
" char str[10];\n"
" if (str[0])\n"
" {\n"
" char str[50];\n"
" str[30] = 0;\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void varid2()
{
check( "void foo()\n"
"{\n"
" char str[10];\n"
" if (str[0])\n"
" {\n"
" char str[50];\n"
" memset(str,0,50);\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestBufferOverrun )

View File

@ -1,105 +1,105 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkother.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestCharVar : public TestFixture
{
public:
TestCharVar() : TestFixture("TestCharVar")
{ }
private:
void run()
{
TEST_CASE( array_index );
TEST_CASE( bitop1 );
TEST_CASE( bitop2 );
}
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check char variable usage..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckCharVariable();
}
void array_index()
{
check( "void foo()\n"
"{\n"
" unsigned char ch = 0x80;\n"
" buf[ch] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
check( "void foo()\n"
"{\n"
" char ch = 0x80;\n"
" buf[ch] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable as array index\n"), errout.str() );
check( "void foo(char ch)\n"
"{\n"
" buf[ch] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Warning - using char variable as array index\n"), errout.str() );
}
void bitop1()
{
check( "void foo()\n"
"{\n"
" char ch;\n"
" result = a | ch;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable in bit operation\n"), errout.str() );
}
void bitop2()
{
check( "void foo()\n"
"{\n"
" char ch;\n"
" func(&ch);\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestCharVar )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkother.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestCharVar : public TestFixture
{
public:
TestCharVar() : TestFixture("TestCharVar")
{ }
private:
void run()
{
TEST_CASE( array_index );
TEST_CASE( bitop1 );
TEST_CASE( bitop2 );
}
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check char variable usage..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckCharVariable();
}
void array_index()
{
check( "void foo()\n"
"{\n"
" unsigned char ch = 0x80;\n"
" buf[ch] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
check( "void foo()\n"
"{\n"
" char ch = 0x80;\n"
" buf[ch] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable as array index\n"), errout.str() );
check( "void foo(char ch)\n"
"{\n"
" buf[ch] = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Warning - using char variable as array index\n"), errout.str() );
}
void bitop1()
{
check( "void foo()\n"
"{\n"
" char ch;\n"
" result = a | ch;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable in bit operation\n"), errout.str() );
}
void bitop2()
{
check( "void foo()\n"
"{\n"
" char ch;\n"
" func(&ch);\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestCharVar )

View File

@ -1,115 +1,115 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkclass.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestClass : public TestFixture
{
public:
TestClass() : TestFixture("TestClass")
{ }
private:
void run()
{
TEST_CASE( virtualDestructor1 ); // Base class not found => no error
TEST_CASE( virtualDestructor2 ); // Base class doesn't have a destructor
TEST_CASE( virtualDestructor3 ); // Base class has a destructor, but it's not virtual
TEST_CASE( virtualDestructor4 ); // Derived class doesn't have a destructor => no error
}
// Check that base classes have virtual destructors
void checkVirtualDestructor(const char code[])
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error log
errout.str("");
// Check..
Settings settings;
CheckClass checkClass( &tokenizer, settings, this );
checkClass.virtualDestructor();
}
void virtualDestructor1()
{
// Base class not found
checkVirtualDestructor("class Derived : public Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
checkVirtualDestructor("class Derived : Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
}
void virtualDestructor2()
{
// Base class doesn't have a destructor
checkVirtualDestructor("class Base { };\n"
"class Derived : public Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string("[test.cpp:1]: Base class Base doesn't have a virtual destructor\n"), errout.str() );
checkVirtualDestructor("class Base { };\n"
"class Derived : Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string(""), errout.str() );
}
void virtualDestructor3()
{
// Base class has a destructor, but it's not virtual
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : public Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : private Fred, public Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
}
void virtualDestructor4()
{
// Derived class doesn't have a destructor => no error
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : public Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : private Fred, public Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestClass )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkclass.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestClass : public TestFixture
{
public:
TestClass() : TestFixture("TestClass")
{ }
private:
void run()
{
TEST_CASE( virtualDestructor1 ); // Base class not found => no error
TEST_CASE( virtualDestructor2 ); // Base class doesn't have a destructor
TEST_CASE( virtualDestructor3 ); // Base class has a destructor, but it's not virtual
TEST_CASE( virtualDestructor4 ); // Derived class doesn't have a destructor => no error
}
// Check that base classes have virtual destructors
void checkVirtualDestructor(const char code[])
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error log
errout.str("");
// Check..
Settings settings;
CheckClass checkClass( &tokenizer, settings, this );
checkClass.virtualDestructor();
}
void virtualDestructor1()
{
// Base class not found
checkVirtualDestructor("class Derived : public Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
checkVirtualDestructor("class Derived : Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
}
void virtualDestructor2()
{
// Base class doesn't have a destructor
checkVirtualDestructor("class Base { };\n"
"class Derived : public Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string("[test.cpp:1]: Base class Base doesn't have a virtual destructor\n"), errout.str() );
checkVirtualDestructor("class Base { };\n"
"class Derived : Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string(""), errout.str() );
}
void virtualDestructor3()
{
// Base class has a destructor, but it's not virtual
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : public Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : private Fred, public Base { public: ~Derived() { (void)11; } };");
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
}
void virtualDestructor4()
{
// Derived class doesn't have a destructor => no error
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : public Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : private Fred, public Base { };");
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestClass )

View File

@ -1,326 +1,326 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkclass.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestConstructors : public TestFixture
{
public:
TestConstructors() : TestFixture("TestConstructors")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check class constructors..
Settings settings;
settings._checkCodingStyle = true;
CheckClass checkClass( &tokenizer, settings, this );
checkClass.CheckConstructors();
}
void run()
{
TEST_CASE( simple1 );
TEST_CASE( simple2 );
TEST_CASE( simple3 );
TEST_CASE( simple4 );
TEST_CASE( initvar_with_this ); // BUG 2190300
TEST_CASE( initvar_if ); // BUG 2190290
TEST_CASE( initvar_operator_eq1 ); // BUG 2190376
TEST_CASE( initvar_operator_eq2 ); // BUG 2190376
TEST_CASE( initvar_operator_eq3 );
TEST_CASE( initvar_same_classname ); // BUG 2208157
TEST_CASE( initvar_chained_assign ); // BUG 2270433
TEST_CASE( initvar_2constructors ); // BUG 2270353
TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor
TEST_CASE( initvar_destructor ); // No variables need to be initialized in a destructor
}
void simple1()
{
check( "class Fred\n"
"{\n"
"public:\n"
" int i;\n"
"};\n" );
std::string actual( errout.str() );
std::string expected( "[test.cpp:1] The class 'Fred' has no constructor\n" );
ASSERT_EQUALS( expected, actual );
}
void simple2()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred() { }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string("[test.cpp:4] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void simple3()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred();\n"
" int i;\n"
"};\n"
"Fred::Fred()\n"
"{ }\n" );
ASSERT_EQUALS( std::string("[test.cpp:7] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void simple4()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred();\n"
" Fred(int _i);\n"
" int i;\n"
"};\n"
"Fred::Fred()\n"
"{ }\n"
"Fred::Fred(int _i)\n"
"{\n"
" i = _i;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:8] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void initvar_with_this()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred()\n"
" { this->i = 0; }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_if()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred()\n"
" {\n"
" if (true)\n"
" i = 0;\n"
" else\n"
" i = 1;\n"
" }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_operator_eq1()
{
// Bug 2190376 - False positive, Uninitialized member variable with operator=
check( "class Fred\n"
"{\n"
"private:\n"
" int i;\n"
"\n"
"public:\n"
" Fred()\n"
" { i = 0; }\n"
"\n"
" Fred(const Fred &fred)\n"
" { *this = fred; }\n"
"\n"
" const Fred & operator=(const Fred &fred)\n"
" { i = fred.i; return *this; }\n"
"};\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_operator_eq2()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred() { i = 0; }\n"
" void operator=() { }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string("[test.cpp:5] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void initvar_operator_eq3()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred() { Init(); }\n"
" void operator=() { Init(); }\n"
"private:\n"
" Init() { i = 0; }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_same_classname()
{
// Bug 2208157 - False positive: Uninitialized variable, same class name
check( "void func1()\n"
"{\n"
" class Fred\n"
" {\n"
" int a;\n"
" Fred() { a = 0; }\n"
" };\n"
"}\n"
"\n"
"void func2()\n"
"{\n"
" class Fred\n"
" {\n"
" int b;\n"
" Fred() { b = 0; }\n"
" };\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_chained_assign()
{
// Bug 2270433 - Uninitialized variable false positive on chained assigns
check( "class c\n"
"{\n"
" c();\n"
"\n"
" int m_iMyInt1;\n"
" int m_iMyInt2;\n"
"}\n"
"\n"
"c::c()\n"
"{\n"
" m_iMyInt1 = m_iMyInt2 = 0;\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_2constructors()
{
check( "class c\n"
"{\n"
" c();\n"
" c(bool b);"
"\n"
" void InitInt();\n"
"\n"
" int m_iMyInt;\n"
" int m_bMyBool;\n"
"}\n"
"\n"
"c::c()\n"
"{\n"
" m_bMyBool = false;\n"
" InitInt();"
"}\n"
"\n"
"c::c(bool b)\n"
"{\n"
" m_bMyBool = b;\n"
" InitInt();\n"
"}\n"
"\n"
"void c::InitInt()\n"
"{\n"
" m_iMyInt = 0;\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_private_constructor()
{
check( "class Fred\n"
"{\n"
"private:\n"
" int var;\n"
" Fred();\n"
"};\n"
"Fred::Fred()\n"
"{ }" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_destructor()
{
check( "class Fred\n"
"{\n"
"private:\n"
" int var;\n"
"public:\n"
" Fred() : var(0) {}\n"
" ~Fred() {}\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestConstructors )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkclass.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestConstructors : public TestFixture
{
public:
TestConstructors() : TestFixture("TestConstructors")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check class constructors..
Settings settings;
settings._checkCodingStyle = true;
CheckClass checkClass( &tokenizer, settings, this );
checkClass.CheckConstructors();
}
void run()
{
TEST_CASE( simple1 );
TEST_CASE( simple2 );
TEST_CASE( simple3 );
TEST_CASE( simple4 );
TEST_CASE( initvar_with_this ); // BUG 2190300
TEST_CASE( initvar_if ); // BUG 2190290
TEST_CASE( initvar_operator_eq1 ); // BUG 2190376
TEST_CASE( initvar_operator_eq2 ); // BUG 2190376
TEST_CASE( initvar_operator_eq3 );
TEST_CASE( initvar_same_classname ); // BUG 2208157
TEST_CASE( initvar_chained_assign ); // BUG 2270433
TEST_CASE( initvar_2constructors ); // BUG 2270353
TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor
TEST_CASE( initvar_destructor ); // No variables need to be initialized in a destructor
}
void simple1()
{
check( "class Fred\n"
"{\n"
"public:\n"
" int i;\n"
"};\n" );
std::string actual( errout.str() );
std::string expected( "[test.cpp:1] The class 'Fred' has no constructor\n" );
ASSERT_EQUALS( expected, actual );
}
void simple2()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred() { }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string("[test.cpp:4] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void simple3()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred();\n"
" int i;\n"
"};\n"
"Fred::Fred()\n"
"{ }\n" );
ASSERT_EQUALS( std::string("[test.cpp:7] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void simple4()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred();\n"
" Fred(int _i);\n"
" int i;\n"
"};\n"
"Fred::Fred()\n"
"{ }\n"
"Fred::Fred(int _i)\n"
"{\n"
" i = _i;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:8] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void initvar_with_this()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred()\n"
" { this->i = 0; }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_if()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred()\n"
" {\n"
" if (true)\n"
" i = 0;\n"
" else\n"
" i = 1;\n"
" }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_operator_eq1()
{
// Bug 2190376 - False positive, Uninitialized member variable with operator=
check( "class Fred\n"
"{\n"
"private:\n"
" int i;\n"
"\n"
"public:\n"
" Fred()\n"
" { i = 0; }\n"
"\n"
" Fred(const Fred &fred)\n"
" { *this = fred; }\n"
"\n"
" const Fred & operator=(const Fred &fred)\n"
" { i = fred.i; return *this; }\n"
"};\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_operator_eq2()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred() { i = 0; }\n"
" void operator=() { }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string("[test.cpp:5] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void initvar_operator_eq3()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred() { Init(); }\n"
" void operator=() { Init(); }\n"
"private:\n"
" Init() { i = 0; }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_same_classname()
{
// Bug 2208157 - False positive: Uninitialized variable, same class name
check( "void func1()\n"
"{\n"
" class Fred\n"
" {\n"
" int a;\n"
" Fred() { a = 0; }\n"
" };\n"
"}\n"
"\n"
"void func2()\n"
"{\n"
" class Fred\n"
" {\n"
" int b;\n"
" Fred() { b = 0; }\n"
" };\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_chained_assign()
{
// Bug 2270433 - Uninitialized variable false positive on chained assigns
check( "class c\n"
"{\n"
" c();\n"
"\n"
" int m_iMyInt1;\n"
" int m_iMyInt2;\n"
"}\n"
"\n"
"c::c()\n"
"{\n"
" m_iMyInt1 = m_iMyInt2 = 0;\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_2constructors()
{
check( "class c\n"
"{\n"
" c();\n"
" c(bool b);"
"\n"
" void InitInt();\n"
"\n"
" int m_iMyInt;\n"
" int m_bMyBool;\n"
"}\n"
"\n"
"c::c()\n"
"{\n"
" m_bMyBool = false;\n"
" InitInt();"
"}\n"
"\n"
"c::c(bool b)\n"
"{\n"
" m_bMyBool = b;\n"
" InitInt();\n"
"}\n"
"\n"
"void c::InitInt()\n"
"{\n"
" m_iMyInt = 0;\n"
"}\n" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err );
}
void initvar_private_constructor()
{
check( "class Fred\n"
"{\n"
"private:\n"
" int var;\n"
" Fred();\n"
"};\n"
"Fred::Fred()\n"
"{ }" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void initvar_destructor()
{
check( "class Fred\n"
"{\n"
"private:\n"
" int var;\n"
"public:\n"
" Fred() : var(0) {}\n"
" ~Fred() {}\n"
"};\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestConstructors )

View File

@ -1,150 +1,150 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for dangerous division..
// such as "svar / uvar". Treating "svar" as unsigned data is not good
#define UNIT_TESTING
#include "tokenize.h"
#include "checkother.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestDivision : public TestFixture
{
public:
TestDivision() : TestFixture("TestDivision")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for unsigned divisions..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckUnsignedDivision();
}
void run()
{
TEST_CASE( division1 );
TEST_CASE( division2 );
TEST_CASE( division3 );
TEST_CASE( division4 );
TEST_CASE( division5 );
TEST_CASE( division6 );
TEST_CASE( division7 );
}
void division1()
{
check( "void f()\n"
"{\n"
" int ivar = -2;\n"
" unsigned int uvar = 2;\n"
" return ivar / uvar;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
}
void division2()
{
check( "void f()\n"
"{\n"
" int ivar = -2;\n"
" unsigned int uvar = 2;\n"
" return uvar / ivar;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
}
void division3()
{
check( "typedef int s32;\n"
"typedef unsigned int u32;\n"
"void f()\n"
"{\n"
" s32 ivar = -2;\n"
" u32 uvar = 2;\n"
" return uvar / ivar;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:7]: Warning: Division with signed and unsigned operators\n"), errout.str() );
}
void division4()
{
check( "void f1()\n"
"{\n"
" int i1;\n"
"}\n"
"\n"
"void f2(unsigned int i1)\n"
"{\n"
" unsigned int i2;\n"
" result = i2 / i1;\n"
);
ASSERT_EQUALS( std::string(""), errout.str() );
}
void division5()
{
check( "#define USER_HASH (16)\n"
"void foo()\n"
"{\n"
" unsigned int val = 32;\n"
" val = val / USER_HASH;\n"
);
ASSERT_EQUALS( std::string(""), errout.str() );
}
void division6()
{
check( "void foo()\n"
"{\n"
" unsigned int val = 32;\n"
" int i = val / -2;\n"
);
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
}
void division7()
{
check( "void foo()\n"
"{\n"
" unsigned int val = 32;\n"
" int i = -96 / val;\n"
);
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
}
};
REGISTER_TEST( TestDivision )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for dangerous division..
// such as "svar / uvar". Treating "svar" as unsigned data is not good
#define UNIT_TESTING
#include "tokenize.h"
#include "checkother.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestDivision : public TestFixture
{
public:
TestDivision() : TestFixture("TestDivision")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for unsigned divisions..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckUnsignedDivision();
}
void run()
{
TEST_CASE( division1 );
TEST_CASE( division2 );
TEST_CASE( division3 );
TEST_CASE( division4 );
TEST_CASE( division5 );
TEST_CASE( division6 );
TEST_CASE( division7 );
}
void division1()
{
check( "void f()\n"
"{\n"
" int ivar = -2;\n"
" unsigned int uvar = 2;\n"
" return ivar / uvar;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
}
void division2()
{
check( "void f()\n"
"{\n"
" int ivar = -2;\n"
" unsigned int uvar = 2;\n"
" return uvar / ivar;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
}
void division3()
{
check( "typedef int s32;\n"
"typedef unsigned int u32;\n"
"void f()\n"
"{\n"
" s32 ivar = -2;\n"
" u32 uvar = 2;\n"
" return uvar / ivar;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:7]: Warning: Division with signed and unsigned operators\n"), errout.str() );
}
void division4()
{
check( "void f1()\n"
"{\n"
" int i1;\n"
"}\n"
"\n"
"void f2(unsigned int i1)\n"
"{\n"
" unsigned int i2;\n"
" result = i2 / i1;\n"
);
ASSERT_EQUALS( std::string(""), errout.str() );
}
void division5()
{
check( "#define USER_HASH (16)\n"
"void foo()\n"
"{\n"
" unsigned int val = 32;\n"
" val = val / USER_HASH;\n"
);
ASSERT_EQUALS( std::string(""), errout.str() );
}
void division6()
{
check( "void foo()\n"
"{\n"
" unsigned int val = 32;\n"
" int i = val / -2;\n"
);
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
}
void division7()
{
check( "void foo()\n"
"{\n"
" unsigned int val = 32;\n"
" int i = -96 / val;\n"
);
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
}
};
REGISTER_TEST( TestDivision )

View File

@ -1,53 +1,53 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include <string>
#include "testsuite.h"
#include "filelister.h"
class TestFileLister : public TestFixture
{
public:
TestFileLister() : TestFixture("TestFileLister")
{ }
private:
void run()
{
TEST_CASE( simplify_path );
}
void simplify_path()
{
ASSERT_EQUALS( std::string( "index.h" ), FileLister::simplifyPath( "index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/index.h" ) );
ASSERT_EQUALS( std::string( "/path/" ), FileLister::simplifyPath( "/path/" ) );
ASSERT_EQUALS( std::string( "/" ), FileLister::simplifyPath( "/" ) );
ASSERT_EQUALS( std::string( "./index.h" ), FileLister::simplifyPath( "./index.h" ) );
ASSERT_EQUALS( std::string( "../index.h" ), FileLister::simplifyPath( "../index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other/../index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other///././../index.h" ) );
ASSERT_EQUALS( std::string( "../path/index.h" ), FileLister::simplifyPath( "../path/other/../index.h" ) );
}
};
REGISTER_TEST( TestFileLister )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include <string>
#include "testsuite.h"
#include "filelister.h"
class TestFileLister : public TestFixture
{
public:
TestFileLister() : TestFixture("TestFileLister")
{ }
private:
void run()
{
TEST_CASE( simplify_path );
}
void simplify_path()
{
ASSERT_EQUALS( std::string( "index.h" ), FileLister::simplifyPath( "index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/index.h" ) );
ASSERT_EQUALS( std::string( "/path/" ), FileLister::simplifyPath( "/path/" ) );
ASSERT_EQUALS( std::string( "/" ), FileLister::simplifyPath( "/" ) );
ASSERT_EQUALS( std::string( "./index.h" ), FileLister::simplifyPath( "./index.h" ) );
ASSERT_EQUALS( std::string( "../index.h" ), FileLister::simplifyPath( "../index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other/../index.h" ) );
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other///././../index.h" ) );
ASSERT_EQUALS( std::string( "../path/index.h" ), FileLister::simplifyPath( "../path/other/../index.h" ) );
}
};
REGISTER_TEST( TestFileLister )

View File

@ -1,105 +1,105 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "testsuite.h"
#include "checkfunctionusage.h"
#include <sstream>
extern std::ostringstream errout;
class TestFunctionUsage : public TestFixture
{
public:
TestFunctionUsage() : TestFixture("TestFunctionUsage")
{ }
private:
void run()
{
TEST_CASE( incondition );
TEST_CASE( return1 );
TEST_CASE( callback1 );
TEST_CASE( else1 );
}
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for unused functions..
CheckFunctionUsage checkFunctionUsage(this);
checkFunctionUsage.parseTokens( tokenizer );
checkFunctionUsage.check();
}
void incondition()
{
check( "int f1()\n"
"{\n"
" if (f1())\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" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestFunctionUsage )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "testsuite.h"
#include "checkfunctionusage.h"
#include <sstream>
extern std::ostringstream errout;
class TestFunctionUsage : public TestFixture
{
public:
TestFunctionUsage() : TestFixture("TestFunctionUsage")
{ }
private:
void run()
{
TEST_CASE( incondition );
TEST_CASE( return1 );
TEST_CASE( callback1 );
TEST_CASE( else1 );
}
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for unused functions..
CheckFunctionUsage checkFunctionUsage(this);
checkFunctionUsage.parseTokens( tokenizer );
checkFunctionUsage.check();
}
void incondition()
{
check( "int f1()\n"
"{\n"
" if (f1())\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" );
std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestFunctionUsage )

View File

@ -1,91 +1,91 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for unused variables..
#define UNIT_TESTING
#include "testsuite.h"
#include "tokenize.h"
#include "checkother.h"
#include <sstream>
extern std::ostringstream errout;
class TestIncompleteStatement : public TestFixture
{
public:
TestIncompleteStatement() : TestFixture("TestIncompleteStatement")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check for unused variables..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckIncompleteStatement();
}
void run()
{
TEST_CASE( test1 );
TEST_CASE( test2 );
}
void test1()
{
check( "void foo()\n"
"{\n"
" const char def[] =\n"
"#ifdef ABC\n"
" \"abc\";\n"
"#else\n"
" \"not abc\";\n"
"#endif\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void test2()
{
// Todo: remove the ';' before the string
check( "void foo()\n"
"{\n"
" ;\"abc\";\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant code: Found a statement that begins with string constant\n"), errout.str() );
}
};
REGISTER_TEST( TestIncompleteStatement )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for unused variables..
#define UNIT_TESTING
#include "testsuite.h"
#include "tokenize.h"
#include "checkother.h"
#include <sstream>
extern std::ostringstream errout;
class TestIncompleteStatement : public TestFixture
{
public:
TestIncompleteStatement() : TestFixture("TestIncompleteStatement")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check for unused variables..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckIncompleteStatement();
}
void run()
{
TEST_CASE( test1 );
TEST_CASE( test2 );
}
void test1()
{
check( "void foo()\n"
"{\n"
" const char def[] =\n"
"#ifdef ABC\n"
" \"abc\";\n"
"#else\n"
" \"not abc\";\n"
"#endif\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void test2()
{
// Todo: remove the ';' before the string
check( "void foo()\n"
"{\n"
" ;\"abc\";\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant code: Found a statement that begins with string constant\n"), errout.str() );
}
};
REGISTER_TEST( TestIncompleteStatement )

File diff suppressed because it is too large Load Diff

View File

@ -1,446 +1,446 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// The preprocessor that c++check uses is a bit special. Instead of generating
// the code for a known configuration, it generates the code for each configuration.
#include "testsuite.h"
#include "preprocessor.h"
#include <map>
#include <string>
class TestPreprocessor : public TestFixture
{
public:
TestPreprocessor() : TestFixture("TestPreprocessor")
{ }
private:
void run()
{
// Just read the code into a string. Perform simple cleanup of the code
TEST_CASE(readCode);
// The bug that started the whole work with the new preprocessor
TEST_CASE( Bug2190219 );
TEST_CASE( test1 );
TEST_CASE( test2 );
TEST_CASE( test3 );
TEST_CASE( test4 );
TEST_CASE( test5 );
TEST_CASE( comments1 );
TEST_CASE( if0 );
TEST_CASE( if1 );
TEST_CASE( elif );
TEST_CASE( include1 );
TEST_CASE( if_cond1 );
TEST_CASE( multiline );
}
void readCode()
{
const char code[] = " \t a //\n"
" #aa\t /* remove this */\tb \r\n";
Preprocessor p;
std::istringstream istr(code);
std::string codestr( p.read(istr,"") );
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)
{
// Begin by checking the sizes
if ( m1.size() != m2.size() )
return false;
// Check each item in the maps..
for ( std::map<std::string,std::string>::const_iterator it1 = m1.begin(); it1 != m1.end(); ++it1 )
{
std::string s1 = it1->first;
std::map<std::string,std::string>::const_iterator it2 = m2.find(s1);
if ( it2 == m2.end() )
return false;
else
{
std::string s1 = it1->second;
std::string s2 = it2->second;
if ( s1 != s2 )
return false;
}
}
// No diffs were found
return true;
}
void Bug2190219()
{
const char filedata[] = "int main()\n"
"{\n"
"#ifdef __cplusplus\n"
" int* flags = new int[10];\n"
"#else\n"
" int* flags = (int*)malloc((10)*sizeof(int));\n"
"#endif\n"
"\n"
"#ifdef __cplusplus\n"
" delete [] flags;\n"
"#else\n"
" free(flags);\n"
"#endif\n"
"}\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "int main()\n"
"{\n"
"\n"
"\n"
"\n"
"int* flags = (int*)malloc((10)*sizeof(int));\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"free(flags);\n"
"\n"
"}\n";
expected["__cplusplus"] = "int main()\n"
"{\n"
"\n"
"int* flags = new int[10];\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"delete [] flags;\n"
"\n"
"\n"
"\n"
"}\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test1()
{
const char filedata[] = "#ifdef WIN32 \n"
" abcdef\n"
"#else \n"
" qwerty\n"
"#endif \n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\nqwerty\n\n";
expected["WIN32"] = "\nabcdef\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test2()
{
const char filedata[] = "# ifndef WIN32\n"
" \" # ifdef WIN32\" // a comment\n"
" # else \n"
" qwerty\n"
" # endif \n";
// Expected result..
std::map<std::string, std::string> expected;
expected["WIN32"] = "\n\n\nqwerty\n\n";
expected[""] = "\n\" # ifdef WIN32\"\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test3()
{
const char filedata[] = "#ifdef ABC\n"
"a\n"
"#ifdef DEF\n"
"b\n"
"#endif\n"
"c\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n\n\n\n";
expected["ABC"] = "\na\n\n\n\nc\n\n";
expected["ABC;DEF"] = "\na\n\nb\n\nc\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test4()
{
const char filedata[] = "#ifdef ABC\n"
"A\n"
"#endif\t\n"
"#ifdef ABC\n"
"A\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n\n\n";
expected["ABC"] = "\nA\n\n\nA\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test5()
{
const char filedata[] = "#ifdef ABC\n"
"A\n"
"#else\n"
"B\n"
"#ifdef DEF\n"
"C\n"
"#endif\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\nB\n\n\n\n\n";
expected["ABC"] = "\nA\n\n\n\n\n\n\n";
expected["DEF"] = "\n\n\nB\n\nC\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void comments1()
{
const char filedata[] = "/*\n"
"#ifdef WIN32\n"
"#endif\n"
"*/\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void if0()
{
const char filedata[] = " # if /* comment */ 0 // comment\n"
"#ifdef WIN32\n"
"#endif\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void if1()
{
const char filedata[] = " # if /* comment */ 1 // comment\n"
"ABC\n"
" # endif \n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\nABC\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void elif()
{
const char filedata[] = "#if DEF1\n"
"ABC\n"
"#elif DEF2\n"
"DEF\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n\n";
expected["DEF1"] = "\nABC\n\n\n\n";
expected["DEF2"] = "\n\n\nDEF\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void include1()
{
const char filedata[] = " # include \"abcd.h\" // abcd\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "#include \"abcd.h\"\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void if_cond1()
{
const char filedata[] = "#if LIBVER>100\n"
" A\n"
"#else\n"
" B\n"
"#endif\n";
std::map<std::string, std::string> expected;
expected[""] = "\n\n\nB\n\n";
expected["LIBVER>100"] = "\nA\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void multiline()
{
const char filedata[] = "#define str \"abc\" \\ \n"
" \"def\" \\ \n"
" \"ghi\" \n";
std::map<std::string, std::string> expected;
expected[""] = "#define str \"abc\" \"def\" \"ghi\"\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
};
REGISTER_TEST( TestPreprocessor )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// The preprocessor that c++check uses is a bit special. Instead of generating
// the code for a known configuration, it generates the code for each configuration.
#include "testsuite.h"
#include "preprocessor.h"
#include <map>
#include <string>
class TestPreprocessor : public TestFixture
{
public:
TestPreprocessor() : TestFixture("TestPreprocessor")
{ }
private:
void run()
{
// Just read the code into a string. Perform simple cleanup of the code
TEST_CASE(readCode);
// The bug that started the whole work with the new preprocessor
TEST_CASE( Bug2190219 );
TEST_CASE( test1 );
TEST_CASE( test2 );
TEST_CASE( test3 );
TEST_CASE( test4 );
TEST_CASE( test5 );
TEST_CASE( comments1 );
TEST_CASE( if0 );
TEST_CASE( if1 );
TEST_CASE( elif );
TEST_CASE( include1 );
TEST_CASE( if_cond1 );
TEST_CASE( multiline );
}
void readCode()
{
const char code[] = " \t a //\n"
" #aa\t /* remove this */\tb \r\n";
Preprocessor p;
std::istringstream istr(code);
std::string codestr( p.read(istr,"") );
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)
{
// Begin by checking the sizes
if ( m1.size() != m2.size() )
return false;
// Check each item in the maps..
for ( std::map<std::string,std::string>::const_iterator it1 = m1.begin(); it1 != m1.end(); ++it1 )
{
std::string s1 = it1->first;
std::map<std::string,std::string>::const_iterator it2 = m2.find(s1);
if ( it2 == m2.end() )
return false;
else
{
std::string s1 = it1->second;
std::string s2 = it2->second;
if ( s1 != s2 )
return false;
}
}
// No diffs were found
return true;
}
void Bug2190219()
{
const char filedata[] = "int main()\n"
"{\n"
"#ifdef __cplusplus\n"
" int* flags = new int[10];\n"
"#else\n"
" int* flags = (int*)malloc((10)*sizeof(int));\n"
"#endif\n"
"\n"
"#ifdef __cplusplus\n"
" delete [] flags;\n"
"#else\n"
" free(flags);\n"
"#endif\n"
"}\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "int main()\n"
"{\n"
"\n"
"\n"
"\n"
"int* flags = (int*)malloc((10)*sizeof(int));\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"free(flags);\n"
"\n"
"}\n";
expected["__cplusplus"] = "int main()\n"
"{\n"
"\n"
"int* flags = new int[10];\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"delete [] flags;\n"
"\n"
"\n"
"\n"
"}\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test1()
{
const char filedata[] = "#ifdef WIN32 \n"
" abcdef\n"
"#else \n"
" qwerty\n"
"#endif \n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\nqwerty\n\n";
expected["WIN32"] = "\nabcdef\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test2()
{
const char filedata[] = "# ifndef WIN32\n"
" \" # ifdef WIN32\" // a comment\n"
" # else \n"
" qwerty\n"
" # endif \n";
// Expected result..
std::map<std::string, std::string> expected;
expected["WIN32"] = "\n\n\nqwerty\n\n";
expected[""] = "\n\" # ifdef WIN32\"\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test3()
{
const char filedata[] = "#ifdef ABC\n"
"a\n"
"#ifdef DEF\n"
"b\n"
"#endif\n"
"c\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n\n\n\n";
expected["ABC"] = "\na\n\n\n\nc\n\n";
expected["ABC;DEF"] = "\na\n\nb\n\nc\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test4()
{
const char filedata[] = "#ifdef ABC\n"
"A\n"
"#endif\t\n"
"#ifdef ABC\n"
"A\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n\n\n";
expected["ABC"] = "\nA\n\n\nA\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void test5()
{
const char filedata[] = "#ifdef ABC\n"
"A\n"
"#else\n"
"B\n"
"#ifdef DEF\n"
"C\n"
"#endif\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\nB\n\n\n\n\n";
expected["ABC"] = "\nA\n\n\n\n\n\n\n";
expected["DEF"] = "\n\n\nB\n\nC\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void comments1()
{
const char filedata[] = "/*\n"
"#ifdef WIN32\n"
"#endif\n"
"*/\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void if0()
{
const char filedata[] = " # if /* comment */ 0 // comment\n"
"#ifdef WIN32\n"
"#endif\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void if1()
{
const char filedata[] = " # if /* comment */ 1 // comment\n"
"ABC\n"
" # endif \n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\nABC\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void elif()
{
const char filedata[] = "#if DEF1\n"
"ABC\n"
"#elif DEF2\n"
"DEF\n"
"#endif\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "\n\n\n\n\n";
expected["DEF1"] = "\nABC\n\n\n\n";
expected["DEF2"] = "\n\n\nDEF\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void include1()
{
const char filedata[] = " # include \"abcd.h\" // abcd\n";
// Expected result..
std::map<std::string, std::string> expected;
expected[""] = "#include \"abcd.h\"\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void if_cond1()
{
const char filedata[] = "#if LIBVER>100\n"
" A\n"
"#else\n"
" B\n"
"#endif\n";
std::map<std::string, std::string> expected;
expected[""] = "\n\n\nB\n\n";
expected["LIBVER>100"] = "\nA\n\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
void multiline()
{
const char filedata[] = "#define str \"abc\" \\ \n"
" \"def\" \\ \n"
" \"ghi\" \n";
std::map<std::string, std::string> expected;
expected[""] = "#define str \"abc\" \"def\" \"ghi\"\n\n\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess( istr, actual, "" );
// Compare results..
ASSERT_EQUALS( true, cmpmaps(actual, expected));
}
};
REGISTER_TEST( TestPreprocessor )

View File

@ -1,87 +1,87 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for dangerous division..
// such as "svar / uvar". Treating "svar" as unsigned data is not good
#define UNIT_TESTING
#include "tokenize.h"
#include "checkother.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestRedundantIf : public TestFixture
{
public:
TestRedundantIf() : TestFixture("TestRedundantIf")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for redundant condition..
CheckOther checkOther( &tokenizer, this );
checkOther.redundantCondition2();
}
void run()
{
TEST_CASE( remove1 );
TEST_CASE( remove2 );
}
void remove1()
{
check( "void f()\n"
"{\n"
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for dangerous division..
// such as "svar / uvar". Treating "svar" as unsigned data is not good
#define UNIT_TESTING
#include "tokenize.h"
#include "checkother.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestRedundantIf : public TestFixture
{
public:
TestRedundantIf() : TestFixture("TestRedundantIf")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for redundant condition..
CheckOther checkOther( &tokenizer, this );
checkOther.redundantCondition2();
}
void run()
{
TEST_CASE( remove1 );
TEST_CASE( remove2 );
}
void remove1()
{
check( "void f()\n"
"{\n"
" if (haystack.find(needle) != haystack.end())\n"
" haystack.remove(needle);"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
}
void remove2()
{
check( "void f()\n"
"{\n"
" haystack.remove(needle);"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
}
void remove2()
{
check( "void f()\n"
"{\n"
" if (haystack.find(needle) != haystack.end())\n"
" {\n"
" haystack.remove(needle);\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
}
};
REGISTER_TEST( TestRedundantIf )
" {\n"
" haystack.remove(needle);\n"
" }\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
}
};
REGISTER_TEST( TestRedundantIf )

View File

@ -1,28 +1,28 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "testsuite.h"
#include <string>
#include <vector>
int main(int argc, const char *argv[])
{
TestFixture::runTests( (argc==2) ? argv[1] : NULL );
return 0;
}
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "testsuite.h"
#include <string>
#include <vector>
int main(int argc, const char *argv[])
{
TestFixture::runTests( (argc==2) ? argv[1] : NULL );
return 0;
}

View File

@ -1,73 +1,73 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "testsuite.h"
#include "tokenize.h"
#include <sstream>
extern std::ostringstream errout;
class TestSimplifyTokens : public TestFixture
{
public:
TestSimplifyTokens() : TestFixture("TestSimplifyTokens")
{ }
private:
void run()
{
TEST_CASE( cast0 );
TEST_CASE( sizeof1 );
}
std::string tok(const char code[])
{
std::istringstream istr(code);
Tokenizer tokenizer;
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
std::string ret;
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
{
ret += tok->str() + " ";
}
return ret;
}
void cast0()
{
const char code1[] = " if ( p == (char *)0 ) ";
const char code2[] = " if ( p == 0 ) ";
ASSERT_EQUALS( tok(code1), tok(code2) );
}
void sizeof1()
{
const char code1[] = " struct ABC *abc = malloc(sizeof(*abc)); ";
const char code2[] = " struct ABC *abc = malloc(100); ";
ASSERT_EQUALS( tok(code1), tok(code2) );
}
};
REGISTER_TEST( TestSimplifyTokens )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "testsuite.h"
#include "tokenize.h"
#include <sstream>
extern std::ostringstream errout;
class TestSimplifyTokens : public TestFixture
{
public:
TestSimplifyTokens() : TestFixture("TestSimplifyTokens")
{ }
private:
void run()
{
TEST_CASE( cast0 );
TEST_CASE( sizeof1 );
}
std::string tok(const char code[])
{
std::istringstream istr(code);
Tokenizer tokenizer;
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
std::string ret;
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
{
ret += tok->str() + " ";
}
return ret;
}
void cast0()
{
const char code1[] = " if ( p == (char *)0 ) ";
const char code2[] = " if ( p == 0 ) ";
ASSERT_EQUALS( tok(code1), tok(code2) );
}
void sizeof1()
{
const char code1[] = " struct ABC *abc = malloc(sizeof(*abc)); ";
const char code2[] = " struct ABC *abc = malloc(100); ";
ASSERT_EQUALS( tok(code1), tok(code2) );
}
};
REGISTER_TEST( TestSimplifyTokens )

View File

@ -1,178 +1,178 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "testsuite.h"
#include <iostream>
#include <list>
std::ostringstream errout;
/**
* TestRegistry
**/
class TestRegistry
{
private:
std::list<TestFixture *> _tests;
public:
static TestRegistry &theInstance()
{
static TestRegistry testreg;
return testreg;
}
void addTest( TestFixture *t )
{
_tests.push_back( t );
}
const std::list<TestFixture *> &tests() const
{
return _tests;
}
};
/**
* TestFixture
**/
std::ostringstream TestFixture::errmsg;
unsigned int TestFixture::countTests;
TestFixture::TestFixture(const std::string &_name) : classname(_name)
{
TestRegistry::theInstance().addTest(this);
}
bool TestFixture::runTest(const char testname[])
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "testsuite.h"
#include <iostream>
#include <list>
std::ostringstream errout;
/**
* TestRegistry
**/
class TestRegistry
{
private:
std::list<TestFixture *> _tests;
public:
static TestRegistry &theInstance()
{
static TestRegistry testreg;
return testreg;
}
void addTest( TestFixture *t )
{
_tests.push_back( t );
}
const std::list<TestFixture *> &tests() const
{
return _tests;
}
};
/**
* TestFixture
**/
std::ostringstream TestFixture::errmsg;
unsigned int TestFixture::countTests;
TestFixture::TestFixture(const std::string &_name) : classname(_name)
{
TestRegistry::theInstance().addTest(this);
}
bool TestFixture::runTest(const char testname[])
{
if ( testToRun.empty() || testToRun == testname )
{
countTests++;
std::cout << classname << "::" << testname << "\n";
{
countTests++;
std::cout << classname << "::" << testname << "\n";
return true;
}
}
return false;
}
static std::string writestr( const std::string &str )
{
std::ostringstream ostr;
ostr << "\"";
for (unsigned int i = 0; i < str.length(); ++i)
{
char ch = str[i];
if ( ch == '\n' )
ostr << "\\n";
else if ( ch == '\t' )
ostr << "\\t";
else if ( ch == '\"' )
ostr << "\\\"";
else
ostr << std::string(1, ch);
}
ostr << "\"";
return ostr.str();
}
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
{
if ( expected != actual )
{
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
<< "Expected:" << std::endl
<< writestr(expected) << std::endl
<< "Actual:" << std::endl
<< writestr(actual) << std::endl;
}
}
void TestFixture::assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual)
{
std::ostringstream ostr1;
ostr1 << expected;
std::ostringstream ostr2;
ostr2 << actual;
assertEquals( filename, linenr, ostr1.str(), ostr2.str() );
}
void TestFixture::printTests()
{
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
{
std::cout << (*it)->classname << std::endl;
}
}
}
static std::string writestr( const std::string &str )
{
std::ostringstream ostr;
ostr << "\"";
for (unsigned int i = 0; i < str.length(); ++i)
{
char ch = str[i];
if ( ch == '\n' )
ostr << "\\n";
else if ( ch == '\t' )
ostr << "\\t";
else if ( ch == '\"' )
ostr << "\\\"";
else
ostr << std::string(1, ch);
}
ostr << "\"";
return ostr.str();
}
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
{
if ( expected != actual )
{
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
<< "Expected:" << std::endl
<< writestr(expected) << std::endl
<< "Actual:" << std::endl
<< writestr(actual) << std::endl;
}
}
void TestFixture::assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual)
{
std::ostringstream ostr1;
ostr1 << expected;
std::ostringstream ostr2;
ostr2 << actual;
assertEquals( filename, linenr, ostr1.str(), ostr2.str() );
}
void TestFixture::printTests()
{
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
{
std::cout << (*it)->classname << std::endl;
}
}
void TestFixture::run(const std::string &str)
{
testToRun = str;
run();
}
void TestFixture::runTests(const char cmd[])
{
std::string classname(cmd ? cmd : "");
std::string testname("");
if ( classname.find("::") != std::string::npos )
{
testname = classname.substr( classname.find("::") + 2 );
classname.erase( classname.find("::") );
}
countTests = 0;
errmsg.str("");
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
{
void TestFixture::runTests(const char cmd[])
{
std::string classname(cmd ? cmd : "");
std::string testname("");
if ( classname.find("::") != std::string::npos )
{
testname = classname.substr( classname.find("::") + 2 );
classname.erase( classname.find("::") );
}
countTests = 0;
errmsg.str("");
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
{
if ( classname.empty() || (*it)->classname == classname )
{
{
(*it)->run(testname);
}
}
std::cout << "\n\nTesting Complete\nNumber of tests: " << countTests << "\n";
std::cerr << errmsg.str();
}
void TestFixture::reportErr( const std::string &errmsg)
{
errout << errmsg << std::endl;
}
void TestFixture::reportOut( const std::string &outmsg)
{
// These can probably be ignored
}
}
}
std::cout << "\n\nTesting Complete\nNumber of tests: " << countTests << "\n";
std::cerr << errmsg.str();
}
void TestFixture::reportErr( const std::string &errmsg)
{
errout << errmsg << std::endl;
}
void TestFixture::reportOut( const std::string &outmsg)
{
// These can probably be ignored
}

View File

@ -1,61 +1,61 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include <sstream>
#include "errorlogger.h"
class TOKEN;
class TestFixture : public ErrorLogger
{
private:
static std::ostringstream errmsg;
static unsigned int countTests;
protected:
std::string classname;
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include <sstream>
#include "errorlogger.h"
class TOKEN;
class TestFixture : public ErrorLogger
{
private:
static std::ostringstream errmsg;
static unsigned int countTests;
protected:
std::string classname;
std::string testToRun;
virtual void run() = 0;
bool runTest(const char testname[]);
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);
public:
virtual void reportErr( const std::string &errmsg);
virtual void reportOut( const std::string &outmsg);
virtual void run() = 0;
bool runTest(const char testname[]);
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);
public:
virtual void reportErr( const std::string &errmsg);
virtual void reportOut( const std::string &outmsg);
void run(const std::string &str);
TestFixture(const std::string &_name);
virtual ~TestFixture() { }
static void printTests();
static void runTests(const char cmd[]);
};
#define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME ();
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance; }
TestFixture(const std::string &_name);
virtual ~TestFixture() { }
static void printTests();
static void runTests(const char cmd[]);
};
#define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME ();
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance; }

View File

@ -1,61 +1,61 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include <cstring>
#include "testsuite.h"
#include "token.h"
extern std::ostringstream errout;
class TestTOKEN : public TestFixture
{
public:
TestTOKEN() : TestFixture("TestTOKEN")
{ }
private:
void run()
{
TEST_CASE( nextprevious );
}
void nextprevious()
{
TOKEN *token = new TOKEN;
token->setstr( "1" );
token->insertToken( "2" );
token->next()->insertToken( "3" );
TOKEN *last = token->next()->next();
ASSERT_EQUALS( token->str(), "1" );
ASSERT_EQUALS( token->next()->str(), "2" );
ASSERT_EQUALS( token->next()->next()->str(), "3" );
if( last->next() )
ASSERT_EQUALS( "Null was expected", "" );
ASSERT_EQUALS( last->str(), "3" );
ASSERT_EQUALS( last->previous()->str(), "2" );
ASSERT_EQUALS( last->previous()->previous()->str(), "1" );
if( token->previous() )
ASSERT_EQUALS( "Null was expected", "" );
}
};
REGISTER_TEST( TestTOKEN )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include <cstring>
#include "testsuite.h"
#include "token.h"
extern std::ostringstream errout;
class TestTOKEN : public TestFixture
{
public:
TestTOKEN() : TestFixture("TestTOKEN")
{ }
private:
void run()
{
TEST_CASE( nextprevious );
}
void nextprevious()
{
TOKEN *token = new TOKEN;
token->setstr( "1" );
token->insertToken( "2" );
token->next()->insertToken( "3" );
TOKEN *last = token->next()->next();
ASSERT_EQUALS( token->str(), "1" );
ASSERT_EQUALS( token->next()->str(), "2" );
ASSERT_EQUALS( token->next()->next()->str(), "3" );
if( last->next() )
ASSERT_EQUALS( "Null was expected", "" );
ASSERT_EQUALS( last->str(), "3" );
ASSERT_EQUALS( last->previous()->str(), "2" );
ASSERT_EQUALS( last->previous()->previous()->str(), "1" );
if( token->previous() )
ASSERT_EQUALS( "Null was expected", "" );
}
};
REGISTER_TEST( TestTOKEN )

File diff suppressed because it is too large Load Diff

View File

@ -1,120 +1,120 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkclass.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestUnusedPrivateFunction : public TestFixture
{
public:
TestUnusedPrivateFunction() : TestFixture("TestUnusedPrivateFunction")
{ }
private:
void run()
{
TEST_CASE( test1 );
// [ 2236547 ] False positive --style unused function, called via pointer
TEST_CASE( func_pointer );
}
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for unused private functions..
Settings settings;
settings._checkCodingStyle = true;
CheckClass checkClass( &tokenizer, settings, this );
checkClass.CheckUnusedPrivateFunctions();
}
void test1()
{
check( "class Fred\n"
"{\n"
"private:\n"
" unsigned int f();\n"
"public:\n"
" Fred();\n"
"};\n"
"\n"
"Fred::Fred()\n"
"{ }\n"
"\n"
"unsigned int Fred::f()\n"
"{ }\n" );
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'f'\n"), errout.str() );
}
void func_pointer()
{
check( "class Fred\n"
"{\n"
"private:\n"
" typedef void (*testfp)();\n"
"\n"
" testfp get()\n"
" {\n"
" return test;\n"
" }\n"
"\n"
" static void test()\n"
" { }\n"
"\n"
"public:\n"
" Fred();\n"
"};\n"
"\n"
"Fred::Fred()\n"
"{}\n" );
std::string str( errout.str() );
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'get'\n"), str );
}
};
REGISTER_TEST( TestUnusedPrivateFunction )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#define UNIT_TESTING
#include "tokenize.h"
#include "checkclass.h"
#include "testsuite.h"
#include <sstream>
extern std::ostringstream errout;
class TestUnusedPrivateFunction : public TestFixture
{
public:
TestUnusedPrivateFunction() : TestFixture("TestUnusedPrivateFunction")
{ }
private:
void run()
{
TEST_CASE( test1 );
// [ 2236547 ] False positive --style unused function, called via pointer
TEST_CASE( func_pointer );
}
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
// Clear the error buffer..
errout.str("");
// Check for unused private functions..
Settings settings;
settings._checkCodingStyle = true;
CheckClass checkClass( &tokenizer, settings, this );
checkClass.CheckUnusedPrivateFunctions();
}
void test1()
{
check( "class Fred\n"
"{\n"
"private:\n"
" unsigned int f();\n"
"public:\n"
" Fred();\n"
"};\n"
"\n"
"Fred::Fred()\n"
"{ }\n"
"\n"
"unsigned int Fred::f()\n"
"{ }\n" );
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'f'\n"), errout.str() );
}
void func_pointer()
{
check( "class Fred\n"
"{\n"
"private:\n"
" typedef void (*testfp)();\n"
"\n"
" testfp get()\n"
" {\n"
" return test;\n"
" }\n"
"\n"
" static void test()\n"
" { }\n"
"\n"
"public:\n"
" Fred();\n"
"};\n"
"\n"
"Fred::Fred()\n"
"{}\n" );
std::string str( errout.str() );
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'get'\n"), str );
}
};
REGISTER_TEST( TestUnusedPrivateFunction )

View File

@ -1,184 +1,184 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for unused variables..
#define UNIT_TESTING
#include "testsuite.h"
#include "tokenize.h"
#include "checkother.h"
#include <sstream>
extern std::ostringstream errout;
class TestUnusedVar : public TestFixture
{
public:
TestUnusedVar() : TestFixture("TestUnusedVar")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check for unused variables..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckStructMemberUsage();
}
void run()
{
TEST_CASE( structmember1 );
TEST_CASE( structmember2 );
TEST_CASE( structmember3 );
TEST_CASE( localvar1 );
TEST_CASE( localvar2 );
TEST_CASE( localvar3 );
TEST_CASE( localvar4 );
}
void structmember1()
{
check( "struct abc\n"
"{\n"
" int a;\n"
" int b;\n"
" int c;\n"
"};\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:4]: struct member 'abc::c' is never read\n"), errout.str() );
}
void structmember2()
{
check( "struct ABC\n"
"{\n"
" int a;\n"
" int b;\n"
" int c;\n"
"};\n"
"\n"
"void foo()\n"
"{\n"
" struct ABC abc;\n"
" int a = abc.a;\n"
" int b = abc.b;\n"
" int c = abc.c;\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void structmember3()
{
check( "struct ABC\n"
"{\n"
" int a;\n"
" int b;\n"
" int c;\n"
"};\n"
"\n"
"static struct ABC abc[] = { {1, 2, 3} };\n"
"\n"
"void foo()\n"
"{\n"
" int a = abc[0].a;\n"
" int b = abc[0].b;\n"
" int c = abc[0].c;\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void functionVariableUsage( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check for unused variables..
CheckOther checkOther( &tokenizer, this );
checkOther.functionVariableUsage();
}
void localvar1()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
}
void localvar2()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i;\n"
" return i;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is not assigned a value\n"), errout.str() );
}
void localvar3()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i;\n"
" if ( abc )\n"
" ;\n"
" else i = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
}
void localvar4()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i = 0;\n"
" f(i);\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestUnusedVar )
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
// Check for unused variables..
#define UNIT_TESTING
#include "testsuite.h"
#include "tokenize.h"
#include "checkother.h"
#include <sstream>
extern std::ostringstream errout;
class TestUnusedVar : public TestFixture
{
public:
TestUnusedVar() : TestFixture("TestUnusedVar")
{ }
private:
void check( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check for unused variables..
CheckOther checkOther( &tokenizer, this );
checkOther.CheckStructMemberUsage();
}
void run()
{
TEST_CASE( structmember1 );
TEST_CASE( structmember2 );
TEST_CASE( structmember3 );
TEST_CASE( localvar1 );
TEST_CASE( localvar2 );
TEST_CASE( localvar3 );
TEST_CASE( localvar4 );
}
void structmember1()
{
check( "struct abc\n"
"{\n"
" int a;\n"
" int b;\n"
" int c;\n"
"};\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:4]: struct member 'abc::c' is never read\n"), errout.str() );
}
void structmember2()
{
check( "struct ABC\n"
"{\n"
" int a;\n"
" int b;\n"
" int c;\n"
"};\n"
"\n"
"void foo()\n"
"{\n"
" struct ABC abc;\n"
" int a = abc.a;\n"
" int b = abc.b;\n"
" int c = abc.c;\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void structmember3()
{
check( "struct ABC\n"
"{\n"
" int a;\n"
" int b;\n"
" int c;\n"
"};\n"
"\n"
"static struct ABC abc[] = { {1, 2, 3} };\n"
"\n"
"void foo()\n"
"{\n"
" int a = abc[0].a;\n"
" int b = abc[0].b;\n"
" int c = abc[0].c;\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
void functionVariableUsage( const char code[] )
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize( istr, "test.cpp" );
tokenizer.simplifyTokenList();
// Clear the error buffer..
errout.str("");
// Check for unused variables..
CheckOther checkOther( &tokenizer, this );
checkOther.functionVariableUsage();
}
void localvar1()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
}
void localvar2()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i;\n"
" return i;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is not assigned a value\n"), errout.str() );
}
void localvar3()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i;\n"
" if ( abc )\n"
" ;\n"
" else i = 0;\n"
"}\n" );
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
}
void localvar4()
{
functionVariableUsage( "void foo()\n"
"{\n"
" int i = 0;\n"
" f(i);\n"
"}\n" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
};
REGISTER_TEST( TestUnusedVar )

860
token.cpp
View File

@ -1,436 +1,436 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "token.h"
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#ifdef __BORLANDC__
#include <ctype.h> // isalpha, isdigit
#endif
TOKEN::TOKEN()
{
_fileIndex = 0;
_cstr = 0;
_str = "";
_linenr = 0;
_next = 0;
_previous = 0;
_varId = 0;
_isName = false;
_isNumber = false;
}
TOKEN::~TOKEN()
{
std::free(_cstr);
}
void TOKEN::setstr( const char s[] )
{
_str = s;
std::free(_cstr);
#ifndef _MSC_VER
_cstr = strdup(s);
#else
_cstr = _strdup(s);
#endif
_isName = bool(_str[0]=='_' || isalpha(_str[0]));
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "token.h"
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#ifdef __BORLANDC__
#include <ctype.h> // isalpha, isdigit
#endif
TOKEN::TOKEN()
{
_fileIndex = 0;
_cstr = 0;
_str = "";
_linenr = 0;
_next = 0;
_previous = 0;
_varId = 0;
_isName = false;
_isNumber = false;
}
TOKEN::~TOKEN()
{
std::free(_cstr);
}
void TOKEN::setstr( const char s[] )
{
_str = s;
std::free(_cstr);
#ifndef _MSC_VER
_cstr = strdup(s);
#else
_cstr = _strdup(s);
#endif
_isName = bool(_str[0]=='_' || isalpha(_str[0]));
_isNumber = bool(isdigit(_str[0]) != 0);
_varId = 0;
}
void TOKEN::combineWithNext(const char str1[], const char str2[])
{
if (!(_next))
return;
if (_str!=str1 || _next->_str!=str2)
return;
std::string newstr(std::string(str1) + std::string(str2));
setstr( newstr.c_str() );
deleteNext();
}
void TOKEN::deleteNext()
{
TOKEN *n = _next;
_next = n->next();
_varId = 0;
}
void TOKEN::combineWithNext(const char str1[], const char str2[])
{
if (!(_next))
return;
if (_str!=str1 || _next->_str!=str2)
return;
std::string newstr(std::string(str1) + std::string(str2));
setstr( newstr.c_str() );
deleteNext();
}
void TOKEN::deleteNext()
{
TOKEN *n = _next;
_next = n->next();
delete n;
if (_next)
_next->previous(this);
}
const TOKEN *TOKEN::tokAt(int index) const
{
const TOKEN *tok = this;
while (index>0 && tok)
{
tok = tok->next();
index--;
}
return tok;
}
const char *TOKEN::strAt(int index) const
{
const TOKEN *tok = this->tokAt(index);
return tok ? tok->_cstr : "";
}
int TOKEN::multiCompare( const char *needle, const char *haystack )
{
bool emptyStringFound = false;
bool findNextOr = false;
const char *haystackPointer = haystack;
for( ; *needle; ++needle )
{
if( *needle == '|' )
{
// If needle and haystack are both at the end, we have a match.
if( *haystackPointer == 0 )
return 1;
haystackPointer = haystack;
if( findNextOr )
findNextOr = false;
else
emptyStringFound = true;
continue;
}
if( findNextOr )
continue;
// If haystack and needle don't share the same character, reset
// haystackpointer and find next '|' character.
if( *haystackPointer != *needle )
{
haystackPointer = haystack;
findNextOr = true;
continue;
}
// All characters in haystack and needle have matched this far
haystackPointer++;
}
// If both needle and haystack are at the end, then we have a match.
if( *haystackPointer == 0 )
return 1;
// If empty string was found or if last character in needle was '|'
if( emptyStringFound || findNextOr == false )
return 0;
return -1;
}
bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[], unsigned int varid)
{
const char *p = pattern;
while ( *p )
{
// Skip spaces in pattern..
while ( *p == ' ' )
p++;
if (!tok)
{
// If we have no tokens, pattern "!!else" should return true
if( isNotPattern( p ) )
return true;
else
return false;
}
// Extract token from pattern..
// TODO: Refactor this so there can't be buffer overflows
char str[500];
char *s = str;
while (*p && *p!=' ')
{
*s = *p;
s++;
p++;
}
*s = 0;
// No token => Success!
if (str[0] == 0)
return true;
bool useVar1;
// Any symbolname..
if (strcmp(str,"%var%")==0 || strcmp(str,"%type%")==0)
{
if (!tok->isName())
return false;
}
// Accept any token
else if (strcmp(str,"%any%")==0 )
{
}
// Variable name..
else if ((useVar1 = (strcmp(str,"%var1%")==0)) || strcmp(str,"%var2%")==0)
{
const char **varname = useVar1 ? varname1 : varname2;
if ( ! varname )
return false;
if (tok->_str != varname[0])
return false;
for ( int i = 1; varname[i]; i++ )
{
if ( !(tok->tokAt(2)) )
return false;
if ( strcmp(tok->strAt( 1), ".") )
return false;
if ( strcmp(tok->strAt( 2), varname[i]) )
return false;
tok = tok->tokAt(2);
}
}
else if (strcmp(str,"%varid%")==0)
{
if ( tok->varId() != varid )
return false;
}
else if (strcmp(str,"%num%")==0)
{
if ( ! tok->isNumber() )
return false;
}
else if (strcmp(str,"%str%")==0)
{
if ( tok->_str[0] != '\"' )
return false;
}
// [.. => search for a one-character token..
else if (str[0]=='[' && strchr(str, ']') && tok->_str[1] == 0)
{
*strrchr(str, ']') = 0;
if ( strchr( str + 1, tok->_str[0] ) == 0 )
return false;
}
// Parse multi options, such as void|int|char (accept token which is one of these 3)
else if ( strchr(str, '|') && strlen( str ) > 2 )
{
int res = multiCompare( str, tok->_cstr );
if( res == 0 )
{
// Empty alternative matches, use the same token on next round
continue;
}
else if( res == -1 )
{
// No match
return false;
}
}
// Parse "not" options. Token can be anything except the given one
else if( isNotPattern( str ) )
{
if( strcmp( tok->aaaa(), &(str[2]) ) == 0 )
return false;
}
else if (str != tok->_str)
return false;
tok = tok->next();
}
// The end of the pattern has been reached and nothing wrong has been found
return true;
}
bool TOKEN::isNotPattern( const char *pattern )
{
if( pattern && strlen(pattern) > 2 && pattern[0] == '!' && pattern[1] == '!' )
return true;
else
return false;
}
bool TOKEN::isName() const
{
return _isName;
}
bool TOKEN::isNumber() const
{
return _isNumber;
}
bool TOKEN::isStandardType() const
{
bool ret = false;
const char *type[] = {"bool","char","short","int","long","float","double",0};
for (int i = 0; type[i]; i++)
ret |= (_str == type[i]);
return ret;
}
//---------------------------------------------------------------------------
const TOKEN *TOKEN::findmatch(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[])
{
for ( ; tok; tok = tok->next())
{
if ( TOKEN::Match(tok, pattern, varname1, varname2) )
return tok;
}
return 0;
}
const TOKEN *TOKEN::findtoken(const TOKEN *tok1, const char *tokenstr[])
{
for (const TOKEN *ret = tok1; ret; ret = ret->next())
{
unsigned int i = 0;
const TOKEN *tok = ret;
while (tokenstr[i])
{
if (!tok)
return NULL;
if (*(tokenstr[i]) && (tokenstr[i] != tok->_str))
break;
tok = tok->next();
i++;
}
if (!tokenstr[i])
return ret;
}
return NULL;
}
unsigned int TOKEN::varId() const
{
return _varId;
}
void TOKEN::varId( unsigned int id )
{
_varId = id;
}
TOKEN *TOKEN::next() const
{
return _next;
}
void TOKEN::next( TOKEN *next )
{
_next = next;
}
TOKEN *TOKEN::previous() const
{
return _previous;
}
void TOKEN::previous( TOKEN *previous )
{
_previous = previous;
}
void TOKEN::insertToken( const char str[] )
{
TOKEN *newToken = new TOKEN;
_next->previous(this);
}
const TOKEN *TOKEN::tokAt(int index) const
{
const TOKEN *tok = this;
while (index>0 && tok)
{
tok = tok->next();
index--;
}
return tok;
}
const char *TOKEN::strAt(int index) const
{
const TOKEN *tok = this->tokAt(index);
return tok ? tok->_cstr : "";
}
int TOKEN::multiCompare( const char *needle, const char *haystack )
{
bool emptyStringFound = false;
bool findNextOr = false;
const char *haystackPointer = haystack;
for( ; *needle; ++needle )
{
if( *needle == '|' )
{
// If needle and haystack are both at the end, we have a match.
if( *haystackPointer == 0 )
return 1;
haystackPointer = haystack;
if( findNextOr )
findNextOr = false;
else
emptyStringFound = true;
continue;
}
if( findNextOr )
continue;
// If haystack and needle don't share the same character, reset
// haystackpointer and find next '|' character.
if( *haystackPointer != *needle )
{
haystackPointer = haystack;
findNextOr = true;
continue;
}
// All characters in haystack and needle have matched this far
haystackPointer++;
}
// If both needle and haystack are at the end, then we have a match.
if( *haystackPointer == 0 )
return 1;
// If empty string was found or if last character in needle was '|'
if( emptyStringFound || findNextOr == false )
return 0;
return -1;
}
bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[], unsigned int varid)
{
const char *p = pattern;
while ( *p )
{
// Skip spaces in pattern..
while ( *p == ' ' )
p++;
if (!tok)
{
// If we have no tokens, pattern "!!else" should return true
if( isNotPattern( p ) )
return true;
else
return false;
}
// Extract token from pattern..
// TODO: Refactor this so there can't be buffer overflows
char str[500];
char *s = str;
while (*p && *p!=' ')
{
*s = *p;
s++;
p++;
}
*s = 0;
// No token => Success!
if (str[0] == 0)
return true;
bool useVar1;
// Any symbolname..
if (strcmp(str,"%var%")==0 || strcmp(str,"%type%")==0)
{
if (!tok->isName())
return false;
}
// Accept any token
else if (strcmp(str,"%any%")==0 )
{
}
// Variable name..
else if ((useVar1 = (strcmp(str,"%var1%")==0)) || strcmp(str,"%var2%")==0)
{
const char **varname = useVar1 ? varname1 : varname2;
if ( ! varname )
return false;
if (tok->_str != varname[0])
return false;
for ( int i = 1; varname[i]; i++ )
{
if ( !(tok->tokAt(2)) )
return false;
if ( strcmp(tok->strAt( 1), ".") )
return false;
if ( strcmp(tok->strAt( 2), varname[i]) )
return false;
tok = tok->tokAt(2);
}
}
else if (strcmp(str,"%varid%")==0)
{
if ( tok->varId() != varid )
return false;
}
else if (strcmp(str,"%num%")==0)
{
if ( ! tok->isNumber() )
return false;
}
else if (strcmp(str,"%str%")==0)
{
if ( tok->_str[0] != '\"' )
return false;
}
// [.. => search for a one-character token..
else if (str[0]=='[' && strchr(str, ']') && tok->_str[1] == 0)
{
*strrchr(str, ']') = 0;
if ( strchr( str + 1, tok->_str[0] ) == 0 )
return false;
}
// Parse multi options, such as void|int|char (accept token which is one of these 3)
else if ( strchr(str, '|') && strlen( str ) > 2 )
{
int res = multiCompare( str, tok->_cstr );
if( res == 0 )
{
// Empty alternative matches, use the same token on next round
continue;
}
else if( res == -1 )
{
// No match
return false;
}
}
// Parse "not" options. Token can be anything except the given one
else if( isNotPattern( str ) )
{
if( strcmp( tok->aaaa(), &(str[2]) ) == 0 )
return false;
}
else if (str != tok->_str)
return false;
tok = tok->next();
}
// The end of the pattern has been reached and nothing wrong has been found
return true;
}
bool TOKEN::isNotPattern( const char *pattern )
{
if( pattern && strlen(pattern) > 2 && pattern[0] == '!' && pattern[1] == '!' )
return true;
else
return false;
}
bool TOKEN::isName() const
{
return _isName;
}
bool TOKEN::isNumber() const
{
return _isNumber;
}
bool TOKEN::isStandardType() const
{
bool ret = false;
const char *type[] = {"bool","char","short","int","long","float","double",0};
for (int i = 0; type[i]; i++)
ret |= (_str == type[i]);
return ret;
}
//---------------------------------------------------------------------------
const TOKEN *TOKEN::findmatch(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[])
{
for ( ; tok; tok = tok->next())
{
if ( TOKEN::Match(tok, pattern, varname1, varname2) )
return tok;
}
return 0;
}
const TOKEN *TOKEN::findtoken(const TOKEN *tok1, const char *tokenstr[])
{
for (const TOKEN *ret = tok1; ret; ret = ret->next())
{
unsigned int i = 0;
const TOKEN *tok = ret;
while (tokenstr[i])
{
if (!tok)
return NULL;
if (*(tokenstr[i]) && (tokenstr[i] != tok->_str))
break;
tok = tok->next();
i++;
}
if (!tokenstr[i])
return ret;
}
return NULL;
}
unsigned int TOKEN::varId() const
{
return _varId;
}
void TOKEN::varId( unsigned int id )
{
_varId = id;
}
TOKEN *TOKEN::next() const
{
return _next;
}
void TOKEN::next( TOKEN *next )
{
_next = next;
}
TOKEN *TOKEN::previous() const
{
return _previous;
}
void TOKEN::previous( TOKEN *previous )
{
_previous = previous;
}
void TOKEN::insertToken( const char str[] )
{
TOKEN *newToken = new TOKEN;
newToken->setstr( str );
newToken->_linenr = _linenr;
newToken->_fileIndex = _fileIndex;
if( this->next() )
{
newToken->next( this->next() );
newToken->next()->previous( newToken );
}
newToken->_fileIndex = _fileIndex;
if( this->next() )
{
newToken->next( this->next() );
newToken->next()->previous( newToken );
}
this->next( newToken );
newToken->previous( this );
}
void TOKEN::eraseTokens( TOKEN *begin, const TOKEN *end )
{
if ( ! begin )
return;
while ( begin->next() && begin->next() != end )
{
begin->deleteNext();
}
}
unsigned int TOKEN::fileIndex() const
{
return _fileIndex;
}
void TOKEN::fileIndex( unsigned int fileIndex )
{
_fileIndex = fileIndex;
}
unsigned int TOKEN::linenr() const
{
return _linenr;
}
void TOKEN::linenr( unsigned int linenr )
{
_linenr = linenr;
}
void TOKEN::printOut( const char *title ) const
{
std::cout << std::endl << "###";
if ( title )
std::cout << " " << title << " ";
else
std::cout << "########";
std::cout << "###" << std::endl;
for( const TOKEN *t = this; t; t = t->next() )
{
std::cout << t->linenr() << ": " << t->str();
if ( t->varId() )
std::cout << " ("<< t->varId() <<")";
std::cout << std::endl;
}
}
this->next( newToken );
newToken->previous( this );
}
void TOKEN::eraseTokens( TOKEN *begin, const TOKEN *end )
{
if ( ! begin )
return;
while ( begin->next() && begin->next() != end )
{
begin->deleteNext();
}
}
unsigned int TOKEN::fileIndex() const
{
return _fileIndex;
}
void TOKEN::fileIndex( unsigned int fileIndex )
{
_fileIndex = fileIndex;
}
unsigned int TOKEN::linenr() const
{
return _linenr;
}
void TOKEN::linenr( unsigned int linenr )
{
_linenr = linenr;
}
void TOKEN::printOut( const char *title ) const
{
std::cout << std::endl << "###";
if ( title )
std::cout << " " << title << " ";
else
std::cout << "########";
std::cout << "###" << std::endl;
for( const TOKEN *t = this; t; t = t->next() )
{
std::cout << t->linenr() << ": " << t->str();
if ( t->varId() )
std::cout << " ("<< t->varId() <<")";
std::cout << std::endl;
}
}

366
token.h
View File

@ -1,183 +1,183 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef TOKEN_H
#define TOKEN_H
#include <string>
class TOKEN
{
public:
TOKEN();
~TOKEN();
void setstr( const char s[] );
const std::string &str() const
{ return _str; }
const char *aaaa() const
{ return _cstr; }
char aaaa0() const
{ return _cstr[0]; }
char aaaa1() const
{ return _cstr[1]; }
/**
* Combine two tokens that belong to each other.
* Ex: "<" and "=" may become "<="
*/
void combineWithNext(const char str1[], const char str2[]);
/**
* Unlink and delete next token.
*/
void deleteNext();
/**
* Returns token in given index, related to this token.
* For example index 1 would return next token, and 2
* would return next from that one.
*/
const TOKEN *tokAt(int index) const;
const char *strAt(int index) const;
/**
* Match given token (or list of tokens) to a pattern list.
*
* Possible patterns
* "%any%" any token
* "%var%" any token which is a name or type e.g. "hello" or "int"
* "%num%" Any numeric token, e.g. "23"
* "%str%" Any token starting with "-character (C-string).
* "%var1%" Match with parameter varname1
* "%var2%" Match with parameter varname2
* "%varid%" Match with parameter varid
* "[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 or empty string
* "!!else" No tokens or any token that is not "else".
* "someRandomText" If token contains "someRandomText".
*
* The patterns can be also combined to compare to multiple tokens at once
* by separating tokens with a space, e.g.
* ") 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
* match its pattern, false is returned.
*
* @param tok List of tokens to be compared to the pattern
* @param pattern The pattern where tokens are compared, e.g. "const"
* or ") const|volatile| {".
* @param varname1 Used with pattern "%var1%" and "%var2%"
* @param varname2 Used with pattern "%var1%" and "%var2%"
* @return true if given token matches 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, unsigned int varid=0);
bool isName() const;
bool isNumber() 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 *findtoken(const TOKEN *tok1, const char *tokenstr[]);
/**
* Needle is build from multiple alternatives. If one of
* them is equal to haystack, return value is 1. If there
* are no matches, but one alternative to needle is empty
* string, return value is 0. If needle was not found, return
* value is -1.
*
* @param needle e.g. "one|two" or "|one|two"
* @param haystack e.g. "one", "two" or "invalid"
* @return 1 if needle is found from the haystack
* 0 if needle was empty string
* -1 if needle was not found
*/
static int multiCompare( const char *needle, const char *haystack );
unsigned int linenr() const;
void linenr( unsigned int linenr );
unsigned int fileIndex() const;
void fileIndex( unsigned int fileIndex );
TOKEN *next() const;
/**
* Delete tokens between begin and end. E.g. if begin = 1
* and end = 5, tokens 2,3 and 4 would be erased.
*
* @param begin Tokens after this will be erased.
* @param end Tokens before this will be erased.
*/
static void eraseTokens( TOKEN *begin, const TOKEN *end );
/**
* Insert new token after this token. This function will handle
* relations between next and previous token also.
* @param str String for the new token.
*/
void insertToken( const char str[] );
TOKEN *previous() const;
unsigned int varId() const;
void varId( unsigned int id );
/**
* For debugging purposes, prints token and all tokens
* followed by it.
* @param title Title for the printout or use default parameter or 0
* for no title.
*/
void printOut( const char *title = 0 ) const;
private:
void next( TOKEN *next );
void previous( TOKEN *previous );
/**
* Return true if pattern is e.g. "!!else".
* See Match() for more info.
*
* @param pattern Pattern to match, e.g. "if ; !!else"
* @return true if pattern starts with "!!" and contains 3
* or more characters.
*/
static bool isNotPattern( const char *pattern );
std::string _str;
char * _cstr;
bool _isName;
bool _isNumber;
unsigned int _varId;
TOKEN *_next;
TOKEN *_previous;
unsigned int _fileIndex;
unsigned int _linenr;
};
#endif // TOKEN_H
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef TOKEN_H
#define TOKEN_H
#include <string>
class TOKEN
{
public:
TOKEN();
~TOKEN();
void setstr( const char s[] );
const std::string &str() const
{ return _str; }
const char *aaaa() const
{ return _cstr; }
char aaaa0() const
{ return _cstr[0]; }
char aaaa1() const
{ return _cstr[1]; }
/**
* Combine two tokens that belong to each other.
* Ex: "<" and "=" may become "<="
*/
void combineWithNext(const char str1[], const char str2[]);
/**
* Unlink and delete next token.
*/
void deleteNext();
/**
* Returns token in given index, related to this token.
* For example index 1 would return next token, and 2
* would return next from that one.
*/
const TOKEN *tokAt(int index) const;
const char *strAt(int index) const;
/**
* Match given token (or list of tokens) to a pattern list.
*
* Possible patterns
* "%any%" any token
* "%var%" any token which is a name or type e.g. "hello" or "int"
* "%num%" Any numeric token, e.g. "23"
* "%str%" Any token starting with "-character (C-string).
* "%var1%" Match with parameter varname1
* "%var2%" Match with parameter varname2
* "%varid%" Match with parameter varid
* "[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 or empty string
* "!!else" No tokens or any token that is not "else".
* "someRandomText" If token contains "someRandomText".
*
* The patterns can be also combined to compare to multiple tokens at once
* by separating tokens with a space, e.g.
* ") 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
* match its pattern, false is returned.
*
* @param tok List of tokens to be compared to the pattern
* @param pattern The pattern where tokens are compared, e.g. "const"
* or ") const|volatile| {".
* @param varname1 Used with pattern "%var1%" and "%var2%"
* @param varname2 Used with pattern "%var1%" and "%var2%"
* @return true if given token matches 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, unsigned int varid=0);
bool isName() const;
bool isNumber() 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 *findtoken(const TOKEN *tok1, const char *tokenstr[]);
/**
* Needle is build from multiple alternatives. If one of
* them is equal to haystack, return value is 1. If there
* are no matches, but one alternative to needle is empty
* string, return value is 0. If needle was not found, return
* value is -1.
*
* @param needle e.g. "one|two" or "|one|two"
* @param haystack e.g. "one", "two" or "invalid"
* @return 1 if needle is found from the haystack
* 0 if needle was empty string
* -1 if needle was not found
*/
static int multiCompare( const char *needle, const char *haystack );
unsigned int linenr() const;
void linenr( unsigned int linenr );
unsigned int fileIndex() const;
void fileIndex( unsigned int fileIndex );
TOKEN *next() const;
/**
* Delete tokens between begin and end. E.g. if begin = 1
* and end = 5, tokens 2,3 and 4 would be erased.
*
* @param begin Tokens after this will be erased.
* @param end Tokens before this will be erased.
*/
static void eraseTokens( TOKEN *begin, const TOKEN *end );
/**
* Insert new token after this token. This function will handle
* relations between next and previous token also.
* @param str String for the new token.
*/
void insertToken( const char str[] );
TOKEN *previous() const;
unsigned int varId() const;
void varId( unsigned int id );
/**
* For debugging purposes, prints token and all tokens
* followed by it.
* @param title Title for the printout or use default parameter or 0
* for no title.
*/
void printOut( const char *title = 0 ) const;
private:
void next( TOKEN *next );
void previous( TOKEN *previous );
/**
* Return true if pattern is e.g. "!!else".
* See Match() for more info.
*
* @param pattern Pattern to match, e.g. "if ; !!else"
* @return true if pattern starts with "!!" and contains 3
* or more characters.
*/
static bool isNotPattern( const char *pattern );
std::string _str;
char * _cstr;
bool _isName;
bool _isNumber;
unsigned int _varId;
TOKEN *_next;
TOKEN *_previous;
unsigned int _fileIndex;
unsigned int _linenr;
};
#endif // TOKEN_H

File diff suppressed because it is too large Load Diff

View File

@ -1,139 +1,139 @@
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef tokenizeH
#define tokenizeH
//---------------------------------------------------------------------------
#include <list>
#include <string>
#include <map>
#include <vector>
#include "settings.h"
#include "errorlogger.h"
#include "token.h"
class Tokenizer
{
private:
// Deallocate lists..
void DeallocateTokens();
/**
* Helper function for "tokenize". This recursively parses into included header files.
*/
void tokenizeCode(std::istream &code, const unsigned int FileIndex=0);
public:
Tokenizer();
~Tokenizer();
/**
* Tokenize code
* @param code input stream for code
* @param FileName The filename
*/
void tokenize(std::istream &code, const char FileName[]);
/** Set variable id */
void setVarId();
/** Simplify tokenlist */
void simplifyTokenList();
// Helper functions for handling the tokens list..
static void deleteTokens(TOKEN *tok);
static const char *getParameterName( const TOKEN *ftok, int par );
static bool SameFileName( const char fname1[], const char fname2[] );
std::string fileLine( const TOKEN *tok ) const;
// Return size.
int SizeOfType(const char type[]) const;
void initTokens();
const std::vector<std::string> *getFiles() const;
void fillFunctionList();
const TOKEN *GetFunctionTokenByName( const char funcname[] ) const;
const TOKEN *tokens() const;
#ifndef UNIT_TESTING
private:
#endif
struct DefineSymbol
{
char *name;
char *value;
struct DefineSymbol *next;
};
void Define(const char Name[], const char Value[]);
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno);
/** Simplify conditions
* @return true if something is modified
* false if nothing is done.
*/
bool simplifyConditions();
/** Simplify casts
* @return true if something is modified
* false if nothing is done.
*/
bool simplifyCasts();
/** Simplify function calls - constant return value
* @return true if something is modified
* false if nothing is done.
*/
bool simplifyFunctionReturn();
/**
* A simplify function that replaces a variable with its value in cases
* when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
*
* @param token The token list to check and modify.
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
bool simplifyKnownVariables();
TOKEN *_gettok(TOKEN *tok, int index);
void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n);
TOKEN *_tokensBack;
std::map<std::string, unsigned int> _typeSize;
std::vector<const TOKEN *> _functionList;
std::vector<std::string> _files;
struct DefineSymbol * _dsymlist;
TOKEN *_tokens;
};
//---------------------------------------------------------------------------
#endif
/*
* c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
//---------------------------------------------------------------------------
#ifndef tokenizeH
#define tokenizeH
//---------------------------------------------------------------------------
#include <list>
#include <string>
#include <map>
#include <vector>
#include "settings.h"
#include "errorlogger.h"
#include "token.h"
class Tokenizer
{
private:
// Deallocate lists..
void DeallocateTokens();
/**
* Helper function for "tokenize". This recursively parses into included header files.
*/
void tokenizeCode(std::istream &code, const unsigned int FileIndex=0);
public:
Tokenizer();
~Tokenizer();
/**
* Tokenize code
* @param code input stream for code
* @param FileName The filename
*/
void tokenize(std::istream &code, const char FileName[]);
/** Set variable id */
void setVarId();
/** Simplify tokenlist */
void simplifyTokenList();
// Helper functions for handling the tokens list..
static void deleteTokens(TOKEN *tok);
static const char *getParameterName( const TOKEN *ftok, int par );
static bool SameFileName( const char fname1[], const char fname2[] );
std::string fileLine( const TOKEN *tok ) const;
// Return size.
int SizeOfType(const char type[]) const;
void initTokens();
const std::vector<std::string> *getFiles() const;
void fillFunctionList();
const TOKEN *GetFunctionTokenByName( const char funcname[] ) const;
const TOKEN *tokens() const;
#ifndef UNIT_TESTING
private:
#endif
struct DefineSymbol
{
char *name;
char *value;
struct DefineSymbol *next;
};
void Define(const char Name[], const char Value[]);
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno);
/** Simplify conditions
* @return true if something is modified
* false if nothing is done.
*/
bool simplifyConditions();
/** Simplify casts
* @return true if something is modified
* false if nothing is done.
*/
bool simplifyCasts();
/** Simplify function calls - constant return value
* @return true if something is modified
* false if nothing is done.
*/
bool simplifyFunctionReturn();
/**
* A simplify function that replaces a variable with its value in cases
* when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
*
* @param token The token list to check and modify.
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
bool simplifyKnownVariables();
TOKEN *_gettok(TOKEN *tok, int index);
void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n);
TOKEN *_tokensBack;
std::map<std::string, unsigned int> _typeSize;
std::vector<const TOKEN *> _functionList;
std::vector<std::string> _files;
struct DefineSymbol * _dsymlist;
TOKEN *_tokens;
};
//---------------------------------------------------------------------------
#endif