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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

860
token.cpp
View File

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

366
token.h
View File

@ -1,183 +1,183 @@
/* /*
* c++check - c/c++ syntax checking * c++check - c/c++ syntax checking
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi * Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/ * along with this program. If not, see <http://www.gnu.org/licenses/
*/ */
#ifndef TOKEN_H #ifndef TOKEN_H
#define TOKEN_H #define TOKEN_H
#include <string> #include <string>
class TOKEN class TOKEN
{ {
public: public:
TOKEN(); TOKEN();
~TOKEN(); ~TOKEN();
void setstr( const char s[] ); void setstr( const char s[] );
const std::string &str() const const std::string &str() const
{ return _str; } { return _str; }
const char *aaaa() const const char *aaaa() const
{ return _cstr; } { return _cstr; }
char aaaa0() const char aaaa0() const
{ return _cstr[0]; } { return _cstr[0]; }
char aaaa1() const char aaaa1() const
{ return _cstr[1]; } { return _cstr[1]; }
/** /**
* Combine two tokens that belong to each other. * Combine two tokens that belong to each other.
* Ex: "<" and "=" may become "<=" * Ex: "<" and "=" may become "<="
*/ */
void combineWithNext(const char str1[], const char str2[]); void combineWithNext(const char str1[], const char str2[]);
/** /**
* Unlink and delete next token. * Unlink and delete next token.
*/ */
void deleteNext(); void deleteNext();
/** /**
* Returns token in given index, related to this token. * Returns token in given index, related to this token.
* For example index 1 would return next token, and 2 * For example index 1 would return next token, and 2
* would return next from that one. * would return next from that one.
*/ */
const TOKEN *tokAt(int index) const; const TOKEN *tokAt(int index) const;
const char *strAt(int index) const; const char *strAt(int index) const;
/** /**
* Match given token (or list of tokens) to a pattern list. * Match given token (or list of tokens) to a pattern list.
* *
* Possible patterns * Possible patterns
* "%any%" any token * "%any%" any token
* "%var%" any token which is a name or type e.g. "hello" or "int" * "%var%" any token which is a name or type e.g. "hello" or "int"
* "%num%" Any numeric token, e.g. "23" * "%num%" Any numeric token, e.g. "23"
* "%str%" Any token starting with "-character (C-string). * "%str%" Any token starting with "-character (C-string).
* "%var1%" Match with parameter varname1 * "%var1%" Match with parameter varname1
* "%var2%" Match with parameter varname2 * "%var2%" Match with parameter varname2
* "%varid%" Match with parameter varid * "%varid%" Match with parameter varid
* "[abc]" Any of the characters 'a' or 'b' or 'c' * "[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
* "int|void|char|" Any of the strings, int, void or char or empty string * "int|void|char|" Any of the strings, int, void or char or empty string
* "!!else" No tokens or any token that is not "else". * "!!else" No tokens or any token that is not "else".
* "someRandomText" If token contains "someRandomText". * "someRandomText" If token contains "someRandomText".
* *
* The patterns can be also combined to compare to multiple tokens at once * The patterns can be also combined to compare to multiple tokens at once
* by separating tokens with a space, e.g. * by separating tokens with a space, e.g.
* ") const|void {" will return true if first token is ')' next token is either * ") 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 * "const" or "void" and token after that is '{'. If even one of the tokens does not
* match its pattern, false is returned. * match its pattern, false is returned.
* *
* @param tok List of tokens to be compared to the pattern * @param tok List of tokens to be compared to the pattern
* @param pattern The pattern where tokens are compared, e.g. "const" * @param pattern The pattern where tokens are compared, e.g. "const"
* or ") const|volatile| {". * or ") const|volatile| {".
* @param varname1 Used with pattern "%var1%" and "%var2%" * @param varname1 Used with pattern "%var1%" and "%var2%"
* @param varname2 Used with pattern "%var1%" and "%var2%" * @param varname2 Used with pattern "%var1%" and "%var2%"
* @return true if given token matches with given pattern * @return true if given token matches with given pattern
* false if given token does not match 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); 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 isName() const;
bool isNumber() const; bool isNumber() const;
bool isStandardType() 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 *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[]); static const TOKEN *findtoken(const TOKEN *tok1, const char *tokenstr[]);
/** /**
* Needle is build from multiple alternatives. If one of * Needle is build from multiple alternatives. If one of
* them is equal to haystack, return value is 1. If there * them is equal to haystack, return value is 1. If there
* are no matches, but one alternative to needle is empty * are no matches, but one alternative to needle is empty
* string, return value is 0. If needle was not found, return * string, return value is 0. If needle was not found, return
* value is -1. * value is -1.
* *
* @param needle e.g. "one|two" or "|one|two" * @param needle e.g. "one|two" or "|one|two"
* @param haystack e.g. "one", "two" or "invalid" * @param haystack e.g. "one", "two" or "invalid"
* @return 1 if needle is found from the haystack * @return 1 if needle is found from the haystack
* 0 if needle was empty string * 0 if needle was empty string
* -1 if needle was not found * -1 if needle was not found
*/ */
static int multiCompare( const char *needle, const char *haystack ); static int multiCompare( const char *needle, const char *haystack );
unsigned int linenr() const; unsigned int linenr() const;
void linenr( unsigned int linenr ); void linenr( unsigned int linenr );
unsigned int fileIndex() const; unsigned int fileIndex() const;
void fileIndex( unsigned int fileIndex ); void fileIndex( unsigned int fileIndex );
TOKEN *next() const; TOKEN *next() const;
/** /**
* Delete tokens between begin and end. E.g. if begin = 1 * Delete tokens between begin and end. E.g. if begin = 1
* and end = 5, tokens 2,3 and 4 would be erased. * and end = 5, tokens 2,3 and 4 would be erased.
* *
* @param begin Tokens after this will be erased. * @param begin Tokens after this will be erased.
* @param end Tokens before this will be erased. * @param end Tokens before this will be erased.
*/ */
static void eraseTokens( TOKEN *begin, const TOKEN *end ); static void eraseTokens( TOKEN *begin, const TOKEN *end );
/** /**
* Insert new token after this token. This function will handle * Insert new token after this token. This function will handle
* relations between next and previous token also. * relations between next and previous token also.
* @param str String for the new token. * @param str String for the new token.
*/ */
void insertToken( const char str[] ); void insertToken( const char str[] );
TOKEN *previous() const; TOKEN *previous() const;
unsigned int varId() const; unsigned int varId() const;
void varId( unsigned int id ); void varId( unsigned int id );
/** /**
* For debugging purposes, prints token and all tokens * For debugging purposes, prints token and all tokens
* followed by it. * followed by it.
* @param title Title for the printout or use default parameter or 0 * @param title Title for the printout or use default parameter or 0
* for no title. * for no title.
*/ */
void printOut( const char *title = 0 ) const; void printOut( const char *title = 0 ) const;
private: private:
void next( TOKEN *next ); void next( TOKEN *next );
void previous( TOKEN *previous ); void previous( TOKEN *previous );
/** /**
* Return true if pattern is e.g. "!!else". * Return true if pattern is e.g. "!!else".
* See Match() for more info. * See Match() for more info.
* *
* @param pattern Pattern to match, e.g. "if ; !!else" * @param pattern Pattern to match, e.g. "if ; !!else"
* @return true if pattern starts with "!!" and contains 3 * @return true if pattern starts with "!!" and contains 3
* or more characters. * or more characters.
*/ */
static bool isNotPattern( const char *pattern ); static bool isNotPattern( const char *pattern );
std::string _str; std::string _str;
char * _cstr; char * _cstr;
bool _isName; bool _isName;
bool _isNumber; bool _isNumber;
unsigned int _varId; unsigned int _varId;
TOKEN *_next; TOKEN *_next;
TOKEN *_previous; TOKEN *_previous;
unsigned int _fileIndex; unsigned int _fileIndex;
unsigned int _linenr; unsigned int _linenr;
}; };
#endif // TOKEN_H #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 * c++check - c/c++ syntax checking
* Copyright (C) 2007 Daniel Marjamäki * Copyright (C) 2007 Daniel Marjamäki
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/ * along with this program. If not, see <http://www.gnu.org/licenses/
*/ */
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#ifndef tokenizeH #ifndef tokenizeH
#define tokenizeH #define tokenizeH
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <list> #include <list>
#include <string> #include <string>
#include <map> #include <map>
#include <vector> #include <vector>
#include "settings.h" #include "settings.h"
#include "errorlogger.h" #include "errorlogger.h"
#include "token.h" #include "token.h"
class Tokenizer class Tokenizer
{ {
private: private:
// Deallocate lists.. // Deallocate lists..
void DeallocateTokens(); void DeallocateTokens();
/** /**
* Helper function for "tokenize". This recursively parses into included header files. * Helper function for "tokenize". This recursively parses into included header files.
*/ */
void tokenizeCode(std::istream &code, const unsigned int FileIndex=0); void tokenizeCode(std::istream &code, const unsigned int FileIndex=0);
public: public:
Tokenizer(); Tokenizer();
~Tokenizer(); ~Tokenizer();
/** /**
* Tokenize code * Tokenize code
* @param code input stream for code * @param code input stream for code
* @param FileName The filename * @param FileName The filename
*/ */
void tokenize(std::istream &code, const char FileName[]); void tokenize(std::istream &code, const char FileName[]);
/** Set variable id */ /** Set variable id */
void setVarId(); void setVarId();
/** Simplify tokenlist */ /** Simplify tokenlist */
void simplifyTokenList(); void simplifyTokenList();
// Helper functions for handling the tokens list.. // Helper functions for handling the tokens list..
static void deleteTokens(TOKEN *tok); static void deleteTokens(TOKEN *tok);
static const char *getParameterName( const TOKEN *ftok, int par ); static const char *getParameterName( const TOKEN *ftok, int par );
static bool SameFileName( const char fname1[], const char fname2[] ); static bool SameFileName( const char fname1[], const char fname2[] );
std::string fileLine( const TOKEN *tok ) const; std::string fileLine( const TOKEN *tok ) const;
// Return size. // Return size.
int SizeOfType(const char type[]) const; int SizeOfType(const char type[]) const;
void initTokens(); void initTokens();
const std::vector<std::string> *getFiles() const; const std::vector<std::string> *getFiles() const;
void fillFunctionList(); void fillFunctionList();
const TOKEN *GetFunctionTokenByName( const char funcname[] ) const; const TOKEN *GetFunctionTokenByName( const char funcname[] ) const;
const TOKEN *tokens() const; const TOKEN *tokens() const;
#ifndef UNIT_TESTING #ifndef UNIT_TESTING
private: private:
#endif #endif
struct DefineSymbol struct DefineSymbol
{ {
char *name; char *name;
char *value; char *value;
struct DefineSymbol *next; struct DefineSymbol *next;
}; };
void Define(const char Name[], const char Value[]); void Define(const char Name[], const char Value[]);
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno); void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno);
/** Simplify conditions /** Simplify conditions
* @return true if something is modified * @return true if something is modified
* false if nothing is done. * false if nothing is done.
*/ */
bool simplifyConditions(); bool simplifyConditions();
/** Simplify casts /** Simplify casts
* @return true if something is modified * @return true if something is modified
* false if nothing is done. * false if nothing is done.
*/ */
bool simplifyCasts(); bool simplifyCasts();
/** Simplify function calls - constant return value /** Simplify function calls - constant return value
* @return true if something is modified * @return true if something is modified
* false if nothing is done. * false if nothing is done.
*/ */
bool simplifyFunctionReturn(); bool simplifyFunctionReturn();
/** /**
* A simplify function that replaces a variable with its value in cases * 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)" * when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
* *
* @param token The token list to check and modify. * @param token The token list to check and modify.
* @return true if modifications to token-list are done. * @return true if modifications to token-list are done.
* false if no modifications are done. * false if no modifications are done.
*/ */
bool simplifyKnownVariables(); bool simplifyKnownVariables();
TOKEN *_gettok(TOKEN *tok, int index); TOKEN *_gettok(TOKEN *tok, int index);
void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n); void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n);
TOKEN *_tokensBack; TOKEN *_tokensBack;
std::map<std::string, unsigned int> _typeSize; std::map<std::string, unsigned int> _typeSize;
std::vector<const TOKEN *> _functionList; std::vector<const TOKEN *> _functionList;
std::vector<std::string> _files; std::vector<std::string> _files;
struct DefineSymbol * _dsymlist; struct DefineSymbol * _dsymlist;
TOKEN *_tokens; TOKEN *_tokens;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif #endif