Formatting: uniformize end of lines.
This commit is contained in:
parent
c56779c9ae
commit
a5fa323a0b
File diff suppressed because it is too large
Load Diff
|
@ -1,54 +1,54 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckBufferOverrunH
|
||||
#define CheckBufferOverrunH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckBufferOverrunClass
|
||||
{
|
||||
public:
|
||||
CheckBufferOverrunClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
|
||||
~CheckBufferOverrunClass();
|
||||
|
||||
// Buffer overrun..
|
||||
void CheckBufferOverrun();
|
||||
|
||||
|
||||
// Dangerous functions that can cause buffer overruns
|
||||
void WarningDangerousFunctions();
|
||||
private:
|
||||
void CheckBufferOverrun_StructVariable();
|
||||
void CheckBufferOverrun_LocalVariable();
|
||||
void CheckBufferOverrun_CheckScope( const TOKEN *tok, const char *varname[], const int size, const int total_size, unsigned int varid );
|
||||
void ReportError(const TOKEN *tok, const char errmsg[]);
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
const Settings _settings;
|
||||
ErrorLogger *_errorLogger;
|
||||
std::list<const TOKEN *> _callStack;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckBufferOverrunH
|
||||
#define CheckBufferOverrunH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckBufferOverrunClass
|
||||
{
|
||||
public:
|
||||
CheckBufferOverrunClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
|
||||
~CheckBufferOverrunClass();
|
||||
|
||||
// Buffer overrun..
|
||||
void CheckBufferOverrun();
|
||||
|
||||
|
||||
// Dangerous functions that can cause buffer overruns
|
||||
void WarningDangerousFunctions();
|
||||
private:
|
||||
void CheckBufferOverrun_StructVariable();
|
||||
void CheckBufferOverrun_LocalVariable();
|
||||
void CheckBufferOverrun_CheckScope( const TOKEN *tok, const char *varname[], const int size, const int total_size, unsigned int varid );
|
||||
void ReportError(const TOKEN *tok, const char errmsg[]);
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
const Settings _settings;
|
||||
ErrorLogger *_errorLogger;
|
||||
std::list<const TOKEN *> _callStack;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
|
|
1496
checkclass.cpp
1496
checkclass.cpp
File diff suppressed because it is too large
Load Diff
134
checkclass.h
134
checkclass.h
|
@ -1,67 +1,67 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckClassH
|
||||
#define CheckClassH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckClass
|
||||
{
|
||||
public:
|
||||
CheckClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
|
||||
~CheckClass();
|
||||
|
||||
void CheckConstructors();
|
||||
|
||||
void CheckUnusedPrivateFunctions();
|
||||
|
||||
void CheckMemset();
|
||||
|
||||
void CheckOperatorEq1(); // Warning upon "void operator=(.."
|
||||
|
||||
// The destructor in a base class should be virtual
|
||||
void virtualDestructor();
|
||||
|
||||
private:
|
||||
struct VAR
|
||||
{
|
||||
const char *name;
|
||||
bool init;
|
||||
struct VAR *next;
|
||||
};
|
||||
|
||||
void ClassChecking_VarList_Initialize(const TOKEN *tok1, const TOKEN *ftok, struct VAR *varlist, const char classname[], std::list<std::string> &callstack);
|
||||
void InitVar(struct VAR *varlist, const char varname[]);
|
||||
const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel );
|
||||
struct VAR *ClassChecking_GetVarList(const TOKEN *tok1);
|
||||
|
||||
// Check constructors for a specified class
|
||||
void CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[]);
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
Settings _settings;
|
||||
ErrorLogger *_errorLogger;
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckClassH
|
||||
#define CheckClassH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckClass
|
||||
{
|
||||
public:
|
||||
CheckClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
|
||||
~CheckClass();
|
||||
|
||||
void CheckConstructors();
|
||||
|
||||
void CheckUnusedPrivateFunctions();
|
||||
|
||||
void CheckMemset();
|
||||
|
||||
void CheckOperatorEq1(); // Warning upon "void operator=(.."
|
||||
|
||||
// The destructor in a base class should be virtual
|
||||
void virtualDestructor();
|
||||
|
||||
private:
|
||||
struct VAR
|
||||
{
|
||||
const char *name;
|
||||
bool init;
|
||||
struct VAR *next;
|
||||
};
|
||||
|
||||
void ClassChecking_VarList_Initialize(const TOKEN *tok1, const TOKEN *ftok, struct VAR *varlist, const char classname[], std::list<std::string> &callstack);
|
||||
void InitVar(struct VAR *varlist, const char varname[]);
|
||||
const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel );
|
||||
struct VAR *ClassChecking_GetVarList(const TOKEN *tok1);
|
||||
|
||||
// Check constructors for a specified class
|
||||
void CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[]);
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
Settings _settings;
|
||||
ErrorLogger *_errorLogger;
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,167 +1,167 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#include "checkfunctionusage.h"
|
||||
#include "tokenize.h"
|
||||
#include <sstream>
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// FUNCTION USAGE - Check for unused functions etc
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CheckFunctionUsage::CheckFunctionUsage( ErrorLogger *errorLogger )
|
||||
{
|
||||
_errorLogger = errorLogger;
|
||||
}
|
||||
|
||||
CheckFunctionUsage::~CheckFunctionUsage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CheckFunctionUsage::parseTokens( const Tokenizer &tokenizer )
|
||||
{
|
||||
// Function declarations..
|
||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||
{
|
||||
if ( tok->fileIndex() != 0 )
|
||||
continue;
|
||||
|
||||
const TOKEN *funcname = 0;
|
||||
|
||||
if ( TOKEN::Match( tok, "%type% %var% (" ) )
|
||||
funcname = tok->tokAt(1);
|
||||
else if ( TOKEN::Match(tok, "%type% * %var% (") )
|
||||
funcname = tok->tokAt(2);
|
||||
else if ( TOKEN::Match(tok, "%type% :: %var% (") && !TOKEN::Match(tok, tok->strAt(2)) )
|
||||
funcname = tok->tokAt(2);
|
||||
|
||||
// Check that ") {" is found..
|
||||
for (const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next())
|
||||
{
|
||||
if ( TOKEN::Match(tok2, ")") )
|
||||
{
|
||||
if ( ! TOKEN::Match(tok2, ") {") && ! TOKEN::Match(tok2, ") const {") )
|
||||
funcname = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( funcname )
|
||||
{
|
||||
FunctionUsage &func = _functions[ funcname->str() ];
|
||||
|
||||
// No filename set yet..
|
||||
if (func.filename.empty())
|
||||
func.filename = tokenizer.getFiles()->at(0);
|
||||
|
||||
// Multiple files => filename = "+"
|
||||
else if (func.filename != tokenizer.getFiles()->at(0))
|
||||
{
|
||||
func.filename = "+";
|
||||
func.usedOtherFile |= func.usedSameFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function usage..
|
||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||
{
|
||||
const TOKEN *funcname = 0;
|
||||
|
||||
if ( TOKEN::Match( tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]" ) ||
|
||||
TOKEN::Match(tok, ":: %var% (") ||
|
||||
TOKEN::Match(tok, "|= %var% (") ||
|
||||
TOKEN::Match(tok, "&= %var% (") ||
|
||||
TOKEN::Match(tok, "&& %var% (") ||
|
||||
TOKEN::Match(tok, "|| %var% (") ||
|
||||
TOKEN::Match(tok, "else %var% (") ||
|
||||
TOKEN::Match(tok, "return %var% (") )
|
||||
funcname = tok->next();
|
||||
|
||||
// funcname ( => Assert that the end paranthesis isn't followed by {
|
||||
if ( TOKEN::Match(funcname, "%var% (") )
|
||||
{
|
||||
int parlevel = 0;
|
||||
for ( const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next() )
|
||||
{
|
||||
if (tok2->str() == "(")
|
||||
++parlevel;
|
||||
|
||||
else if (tok2->str() == ")")
|
||||
{
|
||||
--parlevel;
|
||||
if (parlevel == 0 && (TOKEN::Match(tok2, ") {") || TOKEN::Match(tok2, ") const")))
|
||||
funcname = NULL;
|
||||
if ( parlevel <= 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( funcname )
|
||||
{
|
||||
FunctionUsage &func = _functions[ funcname->str() ];
|
||||
|
||||
if ( func.filename.empty() || func.filename == "+" )
|
||||
func.usedOtherFile = true;
|
||||
|
||||
else
|
||||
func.usedSameFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CheckFunctionUsage::check()
|
||||
{
|
||||
for ( std::map<std::string, FunctionUsage>::const_iterator it = _functions.begin(); it != _functions.end(); ++it )
|
||||
{
|
||||
const FunctionUsage &func = it->second;
|
||||
if ( func.usedOtherFile || func.filename.empty() )
|
||||
continue;
|
||||
if ( ! func.usedSameFile )
|
||||
{
|
||||
std::ostringstream errmsg;
|
||||
if ( func.filename != "+" )
|
||||
errmsg << "[" << func.filename << "] ";
|
||||
errmsg << "The function '" << it->first << "' is never used.";
|
||||
_errorLogger->reportErr( errmsg.str() );
|
||||
}
|
||||
else if ( ! func.usedOtherFile )
|
||||
{
|
||||
/* TODO - add error message "function is only used in <file> it can be static"
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "The function '" << it->first << "' is only used in the file it was declared in so it should have local linkage.";
|
||||
_errorLogger->reportErr( errmsg.str() );
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#include "checkfunctionusage.h"
|
||||
#include "tokenize.h"
|
||||
#include <sstream>
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// FUNCTION USAGE - Check for unused functions etc
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CheckFunctionUsage::CheckFunctionUsage( ErrorLogger *errorLogger )
|
||||
{
|
||||
_errorLogger = errorLogger;
|
||||
}
|
||||
|
||||
CheckFunctionUsage::~CheckFunctionUsage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CheckFunctionUsage::parseTokens( const Tokenizer &tokenizer )
|
||||
{
|
||||
// Function declarations..
|
||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||
{
|
||||
if ( tok->fileIndex() != 0 )
|
||||
continue;
|
||||
|
||||
const TOKEN *funcname = 0;
|
||||
|
||||
if ( TOKEN::Match( tok, "%type% %var% (" ) )
|
||||
funcname = tok->tokAt(1);
|
||||
else if ( TOKEN::Match(tok, "%type% * %var% (") )
|
||||
funcname = tok->tokAt(2);
|
||||
else if ( TOKEN::Match(tok, "%type% :: %var% (") && !TOKEN::Match(tok, tok->strAt(2)) )
|
||||
funcname = tok->tokAt(2);
|
||||
|
||||
// Check that ") {" is found..
|
||||
for (const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next())
|
||||
{
|
||||
if ( TOKEN::Match(tok2, ")") )
|
||||
{
|
||||
if ( ! TOKEN::Match(tok2, ") {") && ! TOKEN::Match(tok2, ") const {") )
|
||||
funcname = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( funcname )
|
||||
{
|
||||
FunctionUsage &func = _functions[ funcname->str() ];
|
||||
|
||||
// No filename set yet..
|
||||
if (func.filename.empty())
|
||||
func.filename = tokenizer.getFiles()->at(0);
|
||||
|
||||
// Multiple files => filename = "+"
|
||||
else if (func.filename != tokenizer.getFiles()->at(0))
|
||||
{
|
||||
func.filename = "+";
|
||||
func.usedOtherFile |= func.usedSameFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function usage..
|
||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||
{
|
||||
const TOKEN *funcname = 0;
|
||||
|
||||
if ( TOKEN::Match( tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]" ) ||
|
||||
TOKEN::Match(tok, ":: %var% (") ||
|
||||
TOKEN::Match(tok, "|= %var% (") ||
|
||||
TOKEN::Match(tok, "&= %var% (") ||
|
||||
TOKEN::Match(tok, "&& %var% (") ||
|
||||
TOKEN::Match(tok, "|| %var% (") ||
|
||||
TOKEN::Match(tok, "else %var% (") ||
|
||||
TOKEN::Match(tok, "return %var% (") )
|
||||
funcname = tok->next();
|
||||
|
||||
// funcname ( => Assert that the end paranthesis isn't followed by {
|
||||
if ( TOKEN::Match(funcname, "%var% (") )
|
||||
{
|
||||
int parlevel = 0;
|
||||
for ( const TOKEN *tok2 = funcname; tok2; tok2 = tok2->next() )
|
||||
{
|
||||
if (tok2->str() == "(")
|
||||
++parlevel;
|
||||
|
||||
else if (tok2->str() == ")")
|
||||
{
|
||||
--parlevel;
|
||||
if (parlevel == 0 && (TOKEN::Match(tok2, ") {") || TOKEN::Match(tok2, ") const")))
|
||||
funcname = NULL;
|
||||
if ( parlevel <= 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( funcname )
|
||||
{
|
||||
FunctionUsage &func = _functions[ funcname->str() ];
|
||||
|
||||
if ( func.filename.empty() || func.filename == "+" )
|
||||
func.usedOtherFile = true;
|
||||
|
||||
else
|
||||
func.usedSameFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CheckFunctionUsage::check()
|
||||
{
|
||||
for ( std::map<std::string, FunctionUsage>::const_iterator it = _functions.begin(); it != _functions.end(); ++it )
|
||||
{
|
||||
const FunctionUsage &func = it->second;
|
||||
if ( func.usedOtherFile || func.filename.empty() )
|
||||
continue;
|
||||
if ( ! func.usedSameFile )
|
||||
{
|
||||
std::ostringstream errmsg;
|
||||
if ( func.filename != "+" )
|
||||
errmsg << "[" << func.filename << "] ";
|
||||
errmsg << "The function '" << it->first << "' is never used.";
|
||||
_errorLogger->reportErr( errmsg.str() );
|
||||
}
|
||||
else if ( ! func.usedOtherFile )
|
||||
{
|
||||
/* TODO - add error message "function is only used in <file> it can be static"
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "The function '" << it->first << "' is only used in the file it was declared in so it should have local linkage.";
|
||||
_errorLogger->reportErr( errmsg.str() );
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckFunctionUsageH
|
||||
#define CheckFunctionUsageH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckFunctionUsage
|
||||
{
|
||||
public:
|
||||
CheckFunctionUsage( ErrorLogger *errorLogger );
|
||||
~CheckFunctionUsage();
|
||||
|
||||
// Parse current tokens and determine..
|
||||
// * Check what functions are used
|
||||
// * What functions are declared
|
||||
void parseTokens( const Tokenizer &tokenizer );
|
||||
|
||||
|
||||
void check();
|
||||
|
||||
private:
|
||||
ErrorLogger *_errorLogger;
|
||||
|
||||
|
||||
class FunctionUsage
|
||||
{
|
||||
public:
|
||||
FunctionUsage()
|
||||
{
|
||||
filename = "";
|
||||
usedOtherFile = false;
|
||||
usedSameFile = false;
|
||||
}
|
||||
|
||||
std::string filename;
|
||||
bool usedSameFile;
|
||||
bool usedOtherFile;
|
||||
};
|
||||
|
||||
std::map<std::string, FunctionUsage> _functions;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckFunctionUsageH
|
||||
#define CheckFunctionUsageH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckFunctionUsage
|
||||
{
|
||||
public:
|
||||
CheckFunctionUsage( ErrorLogger *errorLogger );
|
||||
~CheckFunctionUsage();
|
||||
|
||||
// Parse current tokens and determine..
|
||||
// * Check what functions are used
|
||||
// * What functions are declared
|
||||
void parseTokens( const Tokenizer &tokenizer );
|
||||
|
||||
|
||||
void check();
|
||||
|
||||
private:
|
||||
ErrorLogger *_errorLogger;
|
||||
|
||||
|
||||
class FunctionUsage
|
||||
{
|
||||
public:
|
||||
FunctionUsage()
|
||||
{
|
||||
filename = "";
|
||||
usedOtherFile = false;
|
||||
usedSameFile = false;
|
||||
}
|
||||
|
||||
std::string filename;
|
||||
bool usedSameFile;
|
||||
bool usedOtherFile;
|
||||
};
|
||||
|
||||
std::map<std::string, FunctionUsage> _functions;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
|
|
512
checkheaders.cpp
512
checkheaders.cpp
|
@ -1,256 +1,256 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#include "checkheaders.h"
|
||||
#include "tokenize.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// HEADERS - No implementation in a header
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CheckHeaders::CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger )
|
||||
{
|
||||
_tokenizer = tokenizer;
|
||||
_errorLogger = errorLogger;
|
||||
}
|
||||
|
||||
CheckHeaders::~CheckHeaders()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CheckHeaders::WarningHeaderWithImplementation()
|
||||
{
|
||||
for ( const TOKEN *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||
{
|
||||
// Only interested in included file
|
||||
if (tok->fileIndex() == 0)
|
||||
continue;
|
||||
|
||||
if (TOKEN::Match(tok, ") {"))
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << _tokenizer->fileLine(tok) << ": Found implementation in header";
|
||||
_errorLogger->reportErr(ostr.str());
|
||||
|
||||
// Goto next file..
|
||||
unsigned int fileindex = tok->fileIndex();
|
||||
while ( tok->next() && tok->fileIndex() == fileindex )
|
||||
tok = tok->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// HEADERS - Unneeded include
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void CheckHeaders::WarningIncludeHeader()
|
||||
{
|
||||
// Including..
|
||||
for ( const TOKEN *includetok = _tokenizer->tokens(); includetok; includetok = includetok->next())
|
||||
{
|
||||
if (includetok->str() != "#include")
|
||||
continue;
|
||||
|
||||
// Get fileindex of included file..
|
||||
unsigned int hfile = 0;
|
||||
const char *includefile = includetok->next()->aaaa();
|
||||
while (hfile < _tokenizer->getFiles()->size())
|
||||
{
|
||||
if ( Tokenizer::SameFileName( _tokenizer->getFiles()->at(hfile).c_str(), includefile ) )
|
||||
break;
|
||||
hfile++;
|
||||
}
|
||||
if (hfile == _tokenizer->getFiles()->size())
|
||||
continue;
|
||||
|
||||
// This header is needed if:
|
||||
// * It contains some needed class declaration
|
||||
// * It contains some needed function declaration
|
||||
// * It contains some needed constant value
|
||||
// * It contains some needed variable
|
||||
// * It contains some needed enum
|
||||
|
||||
std::list<std::string> classlist;
|
||||
std::list<std::string> namelist;
|
||||
|
||||
// Extract classes and names in the header..
|
||||
int indentlevel = 0;
|
||||
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next() )
|
||||
{
|
||||
if ( tok1->fileIndex() != hfile )
|
||||
continue;
|
||||
|
||||
// I'm only interested in stuff that is declared at indentlevel 0
|
||||
if (tok1->str() == "{")
|
||||
++indentlevel;
|
||||
|
||||
else if (tok1->str() == "}")
|
||||
--indentlevel;
|
||||
|
||||
if (indentlevel != 0)
|
||||
continue;
|
||||
|
||||
// Class or namespace declaration..
|
||||
// --------------------------------------
|
||||
if (TOKEN::Match(tok1,"class %var% {") || TOKEN::Match(tok1,"class %var% :") || TOKEN::Match(tok1,"namespace %var% {"))
|
||||
classlist.push_back(tok1->strAt(1));
|
||||
|
||||
// Variable declaration..
|
||||
// --------------------------------------
|
||||
else if (TOKEN::Match(tok1, "%type% %var% ;") || TOKEN::Match(tok1, "%type% %var% ["))
|
||||
namelist.push_back(tok1->strAt(1));
|
||||
|
||||
else if (TOKEN::Match(tok1, "%type% * %var% ;") || TOKEN::Match(tok1, "%type% * %var% ["))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1, "const %type% %var% =") || TOKEN::Match(tok1, "const %type% %var% ["))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1, "const %type% * %var% =") || TOKEN::Match(tok1, "const %type% * %var% ["))
|
||||
namelist.push_back(tok1->strAt(3));
|
||||
|
||||
// enum..
|
||||
// --------------------------------------
|
||||
else if (tok1->str() == "enum")
|
||||
{
|
||||
tok1 = tok1->next();
|
||||
while ( ! TOKEN::Match( tok1, "; %any%" ) )
|
||||
{
|
||||
if ( tok1->isName() )
|
||||
namelist.push_back(tok1->str());
|
||||
tok1 = tok1->next();
|
||||
}
|
||||
}
|
||||
|
||||
// function..
|
||||
// --------------------------------------
|
||||
else if (TOKEN::Match(tok1,"%type% %var% ("))
|
||||
namelist.push_back(tok1->strAt(1));
|
||||
|
||||
else if (TOKEN::Match(tok1,"%type% * %var% ("))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1,"const %type% %var% ("))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1,"const %type% * %var% ("))
|
||||
namelist.push_back(tok1->strAt(3));
|
||||
|
||||
// typedef..
|
||||
// --------------------------------------
|
||||
else if (tok1->str() == "typedef")
|
||||
{
|
||||
if (strcmp(tok1->strAt(1),"enum")==0)
|
||||
continue;
|
||||
int parlevel = 0;
|
||||
while (tok1->next())
|
||||
{
|
||||
if ( TOKEN::Match(tok1, "[({]") )
|
||||
parlevel++;
|
||||
|
||||
else if ( TOKEN::Match(tok1, "[)}]") )
|
||||
parlevel--;
|
||||
|
||||
else if (parlevel == 0)
|
||||
{
|
||||
if ( tok1->str() == ";" )
|
||||
break;
|
||||
|
||||
if ( TOKEN::Match(tok1, "%var% ;") )
|
||||
namelist.push_back(tok1->str());
|
||||
}
|
||||
|
||||
tok1 = tok1->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if the extracted names are used...
|
||||
bool Needed = false;
|
||||
bool NeedDeclaration = false;
|
||||
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next())
|
||||
{
|
||||
if (tok1->fileIndex() != includetok->fileIndex())
|
||||
continue;
|
||||
|
||||
if ( TOKEN::Match(tok1, ": %var% {") || TOKEN::Match(tok1, ": %type% %var% {") )
|
||||
{
|
||||
std::string classname = tok1->strAt((strcmp(tok1->strAt(2),"{")) ? 2 : 1);
|
||||
if (std::find(classlist.begin(),classlist.end(),classname)!=classlist.end())
|
||||
{
|
||||
Needed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! tok1->isName() )
|
||||
continue;
|
||||
|
||||
if (std::find(namelist.begin(),namelist.end(),tok1->aaaa() ) != namelist.end())
|
||||
{
|
||||
Needed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! NeedDeclaration )
|
||||
NeedDeclaration = (std::find(classlist.begin(),classlist.end(),tok1->aaaa() ) != classlist.end());
|
||||
}
|
||||
|
||||
|
||||
// Not a header file?
|
||||
if (includetok->fileIndex() == 0)
|
||||
Needed |= NeedDeclaration;
|
||||
|
||||
// Not needed!
|
||||
if (!Needed)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << _tokenizer->fileLine(includetok) << ": The included header '" << includefile << "' is not needed";
|
||||
if (NeedDeclaration)
|
||||
ostr << " (but a forward declaration is needed)";
|
||||
_errorLogger->reportErr(ostr.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#include "checkheaders.h"
|
||||
#include "tokenize.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// HEADERS - No implementation in a header
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CheckHeaders::CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger )
|
||||
{
|
||||
_tokenizer = tokenizer;
|
||||
_errorLogger = errorLogger;
|
||||
}
|
||||
|
||||
CheckHeaders::~CheckHeaders()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CheckHeaders::WarningHeaderWithImplementation()
|
||||
{
|
||||
for ( const TOKEN *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||
{
|
||||
// Only interested in included file
|
||||
if (tok->fileIndex() == 0)
|
||||
continue;
|
||||
|
||||
if (TOKEN::Match(tok, ") {"))
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << _tokenizer->fileLine(tok) << ": Found implementation in header";
|
||||
_errorLogger->reportErr(ostr.str());
|
||||
|
||||
// Goto next file..
|
||||
unsigned int fileindex = tok->fileIndex();
|
||||
while ( tok->next() && tok->fileIndex() == fileindex )
|
||||
tok = tok->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// HEADERS - Unneeded include
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void CheckHeaders::WarningIncludeHeader()
|
||||
{
|
||||
// Including..
|
||||
for ( const TOKEN *includetok = _tokenizer->tokens(); includetok; includetok = includetok->next())
|
||||
{
|
||||
if (includetok->str() != "#include")
|
||||
continue;
|
||||
|
||||
// Get fileindex of included file..
|
||||
unsigned int hfile = 0;
|
||||
const char *includefile = includetok->next()->aaaa();
|
||||
while (hfile < _tokenizer->getFiles()->size())
|
||||
{
|
||||
if ( Tokenizer::SameFileName( _tokenizer->getFiles()->at(hfile).c_str(), includefile ) )
|
||||
break;
|
||||
hfile++;
|
||||
}
|
||||
if (hfile == _tokenizer->getFiles()->size())
|
||||
continue;
|
||||
|
||||
// This header is needed if:
|
||||
// * It contains some needed class declaration
|
||||
// * It contains some needed function declaration
|
||||
// * It contains some needed constant value
|
||||
// * It contains some needed variable
|
||||
// * It contains some needed enum
|
||||
|
||||
std::list<std::string> classlist;
|
||||
std::list<std::string> namelist;
|
||||
|
||||
// Extract classes and names in the header..
|
||||
int indentlevel = 0;
|
||||
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next() )
|
||||
{
|
||||
if ( tok1->fileIndex() != hfile )
|
||||
continue;
|
||||
|
||||
// I'm only interested in stuff that is declared at indentlevel 0
|
||||
if (tok1->str() == "{")
|
||||
++indentlevel;
|
||||
|
||||
else if (tok1->str() == "}")
|
||||
--indentlevel;
|
||||
|
||||
if (indentlevel != 0)
|
||||
continue;
|
||||
|
||||
// Class or namespace declaration..
|
||||
// --------------------------------------
|
||||
if (TOKEN::Match(tok1,"class %var% {") || TOKEN::Match(tok1,"class %var% :") || TOKEN::Match(tok1,"namespace %var% {"))
|
||||
classlist.push_back(tok1->strAt(1));
|
||||
|
||||
// Variable declaration..
|
||||
// --------------------------------------
|
||||
else if (TOKEN::Match(tok1, "%type% %var% ;") || TOKEN::Match(tok1, "%type% %var% ["))
|
||||
namelist.push_back(tok1->strAt(1));
|
||||
|
||||
else if (TOKEN::Match(tok1, "%type% * %var% ;") || TOKEN::Match(tok1, "%type% * %var% ["))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1, "const %type% %var% =") || TOKEN::Match(tok1, "const %type% %var% ["))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1, "const %type% * %var% =") || TOKEN::Match(tok1, "const %type% * %var% ["))
|
||||
namelist.push_back(tok1->strAt(3));
|
||||
|
||||
// enum..
|
||||
// --------------------------------------
|
||||
else if (tok1->str() == "enum")
|
||||
{
|
||||
tok1 = tok1->next();
|
||||
while ( ! TOKEN::Match( tok1, "; %any%" ) )
|
||||
{
|
||||
if ( tok1->isName() )
|
||||
namelist.push_back(tok1->str());
|
||||
tok1 = tok1->next();
|
||||
}
|
||||
}
|
||||
|
||||
// function..
|
||||
// --------------------------------------
|
||||
else if (TOKEN::Match(tok1,"%type% %var% ("))
|
||||
namelist.push_back(tok1->strAt(1));
|
||||
|
||||
else if (TOKEN::Match(tok1,"%type% * %var% ("))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1,"const %type% %var% ("))
|
||||
namelist.push_back(tok1->strAt(2));
|
||||
|
||||
else if (TOKEN::Match(tok1,"const %type% * %var% ("))
|
||||
namelist.push_back(tok1->strAt(3));
|
||||
|
||||
// typedef..
|
||||
// --------------------------------------
|
||||
else if (tok1->str() == "typedef")
|
||||
{
|
||||
if (strcmp(tok1->strAt(1),"enum")==0)
|
||||
continue;
|
||||
int parlevel = 0;
|
||||
while (tok1->next())
|
||||
{
|
||||
if ( TOKEN::Match(tok1, "[({]") )
|
||||
parlevel++;
|
||||
|
||||
else if ( TOKEN::Match(tok1, "[)}]") )
|
||||
parlevel--;
|
||||
|
||||
else if (parlevel == 0)
|
||||
{
|
||||
if ( tok1->str() == ";" )
|
||||
break;
|
||||
|
||||
if ( TOKEN::Match(tok1, "%var% ;") )
|
||||
namelist.push_back(tok1->str());
|
||||
}
|
||||
|
||||
tok1 = tok1->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if the extracted names are used...
|
||||
bool Needed = false;
|
||||
bool NeedDeclaration = false;
|
||||
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next())
|
||||
{
|
||||
if (tok1->fileIndex() != includetok->fileIndex())
|
||||
continue;
|
||||
|
||||
if ( TOKEN::Match(tok1, ": %var% {") || TOKEN::Match(tok1, ": %type% %var% {") )
|
||||
{
|
||||
std::string classname = tok1->strAt((strcmp(tok1->strAt(2),"{")) ? 2 : 1);
|
||||
if (std::find(classlist.begin(),classlist.end(),classname)!=classlist.end())
|
||||
{
|
||||
Needed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! tok1->isName() )
|
||||
continue;
|
||||
|
||||
if (std::find(namelist.begin(),namelist.end(),tok1->aaaa() ) != namelist.end())
|
||||
{
|
||||
Needed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! NeedDeclaration )
|
||||
NeedDeclaration = (std::find(classlist.begin(),classlist.end(),tok1->aaaa() ) != classlist.end());
|
||||
}
|
||||
|
||||
|
||||
// Not a header file?
|
||||
if (includetok->fileIndex() == 0)
|
||||
Needed |= NeedDeclaration;
|
||||
|
||||
// Not needed!
|
||||
if (!Needed)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << _tokenizer->fileLine(includetok) << ": The included header '" << includefile << "' is not needed";
|
||||
if (NeedDeclaration)
|
||||
ostr << " (but a forward declaration is needed)";
|
||||
_errorLogger->reportErr(ostr.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckHeadersH
|
||||
#define CheckHeadersH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckHeaders
|
||||
{
|
||||
public:
|
||||
CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
|
||||
~CheckHeaders();
|
||||
void WarningHeaderWithImplementation();
|
||||
void WarningIncludeHeader();
|
||||
|
||||
private:
|
||||
const Tokenizer *_tokenizer;
|
||||
ErrorLogger *_errorLogger;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckHeadersH
|
||||
#define CheckHeadersH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckHeaders
|
||||
{
|
||||
public:
|
||||
CheckHeaders( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
|
||||
~CheckHeaders();
|
||||
void WarningHeaderWithImplementation();
|
||||
void WarningIncludeHeader();
|
||||
|
||||
private:
|
||||
const Tokenizer *_tokenizer;
|
||||
ErrorLogger *_errorLogger;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
|
|
2602
checkmemoryleak.cpp
2602
checkmemoryleak.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,108 +1,108 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckMemoryLeakH
|
||||
#define CheckMemoryLeakH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/** \brief Check for memory leaks */
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
class CheckMemoryLeakClass
|
||||
{
|
||||
public:
|
||||
CheckMemoryLeakClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
|
||||
~CheckMemoryLeakClass();
|
||||
void CheckMemoryLeak();
|
||||
|
||||
private:
|
||||
|
||||
enum AllocType { No, Malloc, gMalloc, New, NewA, FOPEN, POPEN };
|
||||
|
||||
// Extra allocation..
|
||||
class AllocFunc
|
||||
{
|
||||
public:
|
||||
const char *funcname;
|
||||
AllocType alloctype;
|
||||
|
||||
AllocFunc(const char f[], AllocType a)
|
||||
{
|
||||
funcname = f;
|
||||
alloctype = a;
|
||||
}
|
||||
};
|
||||
|
||||
void CheckMemoryLeak_ClassMembers_Variable( const std::vector<const char *> &classname, const char varname[] );
|
||||
void CheckMemoryLeak_ClassMembers_ParseClass( const TOKEN *tok1, std::vector<const char *> &classname );
|
||||
void CheckMemoryLeak_ClassMembers();
|
||||
void CheckMemoryLeak_InFunction();
|
||||
void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] );
|
||||
|
||||
/**
|
||||
* Simplify code e.g. by replacing empty "{ }" with ";"
|
||||
* @param tok first token. The tokens list can be modified.
|
||||
*/
|
||||
void simplifycode(TOKEN *tok);
|
||||
|
||||
/**
|
||||
* Delete tokens between begin and end. E.g. if begin = 1
|
||||
* and end = 5, tokens 2,3 and 4 would be erased.
|
||||
*
|
||||
* @param begin Tokens after this will be erased.
|
||||
* @param end Tokens before this will be erased.
|
||||
*/
|
||||
void erase(TOKEN *begin, const TOKEN *end);
|
||||
|
||||
/**
|
||||
* Extract a new tokens list that is easier to parse than the "tokens"
|
||||
* @param tok start parse token
|
||||
* @param callstack callstack
|
||||
* @param varname name of variable
|
||||
* @param alloctype
|
||||
* @param dealloctype
|
||||
* @return Newly allocated token array. Caller needs to release reserved
|
||||
* memory by calling Tokenizer::deleteTokens(returnValue);
|
||||
*/
|
||||
TOKEN *getcode(const TOKEN *tok, std::list<const TOKEN *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype);
|
||||
bool notvar(const TOKEN *tok, const char *varnames[]);
|
||||
void instoken(TOKEN *tok, const char str[]);
|
||||
void MemoryLeak( const TOKEN *tok, const char varname[], AllocType alloctype );
|
||||
void MismatchError( const TOKEN *Tok1, const std::list<const TOKEN *> &callstack, const char varname[] );
|
||||
const char * call_func( const TOKEN *tok, std::list<const TOKEN *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype );
|
||||
AllocType GetDeallocationType( const TOKEN *tok, const char *varnames[]);
|
||||
AllocType GetAllocationType( const TOKEN *tok2 );
|
||||
AllocType GetReallocationType( const TOKEN *tok2 );
|
||||
bool isclass( const TOKEN *typestr );
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
ErrorLogger *_errorLogger;
|
||||
const Settings _settings;
|
||||
std::list<AllocFunc> _listAllocFunc;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckMemoryLeakH
|
||||
#define CheckMemoryLeakH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/** \brief Check for memory leaks */
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
class CheckMemoryLeakClass
|
||||
{
|
||||
public:
|
||||
CheckMemoryLeakClass( const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger );
|
||||
~CheckMemoryLeakClass();
|
||||
void CheckMemoryLeak();
|
||||
|
||||
private:
|
||||
|
||||
enum AllocType { No, Malloc, gMalloc, New, NewA, FOPEN, POPEN };
|
||||
|
||||
// Extra allocation..
|
||||
class AllocFunc
|
||||
{
|
||||
public:
|
||||
const char *funcname;
|
||||
AllocType alloctype;
|
||||
|
||||
AllocFunc(const char f[], AllocType a)
|
||||
{
|
||||
funcname = f;
|
||||
alloctype = a;
|
||||
}
|
||||
};
|
||||
|
||||
void CheckMemoryLeak_ClassMembers_Variable( const std::vector<const char *> &classname, const char varname[] );
|
||||
void CheckMemoryLeak_ClassMembers_ParseClass( const TOKEN *tok1, std::vector<const char *> &classname );
|
||||
void CheckMemoryLeak_ClassMembers();
|
||||
void CheckMemoryLeak_InFunction();
|
||||
void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char varname[] );
|
||||
|
||||
/**
|
||||
* Simplify code e.g. by replacing empty "{ }" with ";"
|
||||
* @param tok first token. The tokens list can be modified.
|
||||
*/
|
||||
void simplifycode(TOKEN *tok);
|
||||
|
||||
/**
|
||||
* Delete tokens between begin and end. E.g. if begin = 1
|
||||
* and end = 5, tokens 2,3 and 4 would be erased.
|
||||
*
|
||||
* @param begin Tokens after this will be erased.
|
||||
* @param end Tokens before this will be erased.
|
||||
*/
|
||||
void erase(TOKEN *begin, const TOKEN *end);
|
||||
|
||||
/**
|
||||
* Extract a new tokens list that is easier to parse than the "tokens"
|
||||
* @param tok start parse token
|
||||
* @param callstack callstack
|
||||
* @param varname name of variable
|
||||
* @param alloctype
|
||||
* @param dealloctype
|
||||
* @return Newly allocated token array. Caller needs to release reserved
|
||||
* memory by calling Tokenizer::deleteTokens(returnValue);
|
||||
*/
|
||||
TOKEN *getcode(const TOKEN *tok, std::list<const TOKEN *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype);
|
||||
bool notvar(const TOKEN *tok, const char *varnames[]);
|
||||
void instoken(TOKEN *tok, const char str[]);
|
||||
void MemoryLeak( const TOKEN *tok, const char varname[], AllocType alloctype );
|
||||
void MismatchError( const TOKEN *Tok1, const std::list<const TOKEN *> &callstack, const char varname[] );
|
||||
const char * call_func( const TOKEN *tok, std::list<const TOKEN *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype );
|
||||
AllocType GetDeallocationType( const TOKEN *tok, const char *varnames[]);
|
||||
AllocType GetAllocationType( const TOKEN *tok2 );
|
||||
AllocType GetReallocationType( const TOKEN *tok2 );
|
||||
bool isclass( const TOKEN *typestr );
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
ErrorLogger *_errorLogger;
|
||||
const Settings _settings;
|
||||
std::list<AllocFunc> _listAllocFunc;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
|
1720
checkother.cpp
1720
checkother.cpp
File diff suppressed because it is too large
Load Diff
166
checkother.h
166
checkother.h
|
@ -1,90 +1,90 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckOtherH
|
||||
#define CheckOtherH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckOther
|
||||
{
|
||||
public:
|
||||
CheckOther( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
|
||||
~CheckOther();
|
||||
|
||||
// Casting
|
||||
void WarningOldStylePointerCast();
|
||||
|
||||
// Redundant code
|
||||
void WarningRedundantCode();
|
||||
|
||||
// Warning upon: if (condition);
|
||||
void WarningIf();
|
||||
|
||||
// Assignment in condition
|
||||
void CheckIfAssignment();
|
||||
|
||||
// Invalid function usage..
|
||||
void InvalidFunctionUsage();
|
||||
|
||||
// Check for unsigned division that might create bad results
|
||||
void CheckUnsignedDivision();
|
||||
|
||||
// Check scope of variables
|
||||
void CheckVariableScope();
|
||||
|
||||
// Check for constant function parameter
|
||||
void CheckConstantFunctionParameter();
|
||||
|
||||
// Check that all struct members are used
|
||||
void CheckStructMemberUsage();
|
||||
|
||||
// Using char variable as array index / as operand in bit operation
|
||||
void CheckCharVariable();
|
||||
|
||||
// Incomplete statement. A statement that only contains a constant or variable
|
||||
void CheckIncompleteStatement();
|
||||
|
||||
/** Unreachable code below a 'return' */
|
||||
void unreachableCode();
|
||||
|
||||
/** Unused function variables */
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef CheckOtherH
|
||||
#define CheckOtherH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "tokenize.h"
|
||||
#include "errorlogger.h"
|
||||
|
||||
class CheckOther
|
||||
{
|
||||
public:
|
||||
CheckOther( const Tokenizer *tokenizer, ErrorLogger *errorLogger );
|
||||
~CheckOther();
|
||||
|
||||
// Casting
|
||||
void WarningOldStylePointerCast();
|
||||
|
||||
// Redundant code
|
||||
void WarningRedundantCode();
|
||||
|
||||
// Warning upon: if (condition);
|
||||
void WarningIf();
|
||||
|
||||
// Assignment in condition
|
||||
void CheckIfAssignment();
|
||||
|
||||
// Invalid function usage..
|
||||
void InvalidFunctionUsage();
|
||||
|
||||
// Check for unsigned division that might create bad results
|
||||
void CheckUnsignedDivision();
|
||||
|
||||
// Check scope of variables
|
||||
void CheckVariableScope();
|
||||
|
||||
// Check for constant function parameter
|
||||
void CheckConstantFunctionParameter();
|
||||
|
||||
// Check that all struct members are used
|
||||
void CheckStructMemberUsage();
|
||||
|
||||
// Using char variable as array index / as operand in bit operation
|
||||
void CheckCharVariable();
|
||||
|
||||
// Incomplete statement. A statement that only contains a constant or variable
|
||||
void CheckIncompleteStatement();
|
||||
|
||||
/** Unreachable code below a 'return' */
|
||||
void unreachableCode();
|
||||
|
||||
/** Unused function variables */
|
||||
void functionVariableUsage();
|
||||
|
||||
#ifndef UNIT_TESTING
|
||||
#ifndef UNIT_TESTING
|
||||
private:
|
||||
#endif
|
||||
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
|
||||
#endif
|
||||
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
|
||||
|
||||
// Redundant condition
|
||||
// if (haystack.find(needle) != haystack.end())
|
||||
// Redundant condition
|
||||
// if (haystack.find(needle) != haystack.end())
|
||||
// haystack.remove(needle);
|
||||
void redundantCondition2();
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
ErrorLogger *_errorLogger;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
ErrorLogger *_errorLogger;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
|
|
720
cppcheck.cpp
720
cppcheck.cpp
|
@ -1,360 +1,360 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
#include "cppcheck.h"
|
||||
|
||||
#include "preprocessor.h" // preprocessor.
|
||||
#include "tokenize.h" // <- Tokenizer
|
||||
|
||||
#include "checkmemoryleak.h"
|
||||
#include "checkbufferoverrun.h"
|
||||
#include "checkclass.h"
|
||||
#include "checkheaders.h"
|
||||
#include "checkother.h"
|
||||
#include "checkfunctionusage.h"
|
||||
#include "filelister.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CppCheck::CppCheck( ErrorLogger &errorLogger ) : _checkFunctionUsage( this )
|
||||
{
|
||||
_errorLogger = &errorLogger;
|
||||
}
|
||||
|
||||
CppCheck::~CppCheck()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CppCheck::settings( const Settings &settings )
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
void CppCheck::addFile( const std::string &path )
|
||||
{
|
||||
_filenames.push_back( path );
|
||||
}
|
||||
|
||||
void CppCheck::addFile( const std::string &path, const std::string &content )
|
||||
{
|
||||
_filenames.push_back( path );
|
||||
_fileContents[ path ] = content;
|
||||
}
|
||||
|
||||
std::string CppCheck::parseFromArgs( int argc, const char* const argv[] )
|
||||
{
|
||||
std::vector<std::string> pathnames;
|
||||
bool Recursive = false;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
// Flag used for various purposes during debugging
|
||||
if (strcmp(argv[i],"--debug") == 0)
|
||||
_settings._debug = true;
|
||||
|
||||
// Show all messages
|
||||
else if (strcmp(argv[i],"--all") == 0)
|
||||
_settings._showAll = true;
|
||||
|
||||
// Only print something when there are errors
|
||||
else if (strcmp(argv[i],"--errorsonly")==0)
|
||||
_settings._errorsOnly = true;
|
||||
|
||||
// Checking coding style
|
||||
else if (strcmp(argv[i],"--style")==0)
|
||||
_settings._checkCodingStyle = true;
|
||||
|
||||
// Recursively check source files
|
||||
else if (strcmp(argv[i],"--recursive")==0)
|
||||
Recursive = true;
|
||||
|
||||
// Verbose error messages (configuration info)
|
||||
else if (strcmp(argv[i],"--verbose")==0)
|
||||
_settings._verbose = true;
|
||||
|
||||
else
|
||||
pathnames.push_back( argv[i] );
|
||||
}
|
||||
|
||||
// --recursive was used
|
||||
if ( Recursive )
|
||||
{
|
||||
if( pathnames.size() == 0 )
|
||||
{
|
||||
// Handle situation: cppcheck --recursive
|
||||
FileLister::RecursiveAddFiles( _filenames, "", true );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle situation: cppcheck --recursive path1 path2
|
||||
|
||||
// Execute RecursiveAddFiles() to each given file parameter
|
||||
std::vector<std::string>::const_iterator iter;
|
||||
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
||||
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string>::const_iterator iter;
|
||||
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
||||
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), false );
|
||||
}
|
||||
|
||||
if (_filenames.empty())
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "c++check 1.26\n"
|
||||
"\n"
|
||||
"C/C++ code checking\n"
|
||||
"\n"
|
||||
"Syntax:\n"
|
||||
" cppcheck [--all] [--errorsonly] [--recursive] [--style] [--verbose] [filename1] [filename2]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" --all Make the checking more sensitive. More bugs are detected,\n"
|
||||
" but there are also more false positives\n"
|
||||
" --errorsonly Only print error messages\n"
|
||||
" --recursive Recursively check all *.cpp, *.cxx, *.cc and *.c files\n"
|
||||
" --style Check coding style\n"
|
||||
" --verbose More detailed error reports\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// Check function usage if "--style" and "--all" was given.
|
||||
// There will be false positives for exported library functions
|
||||
if ( _settings._showAll && _settings._checkCodingStyle )
|
||||
_settings._checkFunctionUsage = true;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void CppCheck::check()
|
||||
{
|
||||
std::sort( _filenames.begin(), _filenames.end() );
|
||||
for (unsigned int c = 0; c < _filenames.size(); c++)
|
||||
{
|
||||
_errout.str("");
|
||||
std::string fname = _filenames[c];
|
||||
|
||||
// If only errors are printed, print filename after the check
|
||||
if ( _settings._errorsOnly == false )
|
||||
_errorLogger->reportOut( std::string( "Checking " ) + fname + std::string( "..." ) );
|
||||
|
||||
Preprocessor preprocessor;
|
||||
std::map<std::string, std::string> code;
|
||||
if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() )
|
||||
{
|
||||
// File content was given as a string
|
||||
std::istringstream iss( _fileContents[ _filenames[c] ] );
|
||||
preprocessor.preprocess(iss, code, fname);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only file name was given, read the content from file
|
||||
std::ifstream fin( fname.c_str() );
|
||||
preprocessor.preprocess(fin, code, fname);
|
||||
}
|
||||
|
||||
for ( std::map<std::string,std::string>::const_iterator it = code.begin(); it != code.end(); ++it )
|
||||
{
|
||||
cfg = it->first;
|
||||
checkFile(it->second, _filenames[c].c_str());
|
||||
}
|
||||
|
||||
if ( _settings._errorsOnly == false && _errout.str().empty() )
|
||||
_errorLogger->reportOut( "No errors found" );
|
||||
}
|
||||
|
||||
// This generates false positives - especially for libraries
|
||||
_settings._verbose = false;
|
||||
if ( _settings._checkFunctionUsage )
|
||||
{
|
||||
_errout.str("");
|
||||
if( _settings._errorsOnly == false )
|
||||
_errorLogger->reportOut( "Checking usage of global functions (this may take several minutes).." );
|
||||
|
||||
_checkFunctionUsage.check();
|
||||
}
|
||||
|
||||
_errorList.clear();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// CppCheck - A function that checks a specified file
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||
{
|
||||
Tokenizer _tokenizer;
|
||||
|
||||
// Tokenize the file
|
||||
{
|
||||
std::istringstream istr(code);
|
||||
_tokenizer.tokenize(istr, FileName);
|
||||
}
|
||||
|
||||
// Set variable id
|
||||
_tokenizer.setVarId();
|
||||
|
||||
_tokenizer.fillFunctionList();
|
||||
|
||||
// Check that the memsets are valid.
|
||||
// The 'memset' function can do dangerous things if used wrong.
|
||||
// Important: The checking doesn't work on simplified tokens list.
|
||||
CheckClass checkClass( &_tokenizer, _settings, this );
|
||||
checkClass.CheckMemset();
|
||||
|
||||
|
||||
// Check for unsigned divisions where one operand is signed
|
||||
// Very important to run it before 'SimplifyTokenList'
|
||||
CheckOther checkOther( &_tokenizer, this );
|
||||
if ( _settings._checkCodingStyle )
|
||||
checkOther.CheckUnsignedDivision();
|
||||
|
||||
// Give warning when using char variable as array index
|
||||
// Doesn't work on simplified token list ('unsigned')
|
||||
if ( _settings._checkCodingStyle )
|
||||
checkOther.CheckCharVariable();
|
||||
|
||||
|
||||
// Including header which is not needed (too many false positives)
|
||||
// if ( _settings._checkCodingStyle )
|
||||
// {
|
||||
// CheckHeaders checkHeaders( &tokenizer );
|
||||
// checkHeaders.WarningIncludeHeader();
|
||||
// }
|
||||
|
||||
|
||||
_tokenizer.simplifyTokenList();
|
||||
|
||||
|
||||
if ( _settings._checkFunctionUsage )
|
||||
_checkFunctionUsage.parseTokens(_tokenizer);
|
||||
|
||||
// Memory leak
|
||||
CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this );
|
||||
checkMemoryLeak.CheckMemoryLeak();
|
||||
|
||||
// Buffer overruns..
|
||||
CheckBufferOverrunClass checkBufferOverrun( &_tokenizer, _settings, this );
|
||||
checkBufferOverrun.CheckBufferOverrun();
|
||||
|
||||
// Check that all class constructors are ok.
|
||||
checkClass.CheckConstructors();
|
||||
|
||||
// Check that all base classes have virtual destructors
|
||||
checkClass.virtualDestructor();
|
||||
|
||||
if (_settings._showAll)
|
||||
{
|
||||
// Check for "if (a=b)"
|
||||
checkOther.CheckIfAssignment();
|
||||
|
||||
// Check for case without break
|
||||
// Disabled because it generates many false positives
|
||||
// CheckCaseWithoutBreak();
|
||||
|
||||
// Dangerous usage of strtok
|
||||
// Disabled because it generates false positives
|
||||
//WarningStrTok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Dangerous functions, such as 'gets' and 'scanf'
|
||||
checkBufferOverrun.WarningDangerousFunctions();
|
||||
|
||||
|
||||
// Invalid function usage..
|
||||
checkOther.InvalidFunctionUsage();
|
||||
|
||||
|
||||
if (_settings._checkCodingStyle)
|
||||
{
|
||||
// Check that all private functions are called.
|
||||
checkClass.CheckUnusedPrivateFunctions();
|
||||
|
||||
// Warning upon c-style pointer casts
|
||||
const char *ext = strrchr(FileName, '.');
|
||||
if (ext && strcmp(ext,".cpp")==0)
|
||||
checkOther.WarningOldStylePointerCast();
|
||||
|
||||
checkClass.CheckOperatorEq1();
|
||||
|
||||
// if (a) delete a;
|
||||
checkOther.WarningRedundantCode();
|
||||
|
||||
// if (condition);
|
||||
checkOther.WarningIf();
|
||||
|
||||
// Variable scope (check if the scope could be limited)
|
||||
//CheckVariableScope();
|
||||
|
||||
// Check if a constant function parameter is passed by value
|
||||
checkOther.CheckConstantFunctionParameter();
|
||||
|
||||
// Unused struct members..
|
||||
checkOther.CheckStructMemberUsage();
|
||||
|
||||
// Check for various types of incomplete statements that could for example
|
||||
// mean that an ';' has been added by accident
|
||||
checkOther.CheckIncompleteStatement();
|
||||
|
||||
// Unreachable code below a 'return' statement
|
||||
checkOther.unreachableCode();
|
||||
|
||||
// Usage of local functions
|
||||
checkOther.functionVariableUsage();
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void CppCheck::reportErr( const std::string &errmsg)
|
||||
{
|
||||
if ( /*OnlyReportUniqueErrors*/ true )
|
||||
{
|
||||
if ( std::find( _errorList.begin(), _errorList.end(), errmsg ) != _errorList.end() )
|
||||
return;
|
||||
_errorList.push_back( errmsg );
|
||||
}
|
||||
|
||||
std::string errmsg2( errmsg );
|
||||
if ( _settings._verbose )
|
||||
{
|
||||
errmsg2 += "\n Defines=\'" + cfg + "\'\n";
|
||||
}
|
||||
|
||||
|
||||
_errorLogger->reportErr( errmsg2 );
|
||||
|
||||
_errout << errmsg2 << std::endl;
|
||||
}
|
||||
|
||||
void CppCheck::reportOut( const std::string &outmsg)
|
||||
{
|
||||
// This is currently never called. It is here just to comply with
|
||||
// the interface.
|
||||
}
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
#include "cppcheck.h"
|
||||
|
||||
#include "preprocessor.h" // preprocessor.
|
||||
#include "tokenize.h" // <- Tokenizer
|
||||
|
||||
#include "checkmemoryleak.h"
|
||||
#include "checkbufferoverrun.h"
|
||||
#include "checkclass.h"
|
||||
#include "checkheaders.h"
|
||||
#include "checkother.h"
|
||||
#include "checkfunctionusage.h"
|
||||
#include "filelister.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CppCheck::CppCheck( ErrorLogger &errorLogger ) : _checkFunctionUsage( this )
|
||||
{
|
||||
_errorLogger = &errorLogger;
|
||||
}
|
||||
|
||||
CppCheck::~CppCheck()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CppCheck::settings( const Settings &settings )
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
void CppCheck::addFile( const std::string &path )
|
||||
{
|
||||
_filenames.push_back( path );
|
||||
}
|
||||
|
||||
void CppCheck::addFile( const std::string &path, const std::string &content )
|
||||
{
|
||||
_filenames.push_back( path );
|
||||
_fileContents[ path ] = content;
|
||||
}
|
||||
|
||||
std::string CppCheck::parseFromArgs( int argc, const char* const argv[] )
|
||||
{
|
||||
std::vector<std::string> pathnames;
|
||||
bool Recursive = false;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
// Flag used for various purposes during debugging
|
||||
if (strcmp(argv[i],"--debug") == 0)
|
||||
_settings._debug = true;
|
||||
|
||||
// Show all messages
|
||||
else if (strcmp(argv[i],"--all") == 0)
|
||||
_settings._showAll = true;
|
||||
|
||||
// Only print something when there are errors
|
||||
else if (strcmp(argv[i],"--errorsonly")==0)
|
||||
_settings._errorsOnly = true;
|
||||
|
||||
// Checking coding style
|
||||
else if (strcmp(argv[i],"--style")==0)
|
||||
_settings._checkCodingStyle = true;
|
||||
|
||||
// Recursively check source files
|
||||
else if (strcmp(argv[i],"--recursive")==0)
|
||||
Recursive = true;
|
||||
|
||||
// Verbose error messages (configuration info)
|
||||
else if (strcmp(argv[i],"--verbose")==0)
|
||||
_settings._verbose = true;
|
||||
|
||||
else
|
||||
pathnames.push_back( argv[i] );
|
||||
}
|
||||
|
||||
// --recursive was used
|
||||
if ( Recursive )
|
||||
{
|
||||
if( pathnames.size() == 0 )
|
||||
{
|
||||
// Handle situation: cppcheck --recursive
|
||||
FileLister::RecursiveAddFiles( _filenames, "", true );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle situation: cppcheck --recursive path1 path2
|
||||
|
||||
// Execute RecursiveAddFiles() to each given file parameter
|
||||
std::vector<std::string>::const_iterator iter;
|
||||
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
||||
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string>::const_iterator iter;
|
||||
for(iter=pathnames.begin(); iter!=pathnames.end(); iter++)
|
||||
FileLister::RecursiveAddFiles( _filenames, iter->c_str(), false );
|
||||
}
|
||||
|
||||
if (_filenames.empty())
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "c++check 1.26\n"
|
||||
"\n"
|
||||
"C/C++ code checking\n"
|
||||
"\n"
|
||||
"Syntax:\n"
|
||||
" cppcheck [--all] [--errorsonly] [--recursive] [--style] [--verbose] [filename1] [filename2]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" --all Make the checking more sensitive. More bugs are detected,\n"
|
||||
" but there are also more false positives\n"
|
||||
" --errorsonly Only print error messages\n"
|
||||
" --recursive Recursively check all *.cpp, *.cxx, *.cc and *.c files\n"
|
||||
" --style Check coding style\n"
|
||||
" --verbose More detailed error reports\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// Check function usage if "--style" and "--all" was given.
|
||||
// There will be false positives for exported library functions
|
||||
if ( _settings._showAll && _settings._checkCodingStyle )
|
||||
_settings._checkFunctionUsage = true;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void CppCheck::check()
|
||||
{
|
||||
std::sort( _filenames.begin(), _filenames.end() );
|
||||
for (unsigned int c = 0; c < _filenames.size(); c++)
|
||||
{
|
||||
_errout.str("");
|
||||
std::string fname = _filenames[c];
|
||||
|
||||
// If only errors are printed, print filename after the check
|
||||
if ( _settings._errorsOnly == false )
|
||||
_errorLogger->reportOut( std::string( "Checking " ) + fname + std::string( "..." ) );
|
||||
|
||||
Preprocessor preprocessor;
|
||||
std::map<std::string, std::string> code;
|
||||
if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() )
|
||||
{
|
||||
// File content was given as a string
|
||||
std::istringstream iss( _fileContents[ _filenames[c] ] );
|
||||
preprocessor.preprocess(iss, code, fname);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only file name was given, read the content from file
|
||||
std::ifstream fin( fname.c_str() );
|
||||
preprocessor.preprocess(fin, code, fname);
|
||||
}
|
||||
|
||||
for ( std::map<std::string,std::string>::const_iterator it = code.begin(); it != code.end(); ++it )
|
||||
{
|
||||
cfg = it->first;
|
||||
checkFile(it->second, _filenames[c].c_str());
|
||||
}
|
||||
|
||||
if ( _settings._errorsOnly == false && _errout.str().empty() )
|
||||
_errorLogger->reportOut( "No errors found" );
|
||||
}
|
||||
|
||||
// This generates false positives - especially for libraries
|
||||
_settings._verbose = false;
|
||||
if ( _settings._checkFunctionUsage )
|
||||
{
|
||||
_errout.str("");
|
||||
if( _settings._errorsOnly == false )
|
||||
_errorLogger->reportOut( "Checking usage of global functions (this may take several minutes).." );
|
||||
|
||||
_checkFunctionUsage.check();
|
||||
}
|
||||
|
||||
_errorList.clear();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// CppCheck - A function that checks a specified file
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||
{
|
||||
Tokenizer _tokenizer;
|
||||
|
||||
// Tokenize the file
|
||||
{
|
||||
std::istringstream istr(code);
|
||||
_tokenizer.tokenize(istr, FileName);
|
||||
}
|
||||
|
||||
// Set variable id
|
||||
_tokenizer.setVarId();
|
||||
|
||||
_tokenizer.fillFunctionList();
|
||||
|
||||
// Check that the memsets are valid.
|
||||
// The 'memset' function can do dangerous things if used wrong.
|
||||
// Important: The checking doesn't work on simplified tokens list.
|
||||
CheckClass checkClass( &_tokenizer, _settings, this );
|
||||
checkClass.CheckMemset();
|
||||
|
||||
|
||||
// Check for unsigned divisions where one operand is signed
|
||||
// Very important to run it before 'SimplifyTokenList'
|
||||
CheckOther checkOther( &_tokenizer, this );
|
||||
if ( _settings._checkCodingStyle )
|
||||
checkOther.CheckUnsignedDivision();
|
||||
|
||||
// Give warning when using char variable as array index
|
||||
// Doesn't work on simplified token list ('unsigned')
|
||||
if ( _settings._checkCodingStyle )
|
||||
checkOther.CheckCharVariable();
|
||||
|
||||
|
||||
// Including header which is not needed (too many false positives)
|
||||
// if ( _settings._checkCodingStyle )
|
||||
// {
|
||||
// CheckHeaders checkHeaders( &tokenizer );
|
||||
// checkHeaders.WarningIncludeHeader();
|
||||
// }
|
||||
|
||||
|
||||
_tokenizer.simplifyTokenList();
|
||||
|
||||
|
||||
if ( _settings._checkFunctionUsage )
|
||||
_checkFunctionUsage.parseTokens(_tokenizer);
|
||||
|
||||
// Memory leak
|
||||
CheckMemoryLeakClass checkMemoryLeak( &_tokenizer, _settings, this );
|
||||
checkMemoryLeak.CheckMemoryLeak();
|
||||
|
||||
// Buffer overruns..
|
||||
CheckBufferOverrunClass checkBufferOverrun( &_tokenizer, _settings, this );
|
||||
checkBufferOverrun.CheckBufferOverrun();
|
||||
|
||||
// Check that all class constructors are ok.
|
||||
checkClass.CheckConstructors();
|
||||
|
||||
// Check that all base classes have virtual destructors
|
||||
checkClass.virtualDestructor();
|
||||
|
||||
if (_settings._showAll)
|
||||
{
|
||||
// Check for "if (a=b)"
|
||||
checkOther.CheckIfAssignment();
|
||||
|
||||
// Check for case without break
|
||||
// Disabled because it generates many false positives
|
||||
// CheckCaseWithoutBreak();
|
||||
|
||||
// Dangerous usage of strtok
|
||||
// Disabled because it generates false positives
|
||||
//WarningStrTok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Dangerous functions, such as 'gets' and 'scanf'
|
||||
checkBufferOverrun.WarningDangerousFunctions();
|
||||
|
||||
|
||||
// Invalid function usage..
|
||||
checkOther.InvalidFunctionUsage();
|
||||
|
||||
|
||||
if (_settings._checkCodingStyle)
|
||||
{
|
||||
// Check that all private functions are called.
|
||||
checkClass.CheckUnusedPrivateFunctions();
|
||||
|
||||
// Warning upon c-style pointer casts
|
||||
const char *ext = strrchr(FileName, '.');
|
||||
if (ext && strcmp(ext,".cpp")==0)
|
||||
checkOther.WarningOldStylePointerCast();
|
||||
|
||||
checkClass.CheckOperatorEq1();
|
||||
|
||||
// if (a) delete a;
|
||||
checkOther.WarningRedundantCode();
|
||||
|
||||
// if (condition);
|
||||
checkOther.WarningIf();
|
||||
|
||||
// Variable scope (check if the scope could be limited)
|
||||
//CheckVariableScope();
|
||||
|
||||
// Check if a constant function parameter is passed by value
|
||||
checkOther.CheckConstantFunctionParameter();
|
||||
|
||||
// Unused struct members..
|
||||
checkOther.CheckStructMemberUsage();
|
||||
|
||||
// Check for various types of incomplete statements that could for example
|
||||
// mean that an ';' has been added by accident
|
||||
checkOther.CheckIncompleteStatement();
|
||||
|
||||
// Unreachable code below a 'return' statement
|
||||
checkOther.unreachableCode();
|
||||
|
||||
// Usage of local functions
|
||||
checkOther.functionVariableUsage();
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void CppCheck::reportErr( const std::string &errmsg)
|
||||
{
|
||||
if ( /*OnlyReportUniqueErrors*/ true )
|
||||
{
|
||||
if ( std::find( _errorList.begin(), _errorList.end(), errmsg ) != _errorList.end() )
|
||||
return;
|
||||
_errorList.push_back( errmsg );
|
||||
}
|
||||
|
||||
std::string errmsg2( errmsg );
|
||||
if ( _settings._verbose )
|
||||
{
|
||||
errmsg2 += "\n Defines=\'" + cfg + "\'\n";
|
||||
}
|
||||
|
||||
|
||||
_errorLogger->reportErr( errmsg2 );
|
||||
|
||||
_errout << errmsg2 << std::endl;
|
||||
}
|
||||
|
||||
void CppCheck::reportOut( const std::string &outmsg)
|
||||
{
|
||||
// This is currently never called. It is here just to comply with
|
||||
// the interface.
|
||||
}
|
||||
|
|
252
cppcheck.h
252
cppcheck.h
|
@ -1,126 +1,126 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef CPPCHECK_H
|
||||
#define CPPCHECK_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
#include "checkfunctionusage.h"
|
||||
|
||||
/**
|
||||
* This is the base class which will use other classes to do
|
||||
* static code analysis for C and C++ code to find possible
|
||||
* errors or places that could be improved.
|
||||
* Usage: See check() for more info.
|
||||
*/
|
||||
class CppCheck : public ErrorLogger
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
CppCheck( ErrorLogger &errorLogger );
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~CppCheck();
|
||||
|
||||
/**
|
||||
* This starts the actual checking. Note that you must call
|
||||
* parseFromArgs() or settings() and addFile() before calling this.
|
||||
*/
|
||||
void check();
|
||||
|
||||
/**
|
||||
* Adjust the settings before doing the check. E.g. show only
|
||||
* actual bugs or also coding style issues.
|
||||
*
|
||||
* @param settings New settings which will overwrite the old.
|
||||
*/
|
||||
void settings( const Settings &settings );
|
||||
|
||||
/**
|
||||
* Add new file to be checked.
|
||||
*
|
||||
* @param path Relative or absolute path to the file to be checked,
|
||||
* e.g. "cppcheck.cpp". Note that only source files (.c, .cc or .cpp)
|
||||
* should be added to the list. Include filese are gathered automatically.
|
||||
*/
|
||||
void addFile( const std::string &path );
|
||||
|
||||
/**
|
||||
* Add new unreal file to be checked.
|
||||
*
|
||||
* @param path File name (used for error reporting).
|
||||
* @param content If the file would be a real file, this should be
|
||||
* the content of the file.
|
||||
*/
|
||||
void addFile( const std::string &path, const std::string &content );
|
||||
|
||||
/**
|
||||
* Parse command line args and get settings and file lists
|
||||
* from there.
|
||||
*
|
||||
* @param argc argc from main()
|
||||
* @param argv argv from main()
|
||||
* @return Empty string if parameters were accepted, or
|
||||
* string containing "help" text if no files were found to be
|
||||
* checked.
|
||||
*/
|
||||
std::string parseFromArgs( int argc, const char* const argv[] );
|
||||
|
||||
private:
|
||||
void checkFile(const std::string &code, const char FileName[]);
|
||||
|
||||
/**
|
||||
* Errors and warnings are directed here.
|
||||
*
|
||||
* @param errmsg Errors messages are normally in format
|
||||
* "[filepath:line number] Message", e.g.
|
||||
* "[main.cpp:4] Uninitialized member variable"
|
||||
*/
|
||||
virtual void reportErr( const std::string &errmsg);
|
||||
|
||||
/**
|
||||
* Information about progress is directed here.
|
||||
*
|
||||
* @param outmsg, E.g. "Checking main.cpp..."
|
||||
*/
|
||||
virtual void reportOut( const std::string &outmsg);
|
||||
|
||||
std::list<std::string> _errorList;
|
||||
std::ostringstream _errout;
|
||||
Settings _settings;
|
||||
std::vector<std::string> _filenames;
|
||||
/** Key is file name, and value is the content of the file */
|
||||
std::map<std::string,std::string> _fileContents;
|
||||
CheckFunctionUsage _checkFunctionUsage;
|
||||
ErrorLogger *_errorLogger;
|
||||
|
||||
/** Current configuration */
|
||||
std::string cfg;
|
||||
};
|
||||
|
||||
#endif // CPPCHECK_H
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef CPPCHECK_H
|
||||
#define CPPCHECK_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
#include "checkfunctionusage.h"
|
||||
|
||||
/**
|
||||
* This is the base class which will use other classes to do
|
||||
* static code analysis for C and C++ code to find possible
|
||||
* errors or places that could be improved.
|
||||
* Usage: See check() for more info.
|
||||
*/
|
||||
class CppCheck : public ErrorLogger
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
CppCheck( ErrorLogger &errorLogger );
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~CppCheck();
|
||||
|
||||
/**
|
||||
* This starts the actual checking. Note that you must call
|
||||
* parseFromArgs() or settings() and addFile() before calling this.
|
||||
*/
|
||||
void check();
|
||||
|
||||
/**
|
||||
* Adjust the settings before doing the check. E.g. show only
|
||||
* actual bugs or also coding style issues.
|
||||
*
|
||||
* @param settings New settings which will overwrite the old.
|
||||
*/
|
||||
void settings( const Settings &settings );
|
||||
|
||||
/**
|
||||
* Add new file to be checked.
|
||||
*
|
||||
* @param path Relative or absolute path to the file to be checked,
|
||||
* e.g. "cppcheck.cpp". Note that only source files (.c, .cc or .cpp)
|
||||
* should be added to the list. Include filese are gathered automatically.
|
||||
*/
|
||||
void addFile( const std::string &path );
|
||||
|
||||
/**
|
||||
* Add new unreal file to be checked.
|
||||
*
|
||||
* @param path File name (used for error reporting).
|
||||
* @param content If the file would be a real file, this should be
|
||||
* the content of the file.
|
||||
*/
|
||||
void addFile( const std::string &path, const std::string &content );
|
||||
|
||||
/**
|
||||
* Parse command line args and get settings and file lists
|
||||
* from there.
|
||||
*
|
||||
* @param argc argc from main()
|
||||
* @param argv argv from main()
|
||||
* @return Empty string if parameters were accepted, or
|
||||
* string containing "help" text if no files were found to be
|
||||
* checked.
|
||||
*/
|
||||
std::string parseFromArgs( int argc, const char* const argv[] );
|
||||
|
||||
private:
|
||||
void checkFile(const std::string &code, const char FileName[]);
|
||||
|
||||
/**
|
||||
* Errors and warnings are directed here.
|
||||
*
|
||||
* @param errmsg Errors messages are normally in format
|
||||
* "[filepath:line number] Message", e.g.
|
||||
* "[main.cpp:4] Uninitialized member variable"
|
||||
*/
|
||||
virtual void reportErr( const std::string &errmsg);
|
||||
|
||||
/**
|
||||
* Information about progress is directed here.
|
||||
*
|
||||
* @param outmsg, E.g. "Checking main.cpp..."
|
||||
*/
|
||||
virtual void reportOut( const std::string &outmsg);
|
||||
|
||||
std::list<std::string> _errorList;
|
||||
std::ostringstream _errout;
|
||||
Settings _settings;
|
||||
std::vector<std::string> _filenames;
|
||||
/** Key is file name, and value is the content of the file */
|
||||
std::map<std::string,std::string> _fileContents;
|
||||
CheckFunctionUsage _checkFunctionUsage;
|
||||
ErrorLogger *_errorLogger;
|
||||
|
||||
/** Current configuration */
|
||||
std::string cfg;
|
||||
};
|
||||
|
||||
#endif // CPPCHECK_H
|
||||
|
|
|
@ -1,51 +1,51 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "cppcheckexecutor.h"
|
||||
#include "cppcheck.h"
|
||||
#include <iostream>
|
||||
|
||||
CppCheckExecutor::CppCheckExecutor()
|
||||
{
|
||||
//ctor
|
||||
}
|
||||
|
||||
CppCheckExecutor::~CppCheckExecutor()
|
||||
{
|
||||
//dtor
|
||||
}
|
||||
|
||||
void CppCheckExecutor::check( int argc, const char* const argv[] )
|
||||
{
|
||||
CppCheck cppCheck( *this );
|
||||
std::string result = cppCheck.parseFromArgs( argc, argv );
|
||||
if( result.length() == 0 )
|
||||
cppCheck.check();
|
||||
else
|
||||
std::cout << result;
|
||||
}
|
||||
|
||||
void CppCheckExecutor::reportErr( const std::string &errmsg)
|
||||
{
|
||||
std::cerr << errmsg << std::endl;
|
||||
}
|
||||
|
||||
void CppCheckExecutor::reportOut( const std::string &outmsg)
|
||||
{
|
||||
std::cout << outmsg << std::endl;
|
||||
}
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "cppcheckexecutor.h"
|
||||
#include "cppcheck.h"
|
||||
#include <iostream>
|
||||
|
||||
CppCheckExecutor::CppCheckExecutor()
|
||||
{
|
||||
//ctor
|
||||
}
|
||||
|
||||
CppCheckExecutor::~CppCheckExecutor()
|
||||
{
|
||||
//dtor
|
||||
}
|
||||
|
||||
void CppCheckExecutor::check( int argc, const char* const argv[] )
|
||||
{
|
||||
CppCheck cppCheck( *this );
|
||||
std::string result = cppCheck.parseFromArgs( argc, argv );
|
||||
if( result.length() == 0 )
|
||||
cppCheck.check();
|
||||
else
|
||||
std::cout << result;
|
||||
}
|
||||
|
||||
void CppCheckExecutor::reportErr( const std::string &errmsg)
|
||||
{
|
||||
std::cerr << errmsg << std::endl;
|
||||
}
|
||||
|
||||
void CppCheckExecutor::reportOut( const std::string &outmsg)
|
||||
{
|
||||
std::cout << outmsg << std::endl;
|
||||
}
|
||||
|
|
|
@ -1,71 +1,71 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef CPPCHECKEXECUTOR_H
|
||||
#define CPPCHECKEXECUTOR_H
|
||||
|
||||
#include "errorlogger.h"
|
||||
|
||||
/**
|
||||
* This class works as an example of how CppCheck can be used in external
|
||||
* programs without very little knowledge of the internal parts of the
|
||||
* program itself. If you wish to use cppcheck e.g. as a part of IDE,
|
||||
* just rewrite this class for your needs and possibly use other methods
|
||||
* from CppCheck class instead the ones used here.
|
||||
*/
|
||||
class CppCheckExecutor : public ErrorLogger
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
CppCheckExecutor();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CppCheckExecutor();
|
||||
|
||||
/**
|
||||
* Starts the checking.
|
||||
*
|
||||
* @param argc from main()
|
||||
* @param argv from main()
|
||||
*/
|
||||
void check( int argc, const char* const argv[] );
|
||||
|
||||
/**
|
||||
* Errors and warnings are directed here. This should be
|
||||
* called by the CppCheck class only.
|
||||
*
|
||||
* @param errmsg Errors messages are normally in format
|
||||
* "[filepath:line number] Message", e.g.
|
||||
* "[main.cpp:4] Uninitialized member variable"
|
||||
*/
|
||||
virtual void reportErr( const std::string &errmsg);
|
||||
|
||||
/**
|
||||
* Information about progress is directed here. This should be
|
||||
* called by the CppCheck class only.
|
||||
*
|
||||
* @param outmsg, E.g. "Checking main.cpp..."
|
||||
*/
|
||||
virtual void reportOut( const std::string &outmsg);
|
||||
};
|
||||
|
||||
#endif // CPPCHECKEXECUTOR_H
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef CPPCHECKEXECUTOR_H
|
||||
#define CPPCHECKEXECUTOR_H
|
||||
|
||||
#include "errorlogger.h"
|
||||
|
||||
/**
|
||||
* This class works as an example of how CppCheck can be used in external
|
||||
* programs without very little knowledge of the internal parts of the
|
||||
* program itself. If you wish to use cppcheck e.g. as a part of IDE,
|
||||
* just rewrite this class for your needs and possibly use other methods
|
||||
* from CppCheck class instead the ones used here.
|
||||
*/
|
||||
class CppCheckExecutor : public ErrorLogger
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
CppCheckExecutor();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CppCheckExecutor();
|
||||
|
||||
/**
|
||||
* Starts the checking.
|
||||
*
|
||||
* @param argc from main()
|
||||
* @param argv from main()
|
||||
*/
|
||||
void check( int argc, const char* const argv[] );
|
||||
|
||||
/**
|
||||
* Errors and warnings are directed here. This should be
|
||||
* called by the CppCheck class only.
|
||||
*
|
||||
* @param errmsg Errors messages are normally in format
|
||||
* "[filepath:line number] Message", e.g.
|
||||
* "[main.cpp:4] Uninitialized member variable"
|
||||
*/
|
||||
virtual void reportErr( const std::string &errmsg);
|
||||
|
||||
/**
|
||||
* Information about progress is directed here. This should be
|
||||
* called by the CppCheck class only.
|
||||
*
|
||||
* @param outmsg, E.g. "Checking main.cpp..."
|
||||
*/
|
||||
virtual void reportOut( const std::string &outmsg);
|
||||
};
|
||||
|
||||
#endif // CPPCHECKEXECUTOR_H
|
||||
|
|
100
errorlogger.h
100
errorlogger.h
|
@ -1,50 +1,50 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef ERRORLOGGER_H
|
||||
#define ERRORLOGGER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* This is an interface, which the class responsible of error logging
|
||||
* should implement.
|
||||
*/
|
||||
class ErrorLogger
|
||||
{
|
||||
public:
|
||||
virtual ~ErrorLogger() {}
|
||||
|
||||
/**
|
||||
* Errors and warnings are directed here.
|
||||
*
|
||||
* @param errmsg Errors messages are normally in format
|
||||
* "[filepath:line number] Message", e.g.
|
||||
* "[main.cpp:4] Uninitialized member variable"
|
||||
*/
|
||||
virtual void reportErr( const std::string &errmsg) = 0;
|
||||
|
||||
/**
|
||||
* Information about progress is directed here.
|
||||
*
|
||||
* @param outmsg, E.g. "Checking main.cpp..."
|
||||
*/
|
||||
virtual void reportOut( const std::string &outmsg) = 0;
|
||||
};
|
||||
|
||||
#endif // #ifndef ERRORLOGGER_H
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef ERRORLOGGER_H
|
||||
#define ERRORLOGGER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* This is an interface, which the class responsible of error logging
|
||||
* should implement.
|
||||
*/
|
||||
class ErrorLogger
|
||||
{
|
||||
public:
|
||||
virtual ~ErrorLogger() {}
|
||||
|
||||
/**
|
||||
* Errors and warnings are directed here.
|
||||
*
|
||||
* @param errmsg Errors messages are normally in format
|
||||
* "[filepath:line number] Message", e.g.
|
||||
* "[main.cpp:4] Uninitialized member variable"
|
||||
*/
|
||||
virtual void reportErr( const std::string &errmsg) = 0;
|
||||
|
||||
/**
|
||||
* Information about progress is directed here.
|
||||
*
|
||||
* @param outmsg, E.g. "Checking main.cpp..."
|
||||
*/
|
||||
virtual void reportOut( const std::string &outmsg) = 0;
|
||||
};
|
||||
|
||||
#endif // #ifndef ERRORLOGGER_H
|
||||
|
|
420
filelister.cpp
420
filelister.cpp
|
@ -1,210 +1,210 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "filelister.h"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <glob.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
std::string FileLister::simplifyPath( const char *originalPath )
|
||||
{
|
||||
std::string subPath = "";
|
||||
std::vector<std::string> pathParts;
|
||||
for( ; *originalPath; ++originalPath )
|
||||
{
|
||||
if( *originalPath == '/' )
|
||||
{
|
||||
if( subPath.length() > 0 )
|
||||
{
|
||||
pathParts.push_back( subPath );
|
||||
subPath = "";
|
||||
}
|
||||
|
||||
pathParts.push_back( "/" );
|
||||
}
|
||||
else
|
||||
subPath.append( 1, *originalPath );
|
||||
}
|
||||
|
||||
if( subPath.length() > 0 )
|
||||
pathParts.push_back( subPath );
|
||||
|
||||
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
|
||||
{
|
||||
if( pathParts[i] == ".." && i > 1 )
|
||||
{
|
||||
pathParts.erase( pathParts.begin() + i );
|
||||
pathParts.erase( pathParts.begin()+i-1 );
|
||||
pathParts.erase( pathParts.begin()+i-2 );
|
||||
i = 0;
|
||||
}
|
||||
else if( i > 0 && pathParts[i] == "." )
|
||||
{
|
||||
pathParts.erase( pathParts.begin()+i );
|
||||
i = 0;
|
||||
}
|
||||
else if( pathParts[i] == "/" && i > 0 && pathParts[i-1] == "/" )
|
||||
{
|
||||
pathParts.erase( pathParts.begin()+i-1 );
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
|
||||
{
|
||||
oss << pathParts[i];
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool FileLister::AcceptFile( const std::string &filename )
|
||||
{
|
||||
std::string::size_type dotLocation = filename.find_last_of ( '.' );
|
||||
if ( dotLocation == std::string::npos )
|
||||
return false;
|
||||
|
||||
std::string extension = filename.substr( dotLocation );
|
||||
|
||||
if( extension == ".cpp" ||
|
||||
extension == ".cxx" ||
|
||||
extension == ".cc" ||
|
||||
extension == ".c" )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
////// This code is for __GNUC__ only /////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __GNUC__
|
||||
// gcc / cygwin..
|
||||
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << path;
|
||||
if( recursive )
|
||||
{
|
||||
if ( path.length() > 0 && path[path.length()-1] != '/' )
|
||||
oss << "/";
|
||||
|
||||
oss << "*";
|
||||
}
|
||||
|
||||
glob_t glob_results;
|
||||
glob( oss.str().c_str(), GLOB_MARK, 0, &glob_results);
|
||||
for ( unsigned int i = 0; i < glob_results.gl_pathc; i++ )
|
||||
{
|
||||
std::string filename = glob_results.gl_pathv[i];
|
||||
if ( filename == "." || filename == ".." || filename.length() == 0 )
|
||||
continue;
|
||||
|
||||
if ( filename[filename.length()-1] != '/' )
|
||||
{
|
||||
// File
|
||||
|
||||
// If recursive is not used, accept all files given by user
|
||||
if( !recursive || FileLister::AcceptFile( filename ) )
|
||||
filenames.push_back( filename );
|
||||
}
|
||||
else if( recursive )
|
||||
{
|
||||
// Directory
|
||||
FileLister::RecursiveAddFiles( filenames, filename, recursive );
|
||||
}
|
||||
}
|
||||
globfree(&glob_results);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
////// This code is for Borland C++ and Visual C++ ////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
|
||||
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
|
||||
{
|
||||
std::ostringstream bdir, oss;
|
||||
oss << path;
|
||||
if (recursive)
|
||||
{
|
||||
bdir << path;
|
||||
if ( path.length() > 0 && path[path.length()-1] != '/' )
|
||||
{
|
||||
bdir << "/";
|
||||
oss << "/";
|
||||
}
|
||||
|
||||
oss << "*";
|
||||
}
|
||||
|
||||
WIN32_FIND_DATA ffd;
|
||||
HANDLE hFind = FindFirstFile(oss.str().c_str(), &ffd);
|
||||
if ( INVALID_HANDLE_VALUE == hFind )
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
std::ostringstream fname;
|
||||
fname << bdir.str().c_str() << ffd.cFileName;
|
||||
|
||||
if ( ffd.cFileName[0] == '.' || ffd.cFileName[0] == '\0' )
|
||||
continue;
|
||||
|
||||
if ( ( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
|
||||
{
|
||||
// File
|
||||
|
||||
// If recursive is not used, accept all files given by user
|
||||
if ( !recursive || FileLister::AcceptFile( ffd.cFileName ) )
|
||||
filenames.push_back( fname.str() );
|
||||
}
|
||||
else if ( recursive )
|
||||
{
|
||||
// Directory
|
||||
fname << "/";
|
||||
FileLister::RecursiveAddFiles( filenames, fname.str().c_str(), recursive );
|
||||
}
|
||||
}
|
||||
while (FindNextFile(hFind, &ffd) != FALSE);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "filelister.h"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <glob.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
std::string FileLister::simplifyPath( const char *originalPath )
|
||||
{
|
||||
std::string subPath = "";
|
||||
std::vector<std::string> pathParts;
|
||||
for( ; *originalPath; ++originalPath )
|
||||
{
|
||||
if( *originalPath == '/' )
|
||||
{
|
||||
if( subPath.length() > 0 )
|
||||
{
|
||||
pathParts.push_back( subPath );
|
||||
subPath = "";
|
||||
}
|
||||
|
||||
pathParts.push_back( "/" );
|
||||
}
|
||||
else
|
||||
subPath.append( 1, *originalPath );
|
||||
}
|
||||
|
||||
if( subPath.length() > 0 )
|
||||
pathParts.push_back( subPath );
|
||||
|
||||
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
|
||||
{
|
||||
if( pathParts[i] == ".." && i > 1 )
|
||||
{
|
||||
pathParts.erase( pathParts.begin() + i );
|
||||
pathParts.erase( pathParts.begin()+i-1 );
|
||||
pathParts.erase( pathParts.begin()+i-2 );
|
||||
i = 0;
|
||||
}
|
||||
else if( i > 0 && pathParts[i] == "." )
|
||||
{
|
||||
pathParts.erase( pathParts.begin()+i );
|
||||
i = 0;
|
||||
}
|
||||
else if( pathParts[i] == "/" && i > 0 && pathParts[i-1] == "/" )
|
||||
{
|
||||
pathParts.erase( pathParts.begin()+i-1 );
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
for( std::vector<std::string>::size_type i = 0; i < pathParts.size(); ++i )
|
||||
{
|
||||
oss << pathParts[i];
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool FileLister::AcceptFile( const std::string &filename )
|
||||
{
|
||||
std::string::size_type dotLocation = filename.find_last_of ( '.' );
|
||||
if ( dotLocation == std::string::npos )
|
||||
return false;
|
||||
|
||||
std::string extension = filename.substr( dotLocation );
|
||||
|
||||
if( extension == ".cpp" ||
|
||||
extension == ".cxx" ||
|
||||
extension == ".cc" ||
|
||||
extension == ".c" )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
////// This code is for __GNUC__ only /////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __GNUC__
|
||||
// gcc / cygwin..
|
||||
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << path;
|
||||
if( recursive )
|
||||
{
|
||||
if ( path.length() > 0 && path[path.length()-1] != '/' )
|
||||
oss << "/";
|
||||
|
||||
oss << "*";
|
||||
}
|
||||
|
||||
glob_t glob_results;
|
||||
glob( oss.str().c_str(), GLOB_MARK, 0, &glob_results);
|
||||
for ( unsigned int i = 0; i < glob_results.gl_pathc; i++ )
|
||||
{
|
||||
std::string filename = glob_results.gl_pathv[i];
|
||||
if ( filename == "." || filename == ".." || filename.length() == 0 )
|
||||
continue;
|
||||
|
||||
if ( filename[filename.length()-1] != '/' )
|
||||
{
|
||||
// File
|
||||
|
||||
// If recursive is not used, accept all files given by user
|
||||
if( !recursive || FileLister::AcceptFile( filename ) )
|
||||
filenames.push_back( filename );
|
||||
}
|
||||
else if( recursive )
|
||||
{
|
||||
// Directory
|
||||
FileLister::RecursiveAddFiles( filenames, filename, recursive );
|
||||
}
|
||||
}
|
||||
globfree(&glob_results);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
////// This code is for Borland C++ and Visual C++ ////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
|
||||
void FileLister::RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive )
|
||||
{
|
||||
std::ostringstream bdir, oss;
|
||||
oss << path;
|
||||
if (recursive)
|
||||
{
|
||||
bdir << path;
|
||||
if ( path.length() > 0 && path[path.length()-1] != '/' )
|
||||
{
|
||||
bdir << "/";
|
||||
oss << "/";
|
||||
}
|
||||
|
||||
oss << "*";
|
||||
}
|
||||
|
||||
WIN32_FIND_DATA ffd;
|
||||
HANDLE hFind = FindFirstFile(oss.str().c_str(), &ffd);
|
||||
if ( INVALID_HANDLE_VALUE == hFind )
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
std::ostringstream fname;
|
||||
fname << bdir.str().c_str() << ffd.cFileName;
|
||||
|
||||
if ( ffd.cFileName[0] == '.' || ffd.cFileName[0] == '\0' )
|
||||
continue;
|
||||
|
||||
if ( ( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
|
||||
{
|
||||
// File
|
||||
|
||||
// If recursive is not used, accept all files given by user
|
||||
if ( !recursive || FileLister::AcceptFile( ffd.cFileName ) )
|
||||
filenames.push_back( fname.str() );
|
||||
}
|
||||
else if ( recursive )
|
||||
{
|
||||
// Directory
|
||||
fname << "/";
|
||||
FileLister::RecursiveAddFiles( filenames, fname.str().c_str(), recursive );
|
||||
}
|
||||
}
|
||||
while (FindNextFile(hFind, &ffd) != FALSE);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
94
filelister.h
94
filelister.h
|
@ -1,47 +1,47 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef FileListerH
|
||||
#define FileListerH
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Check that the compiler are supported
|
||||
// This program should be compiled with either GCC/BORLAND/MSC to work..
|
||||
#ifndef __GNUC__
|
||||
#ifndef __BORLANDC__
|
||||
#ifndef _MSC_VER
|
||||
#error "C++Check must be compiled by either GCC/BORLAND/MSC to work fully.\n"
|
||||
#error "Please report that you couldn't compile c++check through the web page:\n"
|
||||
#error " https://sourceforge.net/projects/cppcheck/"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
class FileLister
|
||||
{
|
||||
public:
|
||||
static void RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive );
|
||||
static std::string simplifyPath( const char *originalPath );
|
||||
private:
|
||||
static bool AcceptFile( const std::string &filename );
|
||||
};
|
||||
|
||||
#endif // #ifndef FILELISTER_H
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef FileListerH
|
||||
#define FileListerH
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Check that the compiler are supported
|
||||
// This program should be compiled with either GCC/BORLAND/MSC to work..
|
||||
#ifndef __GNUC__
|
||||
#ifndef __BORLANDC__
|
||||
#ifndef _MSC_VER
|
||||
#error "C++Check must be compiled by either GCC/BORLAND/MSC to work fully.\n"
|
||||
#error "Please report that you couldn't compile c++check through the web page:\n"
|
||||
#error " https://sourceforge.net/projects/cppcheck/"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
class FileLister
|
||||
{
|
||||
public:
|
||||
static void RecursiveAddFiles( std::vector<std::string> &filenames, const std::string &path, bool recursive );
|
||||
static std::string simplifyPath( const char *originalPath );
|
||||
private:
|
||||
static bool AcceptFile( const std::string &filename );
|
||||
};
|
||||
|
||||
#endif // #ifndef FILELISTER_H
|
||||
|
|
66
main.cpp
66
main.cpp
|
@ -1,33 +1,33 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "cppcheckexecutor.h"
|
||||
|
||||
/**
|
||||
* Main function of cppcheck
|
||||
*
|
||||
* @param argc Passed to CppCheck::parseFromArgs()
|
||||
* @param argv Passed to CppCheck::parseFromArgs()
|
||||
* @return 0
|
||||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CppCheckExecutor exec;
|
||||
exec.check( argc, argv );
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "cppcheckexecutor.h"
|
||||
|
||||
/**
|
||||
* Main function of cppcheck
|
||||
*
|
||||
* @param argc Passed to CppCheck::parseFromArgs()
|
||||
* @param argv Passed to CppCheck::parseFromArgs()
|
||||
* @return 0
|
||||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CppCheckExecutor exec;
|
||||
exec.check( argc, argv );
|
||||
return 0;
|
||||
}
|
||||
|
|
750
preprocessor.cpp
750
preprocessor.cpp
|
@ -1,375 +1,375 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#include "preprocessor.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#include <ctype>
|
||||
#endif
|
||||
|
||||
|
||||
Preprocessor::Preprocessor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||
std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
||||
{
|
||||
// Get filedata from stream..
|
||||
bool ignoreSpace = true;
|
||||
|
||||
// For the error report
|
||||
int lineno = 1;
|
||||
|
||||
std::ostringstream code;
|
||||
for (char ch = (char)istr.get(); istr.good(); ch = (char)istr.get())
|
||||
{
|
||||
if ( ch < 0 )
|
||||
continue;
|
||||
|
||||
if ( ch == '\n' )
|
||||
++lineno;
|
||||
|
||||
// Replace assorted special chars with spaces..
|
||||
if ( (ch != '\n') && (isspace(ch) || iscntrl(ch)) )
|
||||
ch = ' ';
|
||||
|
||||
// Skip spaces after ' ' and after '#'
|
||||
if ( ch == ' ' && ignoreSpace )
|
||||
continue;
|
||||
ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/');
|
||||
|
||||
// Remove comments..
|
||||
if ( ch == '/' )
|
||||
{
|
||||
char chNext = (char)istr.get();
|
||||
|
||||
if ( chNext == '/' )
|
||||
{
|
||||
while (istr.good() && ch!='\n')
|
||||
ch = (char)istr.get();
|
||||
code << "\n";
|
||||
++lineno;
|
||||
}
|
||||
|
||||
else if ( chNext == '*' )
|
||||
{
|
||||
char chPrev = 0;
|
||||
while (istr.good() && (chPrev!='*' || ch!='/'))
|
||||
{
|
||||
chPrev = ch;
|
||||
ch = (char)istr.get();
|
||||
if (ch == '\n')
|
||||
{
|
||||
code << "\n";
|
||||
++lineno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( chNext == '\n' )
|
||||
++lineno;
|
||||
code << std::string(1,ch) << std::string(1,chNext);
|
||||
}
|
||||
}
|
||||
|
||||
// String constants..
|
||||
else if ( ch == '\"' )
|
||||
{
|
||||
code << "\"";
|
||||
do
|
||||
{
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
if ( ch == '\\' )
|
||||
{
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
|
||||
// Avoid exiting loop if string contains "-characters
|
||||
ch = 0;
|
||||
}
|
||||
} while ( istr.good() && ch != '\"' );
|
||||
}
|
||||
|
||||
// char constants..
|
||||
else if ( ch == '\'' )
|
||||
{
|
||||
code << "\'";
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
if ( ch == '\\' )
|
||||
{
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
}
|
||||
ch = (char)istr.get();
|
||||
code << "\'";
|
||||
}
|
||||
|
||||
// Just some code..
|
||||
else
|
||||
{
|
||||
code << std::string(1, ch);
|
||||
}
|
||||
}
|
||||
|
||||
return code.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the code for each configuration
|
||||
* \param istr The (file/string) stream to read from.
|
||||
* \param result The map that will get the results
|
||||
*/
|
||||
void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename)
|
||||
{
|
||||
std::string codestr( read(istr, filename) );
|
||||
|
||||
// Replace all tabs with spaces..
|
||||
std::string::size_type loc = 0;
|
||||
while ( (loc = codestr.find("\t", loc)) != std::string::npos )
|
||||
codestr[loc] = ' ';
|
||||
|
||||
// Remove all indentation..
|
||||
if ( !codestr.empty() && codestr[0] == ' ' )
|
||||
codestr.erase( 0, codestr.find_first_not_of(" ") );
|
||||
loc = 0;
|
||||
while ( (loc = codestr.find("\n ", loc)) != std::string::npos )
|
||||
codestr.erase( 1 + loc, 1 );
|
||||
|
||||
// Remove all trailing spaces..
|
||||
loc = 0;
|
||||
while ( (loc = codestr.find(" \n", loc)) != std::string::npos )
|
||||
{
|
||||
codestr.erase( loc, 1 );
|
||||
if ( loc > 0 )
|
||||
--loc;
|
||||
}
|
||||
|
||||
// Using the backslash at the end of a line..
|
||||
while ( (loc = codestr.rfind("\\\n")) != std::string::npos )
|
||||
{
|
||||
codestr.erase(loc, 2);
|
||||
if (loc > 0 && codestr[loc-1] != ' ')
|
||||
codestr.insert(loc, " ");
|
||||
if ( (loc = codestr.find("\n", loc)) != std::string::npos)
|
||||
codestr.insert( loc, "\n" );
|
||||
}
|
||||
|
||||
// Get all possible configurations..
|
||||
std::list<std::string> cfgs = getcfgs( codestr );
|
||||
|
||||
// Extract the code for each possible configuration..
|
||||
result.clear();
|
||||
for ( std::list<std::string>::const_iterator it = cfgs.begin(); it != cfgs.end(); ++it )
|
||||
{
|
||||
result[ *it ] = getcode( codestr, *it );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get the DEF in this line: "#ifdef DEF"
|
||||
std::string Preprocessor::getdef(std::string line, bool def)
|
||||
{
|
||||
// If def is true, the line must start with "#ifdef"
|
||||
if ( def && line.find("#ifdef ") != 0 && line.find("#if ") != 0 && line.find("#elif ") != 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// If def is false, the line must start with "#ifndef"
|
||||
if ( !def && line.find("#ifndef ") != 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Remove the "#ifdef" or "#ifndef"
|
||||
line.erase( 0, line.find(" ") );
|
||||
|
||||
// Remove all spaces.
|
||||
while ( line.find(" ") != std::string::npos )
|
||||
line.erase( line.find(" "), 1 );
|
||||
|
||||
// The remaining string is our result.
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::list<std::string> Preprocessor::getcfgs( const std::string &filedata )
|
||||
{
|
||||
std::list<std::string> ret;
|
||||
ret.push_back("");
|
||||
|
||||
std::list<std::string> deflist;
|
||||
|
||||
std::istringstream istr(filedata);
|
||||
std::string line;
|
||||
while ( getline(istr, line) )
|
||||
{
|
||||
std::string def = getdef(line, true) + getdef(line, false);
|
||||
if (!def.empty())
|
||||
{
|
||||
if ( ! deflist.empty() && line.find("#elif ") == 0 )
|
||||
deflist.pop_back();
|
||||
deflist.push_back(def);
|
||||
def = "";
|
||||
for ( std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)
|
||||
{
|
||||
if ( *it == "0" )
|
||||
break;
|
||||
if ( *it == "1" )
|
||||
continue;
|
||||
if ( ! def.empty() )
|
||||
def += ";";
|
||||
def += *it;
|
||||
}
|
||||
|
||||
if (std::find(ret.begin(), ret.end(), def) == ret.end())
|
||||
ret.push_back( def );
|
||||
}
|
||||
|
||||
if ( line.find("#else") == 0 && ! deflist.empty() )
|
||||
{
|
||||
std::string def( ( deflist.back() == "1" ) ? "0" : "1" );
|
||||
deflist.pop_back();
|
||||
deflist.push_back( def );
|
||||
}
|
||||
|
||||
if ( line.find("#endif") == 0 && ! deflist.empty() )
|
||||
deflist.pop_back();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Preprocessor::match_cfg_def( std::string cfg, const std::string &def )
|
||||
{
|
||||
if ( def == "0" )
|
||||
return false;
|
||||
|
||||
if ( def == "1" )
|
||||
return true;
|
||||
|
||||
if ( cfg.empty() )
|
||||
return false;
|
||||
|
||||
while ( ! cfg.empty() )
|
||||
{
|
||||
if ( cfg.find(";") == std::string::npos )
|
||||
return bool(cfg == def);
|
||||
std::string _cfg = cfg.substr( 0, cfg.find(";") );
|
||||
if ( _cfg == def )
|
||||
return true;
|
||||
cfg.erase( 0, cfg.find(";") + 1 );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string Preprocessor::getcode(const std::string &filedata, std::string cfg)
|
||||
{
|
||||
std::ostringstream ret;
|
||||
|
||||
bool match = true;
|
||||
std::list<bool> matching_ifdef;
|
||||
std::list<bool> matched_ifdef;
|
||||
|
||||
std::istringstream istr(filedata);
|
||||
std::string line;
|
||||
while ( getline(istr, line) )
|
||||
{
|
||||
std::string def = getdef( line, true );
|
||||
std::string ndef = getdef( line, false );
|
||||
|
||||
if ( line.find("#elif ") == 0 )
|
||||
{
|
||||
if ( matched_ifdef.back() )
|
||||
{
|
||||
matching_ifdef.back() = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( match_cfg_def(cfg, def) )
|
||||
{
|
||||
matching_ifdef.back() = true;
|
||||
matched_ifdef.back() = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ( ! def.empty() )
|
||||
{
|
||||
matching_ifdef.push_back( match_cfg_def(cfg, def) );
|
||||
matched_ifdef.push_back( matching_ifdef.back() );
|
||||
}
|
||||
|
||||
else if ( ! ndef.empty() )
|
||||
{
|
||||
matching_ifdef.push_back( ! match_cfg_def(cfg, ndef) );
|
||||
matched_ifdef.push_back( matching_ifdef.back() );
|
||||
}
|
||||
|
||||
else if ( line == "#else" )
|
||||
{
|
||||
if ( ! matched_ifdef.empty() )
|
||||
matching_ifdef.back() = ! matched_ifdef.back();
|
||||
}
|
||||
|
||||
else if ( line == "#endif" )
|
||||
{
|
||||
if ( ! matched_ifdef.empty() )
|
||||
matched_ifdef.pop_back();
|
||||
if ( ! matching_ifdef.empty() )
|
||||
matching_ifdef.pop_back();
|
||||
}
|
||||
|
||||
if ( !line.empty() && line[0] == '#' )
|
||||
{
|
||||
match = true;
|
||||
for ( std::list<bool>::const_iterator it = matching_ifdef.begin(); it != matching_ifdef.end(); ++it )
|
||||
match &= bool(*it);
|
||||
}
|
||||
if ( ! match )
|
||||
line = "";
|
||||
|
||||
if ( line.find("#if") == 0 ||
|
||||
line.find("#else") == 0 ||
|
||||
line.find("#elif") == 0 ||
|
||||
line.find("#endif") == 0 )
|
||||
line = "";
|
||||
|
||||
ret << line << "\n";
|
||||
}
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#include "preprocessor.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#include <ctype>
|
||||
#endif
|
||||
|
||||
|
||||
Preprocessor::Preprocessor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||
std::string Preprocessor::read(std::istream &istr, const std::string &filename)
|
||||
{
|
||||
// Get filedata from stream..
|
||||
bool ignoreSpace = true;
|
||||
|
||||
// For the error report
|
||||
int lineno = 1;
|
||||
|
||||
std::ostringstream code;
|
||||
for (char ch = (char)istr.get(); istr.good(); ch = (char)istr.get())
|
||||
{
|
||||
if ( ch < 0 )
|
||||
continue;
|
||||
|
||||
if ( ch == '\n' )
|
||||
++lineno;
|
||||
|
||||
// Replace assorted special chars with spaces..
|
||||
if ( (ch != '\n') && (isspace(ch) || iscntrl(ch)) )
|
||||
ch = ' ';
|
||||
|
||||
// Skip spaces after ' ' and after '#'
|
||||
if ( ch == ' ' && ignoreSpace )
|
||||
continue;
|
||||
ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/');
|
||||
|
||||
// Remove comments..
|
||||
if ( ch == '/' )
|
||||
{
|
||||
char chNext = (char)istr.get();
|
||||
|
||||
if ( chNext == '/' )
|
||||
{
|
||||
while (istr.good() && ch!='\n')
|
||||
ch = (char)istr.get();
|
||||
code << "\n";
|
||||
++lineno;
|
||||
}
|
||||
|
||||
else if ( chNext == '*' )
|
||||
{
|
||||
char chPrev = 0;
|
||||
while (istr.good() && (chPrev!='*' || ch!='/'))
|
||||
{
|
||||
chPrev = ch;
|
||||
ch = (char)istr.get();
|
||||
if (ch == '\n')
|
||||
{
|
||||
code << "\n";
|
||||
++lineno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( chNext == '\n' )
|
||||
++lineno;
|
||||
code << std::string(1,ch) << std::string(1,chNext);
|
||||
}
|
||||
}
|
||||
|
||||
// String constants..
|
||||
else if ( ch == '\"' )
|
||||
{
|
||||
code << "\"";
|
||||
do
|
||||
{
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
if ( ch == '\\' )
|
||||
{
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
|
||||
// Avoid exiting loop if string contains "-characters
|
||||
ch = 0;
|
||||
}
|
||||
} while ( istr.good() && ch != '\"' );
|
||||
}
|
||||
|
||||
// char constants..
|
||||
else if ( ch == '\'' )
|
||||
{
|
||||
code << "\'";
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
if ( ch == '\\' )
|
||||
{
|
||||
ch = (char)istr.get();
|
||||
code << std::string(1,ch);
|
||||
}
|
||||
ch = (char)istr.get();
|
||||
code << "\'";
|
||||
}
|
||||
|
||||
// Just some code..
|
||||
else
|
||||
{
|
||||
code << std::string(1, ch);
|
||||
}
|
||||
}
|
||||
|
||||
return code.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the code for each configuration
|
||||
* \param istr The (file/string) stream to read from.
|
||||
* \param result The map that will get the results
|
||||
*/
|
||||
void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename)
|
||||
{
|
||||
std::string codestr( read(istr, filename) );
|
||||
|
||||
// Replace all tabs with spaces..
|
||||
std::string::size_type loc = 0;
|
||||
while ( (loc = codestr.find("\t", loc)) != std::string::npos )
|
||||
codestr[loc] = ' ';
|
||||
|
||||
// Remove all indentation..
|
||||
if ( !codestr.empty() && codestr[0] == ' ' )
|
||||
codestr.erase( 0, codestr.find_first_not_of(" ") );
|
||||
loc = 0;
|
||||
while ( (loc = codestr.find("\n ", loc)) != std::string::npos )
|
||||
codestr.erase( 1 + loc, 1 );
|
||||
|
||||
// Remove all trailing spaces..
|
||||
loc = 0;
|
||||
while ( (loc = codestr.find(" \n", loc)) != std::string::npos )
|
||||
{
|
||||
codestr.erase( loc, 1 );
|
||||
if ( loc > 0 )
|
||||
--loc;
|
||||
}
|
||||
|
||||
// Using the backslash at the end of a line..
|
||||
while ( (loc = codestr.rfind("\\\n")) != std::string::npos )
|
||||
{
|
||||
codestr.erase(loc, 2);
|
||||
if (loc > 0 && codestr[loc-1] != ' ')
|
||||
codestr.insert(loc, " ");
|
||||
if ( (loc = codestr.find("\n", loc)) != std::string::npos)
|
||||
codestr.insert( loc, "\n" );
|
||||
}
|
||||
|
||||
// Get all possible configurations..
|
||||
std::list<std::string> cfgs = getcfgs( codestr );
|
||||
|
||||
// Extract the code for each possible configuration..
|
||||
result.clear();
|
||||
for ( std::list<std::string>::const_iterator it = cfgs.begin(); it != cfgs.end(); ++it )
|
||||
{
|
||||
result[ *it ] = getcode( codestr, *it );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get the DEF in this line: "#ifdef DEF"
|
||||
std::string Preprocessor::getdef(std::string line, bool def)
|
||||
{
|
||||
// If def is true, the line must start with "#ifdef"
|
||||
if ( def && line.find("#ifdef ") != 0 && line.find("#if ") != 0 && line.find("#elif ") != 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// If def is false, the line must start with "#ifndef"
|
||||
if ( !def && line.find("#ifndef ") != 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Remove the "#ifdef" or "#ifndef"
|
||||
line.erase( 0, line.find(" ") );
|
||||
|
||||
// Remove all spaces.
|
||||
while ( line.find(" ") != std::string::npos )
|
||||
line.erase( line.find(" "), 1 );
|
||||
|
||||
// The remaining string is our result.
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::list<std::string> Preprocessor::getcfgs( const std::string &filedata )
|
||||
{
|
||||
std::list<std::string> ret;
|
||||
ret.push_back("");
|
||||
|
||||
std::list<std::string> deflist;
|
||||
|
||||
std::istringstream istr(filedata);
|
||||
std::string line;
|
||||
while ( getline(istr, line) )
|
||||
{
|
||||
std::string def = getdef(line, true) + getdef(line, false);
|
||||
if (!def.empty())
|
||||
{
|
||||
if ( ! deflist.empty() && line.find("#elif ") == 0 )
|
||||
deflist.pop_back();
|
||||
deflist.push_back(def);
|
||||
def = "";
|
||||
for ( std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)
|
||||
{
|
||||
if ( *it == "0" )
|
||||
break;
|
||||
if ( *it == "1" )
|
||||
continue;
|
||||
if ( ! def.empty() )
|
||||
def += ";";
|
||||
def += *it;
|
||||
}
|
||||
|
||||
if (std::find(ret.begin(), ret.end(), def) == ret.end())
|
||||
ret.push_back( def );
|
||||
}
|
||||
|
||||
if ( line.find("#else") == 0 && ! deflist.empty() )
|
||||
{
|
||||
std::string def( ( deflist.back() == "1" ) ? "0" : "1" );
|
||||
deflist.pop_back();
|
||||
deflist.push_back( def );
|
||||
}
|
||||
|
||||
if ( line.find("#endif") == 0 && ! deflist.empty() )
|
||||
deflist.pop_back();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Preprocessor::match_cfg_def( std::string cfg, const std::string &def )
|
||||
{
|
||||
if ( def == "0" )
|
||||
return false;
|
||||
|
||||
if ( def == "1" )
|
||||
return true;
|
||||
|
||||
if ( cfg.empty() )
|
||||
return false;
|
||||
|
||||
while ( ! cfg.empty() )
|
||||
{
|
||||
if ( cfg.find(";") == std::string::npos )
|
||||
return bool(cfg == def);
|
||||
std::string _cfg = cfg.substr( 0, cfg.find(";") );
|
||||
if ( _cfg == def )
|
||||
return true;
|
||||
cfg.erase( 0, cfg.find(";") + 1 );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string Preprocessor::getcode(const std::string &filedata, std::string cfg)
|
||||
{
|
||||
std::ostringstream ret;
|
||||
|
||||
bool match = true;
|
||||
std::list<bool> matching_ifdef;
|
||||
std::list<bool> matched_ifdef;
|
||||
|
||||
std::istringstream istr(filedata);
|
||||
std::string line;
|
||||
while ( getline(istr, line) )
|
||||
{
|
||||
std::string def = getdef( line, true );
|
||||
std::string ndef = getdef( line, false );
|
||||
|
||||
if ( line.find("#elif ") == 0 )
|
||||
{
|
||||
if ( matched_ifdef.back() )
|
||||
{
|
||||
matching_ifdef.back() = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( match_cfg_def(cfg, def) )
|
||||
{
|
||||
matching_ifdef.back() = true;
|
||||
matched_ifdef.back() = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ( ! def.empty() )
|
||||
{
|
||||
matching_ifdef.push_back( match_cfg_def(cfg, def) );
|
||||
matched_ifdef.push_back( matching_ifdef.back() );
|
||||
}
|
||||
|
||||
else if ( ! ndef.empty() )
|
||||
{
|
||||
matching_ifdef.push_back( ! match_cfg_def(cfg, ndef) );
|
||||
matched_ifdef.push_back( matching_ifdef.back() );
|
||||
}
|
||||
|
||||
else if ( line == "#else" )
|
||||
{
|
||||
if ( ! matched_ifdef.empty() )
|
||||
matching_ifdef.back() = ! matched_ifdef.back();
|
||||
}
|
||||
|
||||
else if ( line == "#endif" )
|
||||
{
|
||||
if ( ! matched_ifdef.empty() )
|
||||
matched_ifdef.pop_back();
|
||||
if ( ! matching_ifdef.empty() )
|
||||
matching_ifdef.pop_back();
|
||||
}
|
||||
|
||||
if ( !line.empty() && line[0] == '#' )
|
||||
{
|
||||
match = true;
|
||||
for ( std::list<bool>::const_iterator it = matching_ifdef.begin(); it != matching_ifdef.end(); ++it )
|
||||
match &= bool(*it);
|
||||
}
|
||||
if ( ! match )
|
||||
line = "";
|
||||
|
||||
if ( line.find("#if") == 0 ||
|
||||
line.find("#else") == 0 ||
|
||||
line.find("#elif") == 0 ||
|
||||
line.find("#endif") == 0 )
|
||||
line = "";
|
||||
|
||||
ret << line << "\n";
|
||||
}
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
|
|
116
preprocessor.h
116
preprocessor.h
|
@ -1,58 +1,58 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef preprocessorH
|
||||
#define preprocessorH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <map>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
|
||||
class Preprocessor
|
||||
{
|
||||
public:
|
||||
Preprocessor();
|
||||
|
||||
void preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename);
|
||||
|
||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||
std::string read(std::istream &istr, const std::string &filename);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get preprocessed code for a given configuration
|
||||
*/
|
||||
std::string getcode(const std::string &filedata, std::string cfg);
|
||||
|
||||
/**
|
||||
* Get all possible configurations. By looking at the ifdefs and ifndefs in filedata
|
||||
*/
|
||||
std::list<std::string> getcfgs( const std::string &filedata );
|
||||
|
||||
std::string getdef(std::string line, bool def);
|
||||
|
||||
bool match_cfg_def( std::string cfg, const std::string &def );
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef preprocessorH
|
||||
#define preprocessorH
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <map>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
|
||||
class Preprocessor
|
||||
{
|
||||
public:
|
||||
Preprocessor();
|
||||
|
||||
void preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename);
|
||||
|
||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||
std::string read(std::istream &istr, const std::string &filename);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get preprocessed code for a given configuration
|
||||
*/
|
||||
std::string getcode(const std::string &filedata, std::string cfg);
|
||||
|
||||
/**
|
||||
* Get all possible configurations. By looking at the ifdefs and ifndefs in filedata
|
||||
*/
|
||||
std::list<std::string> getcfgs( const std::string &filedata );
|
||||
|
||||
std::string getdef(std::string line, bool def);
|
||||
|
||||
bool match_cfg_def( std::string cfg, const std::string &def );
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
|
|
68
settings.cpp
68
settings.cpp
|
@ -1,34 +1,34 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
_debug = false;
|
||||
_showAll = false;
|
||||
_checkCodingStyle = false;
|
||||
_errorsOnly = false;
|
||||
_checkFunctionUsage = false;
|
||||
_verbose = false;
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
|
||||
}
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
_debug = false;
|
||||
_showAll = false;
|
||||
_checkCodingStyle = false;
|
||||
_errorsOnly = false;
|
||||
_checkFunctionUsage = false;
|
||||
_verbose = false;
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
82
settings.h
82
settings.h
|
@ -1,41 +1,41 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
/**
|
||||
* This is just a container for general settings so that we don't need
|
||||
* to pass individual values to functions or constructors now or in the
|
||||
* future when we might have even more detailed settings.
|
||||
*/
|
||||
class Settings
|
||||
{
|
||||
public:
|
||||
Settings();
|
||||
virtual ~Settings();
|
||||
|
||||
bool _debug;
|
||||
bool _showAll;
|
||||
bool _checkCodingStyle;
|
||||
bool _errorsOnly;
|
||||
bool _checkFunctionUsage;
|
||||
bool _verbose;
|
||||
};
|
||||
|
||||
#endif // SETTINGS_H
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
/**
|
||||
* This is just a container for general settings so that we don't need
|
||||
* to pass individual values to functions or constructors now or in the
|
||||
* future when we might have even more detailed settings.
|
||||
*/
|
||||
class Settings
|
||||
{
|
||||
public:
|
||||
Settings();
|
||||
virtual ~Settings();
|
||||
|
||||
bool _debug;
|
||||
bool _showAll;
|
||||
bool _checkCodingStyle;
|
||||
bool _errorsOnly;
|
||||
bool _checkFunctionUsage;
|
||||
bool _verbose;
|
||||
};
|
||||
|
||||
#endif // SETTINGS_H
|
||||
|
|
|
@ -1,397 +1,397 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkbufferoverrun.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestBufferOverrun : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestBufferOverrun() : TestFixture("TestBufferOverrun")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Assign variable ids
|
||||
tokenizer.setVarId();
|
||||
|
||||
// Fill function list
|
||||
tokenizer.fillFunctionList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for buffer overruns..
|
||||
Settings settings;
|
||||
settings._showAll = true;
|
||||
CheckBufferOverrunClass checkBufferOverrun( &tokenizer, settings, this );
|
||||
checkBufferOverrun.CheckBufferOverrun();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( noerr1 );
|
||||
TEST_CASE( noerr2 );
|
||||
TEST_CASE( noerr3 );
|
||||
TEST_CASE( noerr4 );
|
||||
|
||||
TEST_CASE( array_index_1 );
|
||||
TEST_CASE( array_index_2 );
|
||||
TEST_CASE( array_index_3 );
|
||||
TEST_CASE( array_index_4 );
|
||||
TEST_CASE( array_index_5 );
|
||||
TEST_CASE( array_index_6 );
|
||||
TEST_CASE( array_index_7 );
|
||||
TEST_CASE( array_index_8 );
|
||||
TEST_CASE( array_index_9 );
|
||||
TEST_CASE( array_index_10 );
|
||||
TEST_CASE( array_index_11 );
|
||||
TEST_CASE( array_index_12 );
|
||||
|
||||
TEST_CASE( buffer_overrun_1 );
|
||||
TEST_CASE( buffer_overrun_2 );
|
||||
|
||||
TEST_CASE( varid1 );
|
||||
TEST_CASE( varid2 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void noerr1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" if (ab)\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" }\n"
|
||||
" if (ab)\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void noerr2()
|
||||
{
|
||||
check( "void f1(char *str)\n"
|
||||
"{\n"
|
||||
" strcpy(buf,str);\n"
|
||||
"}\n"
|
||||
"void f2(char *str)\n"
|
||||
"{\n"
|
||||
" strcat(buf,str);\n"
|
||||
"}\n"
|
||||
"void f3(char *str)\n"
|
||||
"{\n"
|
||||
" sprintf(buf,\"%s\",str);\n"
|
||||
"}\n"
|
||||
"void f4(const char str[])\n"
|
||||
"{\n"
|
||||
" strcpy(buf, str);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void noerr3()
|
||||
{
|
||||
check( "static void f()\n"
|
||||
"{\n"
|
||||
" char data[1];\n"
|
||||
" return abc.data[1];\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void noerr4()
|
||||
{
|
||||
// The memory isn't read or written and therefore there is no error.
|
||||
check( "static void f()\n"
|
||||
"{\n"
|
||||
" char data[100];\n"
|
||||
" const char *p = &data[100];\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_1()
|
||||
{
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" char str[0x10];\n"
|
||||
" str[15] = 0;\n"
|
||||
" str[16] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_2()
|
||||
{
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" char *str = new char[0x10];\n"
|
||||
" str[15] = 0;\n"
|
||||
" str[16] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_3()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int val[50];\n"
|
||||
" for (i = 0; i < 100; i++)\n"
|
||||
" sum += val[i];\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Buffer overrun\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_4()
|
||||
{
|
||||
check( "const int SIZE = 10;\n"
|
||||
"void f()\n"
|
||||
"{\n"
|
||||
" int i[SIZE];\n"
|
||||
" i[SIZE] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_5()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int i[10];\n"
|
||||
" i[ sizeof(i) - 1 ] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_6()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" struct ABC abc;\n"
|
||||
" abc.str[10] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:9]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_7()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f(ABC *abc)\n"
|
||||
"{\n"
|
||||
" abc->str[10] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:8]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_8()
|
||||
{
|
||||
check( "const int SIZE = 10;\n"
|
||||
"\n"
|
||||
"struct ABC\n"
|
||||
"{\n"
|
||||
" char str[SIZE];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" struct ABC abc;\n"
|
||||
" abc.str[SIZE] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:11]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
void array_index_9()
|
||||
{
|
||||
check( "static void memclr( char *data )\n"
|
||||
"{\n"
|
||||
" data[10] = 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" char str[5];\n"
|
||||
" memclr( str ); // ERROR\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:9] -> [test.cpp:3]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_10()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void memclr( char *data )\n"
|
||||
"{\n"
|
||||
" data[10] = 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static void f(ABC *abc)\n"
|
||||
"{\n"
|
||||
" memclr(abc->str);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:13] -> [test.cpp:8]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_11()
|
||||
{
|
||||
check( "class ABC\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" ABC();\n"
|
||||
" char *str[10];\n"
|
||||
" struct ABC *next;"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" for ( ABC *abc = abc1; abc; abc = abc->next() )\n"
|
||||
" {\n"
|
||||
" abc->str[10] = 0;\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:12]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_12()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" char str[10];\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{\n"
|
||||
" str[10] = 0;\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:10]: Array index out of bounds\n"), err );
|
||||
}
|
||||
|
||||
|
||||
void buffer_overrun_1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" char str[3];\n"
|
||||
" strcpy(str, \"abc\");\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Buffer overrun\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void buffer_overrun_2()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[5];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f(ABC *abc)\n"
|
||||
"{\n"
|
||||
" strcpy( abc->str, \"abcdef\" );\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:8]: Buffer overrun\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void varid1()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
" if (str[0])\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" str[30] = 0;\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void varid2()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
" if (str[0])\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" memset(str,0,50);\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestBufferOverrun )
|
||||
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkbufferoverrun.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestBufferOverrun : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestBufferOverrun() : TestFixture("TestBufferOverrun")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Assign variable ids
|
||||
tokenizer.setVarId();
|
||||
|
||||
// Fill function list
|
||||
tokenizer.fillFunctionList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for buffer overruns..
|
||||
Settings settings;
|
||||
settings._showAll = true;
|
||||
CheckBufferOverrunClass checkBufferOverrun( &tokenizer, settings, this );
|
||||
checkBufferOverrun.CheckBufferOverrun();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( noerr1 );
|
||||
TEST_CASE( noerr2 );
|
||||
TEST_CASE( noerr3 );
|
||||
TEST_CASE( noerr4 );
|
||||
|
||||
TEST_CASE( array_index_1 );
|
||||
TEST_CASE( array_index_2 );
|
||||
TEST_CASE( array_index_3 );
|
||||
TEST_CASE( array_index_4 );
|
||||
TEST_CASE( array_index_5 );
|
||||
TEST_CASE( array_index_6 );
|
||||
TEST_CASE( array_index_7 );
|
||||
TEST_CASE( array_index_8 );
|
||||
TEST_CASE( array_index_9 );
|
||||
TEST_CASE( array_index_10 );
|
||||
TEST_CASE( array_index_11 );
|
||||
TEST_CASE( array_index_12 );
|
||||
|
||||
TEST_CASE( buffer_overrun_1 );
|
||||
TEST_CASE( buffer_overrun_2 );
|
||||
|
||||
TEST_CASE( varid1 );
|
||||
TEST_CASE( varid2 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void noerr1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" if (ab)\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" }\n"
|
||||
" if (ab)\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void noerr2()
|
||||
{
|
||||
check( "void f1(char *str)\n"
|
||||
"{\n"
|
||||
" strcpy(buf,str);\n"
|
||||
"}\n"
|
||||
"void f2(char *str)\n"
|
||||
"{\n"
|
||||
" strcat(buf,str);\n"
|
||||
"}\n"
|
||||
"void f3(char *str)\n"
|
||||
"{\n"
|
||||
" sprintf(buf,\"%s\",str);\n"
|
||||
"}\n"
|
||||
"void f4(const char str[])\n"
|
||||
"{\n"
|
||||
" strcpy(buf, str);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void noerr3()
|
||||
{
|
||||
check( "static void f()\n"
|
||||
"{\n"
|
||||
" char data[1];\n"
|
||||
" return abc.data[1];\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void noerr4()
|
||||
{
|
||||
// The memory isn't read or written and therefore there is no error.
|
||||
check( "static void f()\n"
|
||||
"{\n"
|
||||
" char data[100];\n"
|
||||
" const char *p = &data[100];\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_1()
|
||||
{
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" char str[0x10];\n"
|
||||
" str[15] = 0;\n"
|
||||
" str[16] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_2()
|
||||
{
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" char *str = new char[0x10];\n"
|
||||
" str[15] = 0;\n"
|
||||
" str[16] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_3()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int val[50];\n"
|
||||
" for (i = 0; i < 100; i++)\n"
|
||||
" sum += val[i];\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Buffer overrun\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_4()
|
||||
{
|
||||
check( "const int SIZE = 10;\n"
|
||||
"void f()\n"
|
||||
"{\n"
|
||||
" int i[SIZE];\n"
|
||||
" i[SIZE] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_5()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int i[10];\n"
|
||||
" i[ sizeof(i) - 1 ] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_6()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" struct ABC abc;\n"
|
||||
" abc.str[10] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:9]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_7()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f(ABC *abc)\n"
|
||||
"{\n"
|
||||
" abc->str[10] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:8]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_8()
|
||||
{
|
||||
check( "const int SIZE = 10;\n"
|
||||
"\n"
|
||||
"struct ABC\n"
|
||||
"{\n"
|
||||
" char str[SIZE];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" struct ABC abc;\n"
|
||||
" abc.str[SIZE] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:11]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
void array_index_9()
|
||||
{
|
||||
check( "static void memclr( char *data )\n"
|
||||
"{\n"
|
||||
" data[10] = 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" char str[5];\n"
|
||||
" memclr( str ); // ERROR\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:9] -> [test.cpp:3]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_10()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void memclr( char *data )\n"
|
||||
"{\n"
|
||||
" data[10] = 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static void f(ABC *abc)\n"
|
||||
"{\n"
|
||||
" memclr(abc->str);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:13] -> [test.cpp:8]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_11()
|
||||
{
|
||||
check( "class ABC\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" ABC();\n"
|
||||
" char *str[10];\n"
|
||||
" struct ABC *next;"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" for ( ABC *abc = abc1; abc; abc = abc->next() )\n"
|
||||
" {\n"
|
||||
" abc->str[10] = 0;\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:12]: Array index out of bounds\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void array_index_12()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" char str[10];\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{\n"
|
||||
" str[10] = 0;\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:10]: Array index out of bounds\n"), err );
|
||||
}
|
||||
|
||||
|
||||
void buffer_overrun_1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" char str[3];\n"
|
||||
" strcpy(str, \"abc\");\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Buffer overrun\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void buffer_overrun_2()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" char str[5];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static void f(ABC *abc)\n"
|
||||
"{\n"
|
||||
" strcpy( abc->str, \"abcdef\" );\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:8]: Buffer overrun\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void varid1()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
" if (str[0])\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" str[30] = 0;\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void varid2()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char str[10];\n"
|
||||
" if (str[0])\n"
|
||||
" {\n"
|
||||
" char str[50];\n"
|
||||
" memset(str,0,50);\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestBufferOverrun )
|
||||
|
||||
|
||||
|
|
210
testcharvar.cpp
210
testcharvar.cpp
|
@ -1,105 +1,105 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
#include "testsuite.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestCharVar : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestCharVar() : TestFixture("TestCharVar")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( array_index );
|
||||
TEST_CASE( bitop1 );
|
||||
TEST_CASE( bitop2 );
|
||||
}
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check char variable usage..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckCharVariable();
|
||||
}
|
||||
|
||||
void array_index()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" unsigned char ch = 0x80;\n"
|
||||
" buf[ch] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char ch = 0x80;\n"
|
||||
" buf[ch] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable as array index\n"), errout.str() );
|
||||
|
||||
check( "void foo(char ch)\n"
|
||||
"{\n"
|
||||
" buf[ch] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Warning - using char variable as array index\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void bitop1()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char ch;\n"
|
||||
" result = a | ch;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable in bit operation\n"), errout.str() );
|
||||
}
|
||||
|
||||
void bitop2()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char ch;\n"
|
||||
" func(&ch);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestCharVar )
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
#include "testsuite.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestCharVar : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestCharVar() : TestFixture("TestCharVar")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( array_index );
|
||||
TEST_CASE( bitop1 );
|
||||
TEST_CASE( bitop2 );
|
||||
}
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check char variable usage..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckCharVariable();
|
||||
}
|
||||
|
||||
void array_index()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" unsigned char ch = 0x80;\n"
|
||||
" buf[ch] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char ch = 0x80;\n"
|
||||
" buf[ch] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable as array index\n"), errout.str() );
|
||||
|
||||
check( "void foo(char ch)\n"
|
||||
"{\n"
|
||||
" buf[ch] = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Warning - using char variable as array index\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void bitop1()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char ch;\n"
|
||||
" result = a | ch;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Warning - using char variable in bit operation\n"), errout.str() );
|
||||
}
|
||||
|
||||
void bitop2()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" char ch;\n"
|
||||
" func(&ch);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestCharVar )
|
||||
|
||||
|
|
230
testclass.cpp
230
testclass.cpp
|
@ -1,115 +1,115 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkclass.h"
|
||||
#include "testsuite.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestClass : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestClass() : TestFixture("TestClass")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( virtualDestructor1 ); // Base class not found => no error
|
||||
TEST_CASE( virtualDestructor2 ); // Base class doesn't have a destructor
|
||||
TEST_CASE( virtualDestructor3 ); // Base class has a destructor, but it's not virtual
|
||||
TEST_CASE( virtualDestructor4 ); // Derived class doesn't have a destructor => no error
|
||||
}
|
||||
|
||||
// Check that base classes have virtual destructors
|
||||
void checkVirtualDestructor(const char code[])
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error log
|
||||
errout.str("");
|
||||
|
||||
// Check..
|
||||
Settings settings;
|
||||
CheckClass checkClass( &tokenizer, settings, this );
|
||||
checkClass.virtualDestructor();
|
||||
}
|
||||
|
||||
|
||||
void virtualDestructor1()
|
||||
{
|
||||
// Base class not found
|
||||
|
||||
checkVirtualDestructor("class Derived : public Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Derived : Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void virtualDestructor2()
|
||||
{
|
||||
// Base class doesn't have a destructor
|
||||
|
||||
checkVirtualDestructor("class Base { };\n"
|
||||
"class Derived : public Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string("[test.cpp:1]: Base class Base doesn't have a virtual destructor\n"), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Base { };\n"
|
||||
"class Derived : Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void virtualDestructor3()
|
||||
{
|
||||
// Base class has a destructor, but it's not virtual
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : public Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : private Fred, public Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
|
||||
}
|
||||
|
||||
void virtualDestructor4()
|
||||
{
|
||||
// Derived class doesn't have a destructor => no error
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : public Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : private Fred, public Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestClass )
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkclass.h"
|
||||
#include "testsuite.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestClass : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestClass() : TestFixture("TestClass")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( virtualDestructor1 ); // Base class not found => no error
|
||||
TEST_CASE( virtualDestructor2 ); // Base class doesn't have a destructor
|
||||
TEST_CASE( virtualDestructor3 ); // Base class has a destructor, but it's not virtual
|
||||
TEST_CASE( virtualDestructor4 ); // Derived class doesn't have a destructor => no error
|
||||
}
|
||||
|
||||
// Check that base classes have virtual destructors
|
||||
void checkVirtualDestructor(const char code[])
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error log
|
||||
errout.str("");
|
||||
|
||||
// Check..
|
||||
Settings settings;
|
||||
CheckClass checkClass( &tokenizer, settings, this );
|
||||
checkClass.virtualDestructor();
|
||||
}
|
||||
|
||||
|
||||
void virtualDestructor1()
|
||||
{
|
||||
// Base class not found
|
||||
|
||||
checkVirtualDestructor("class Derived : public Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Derived : Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void virtualDestructor2()
|
||||
{
|
||||
// Base class doesn't have a destructor
|
||||
|
||||
checkVirtualDestructor("class Base { };\n"
|
||||
"class Derived : public Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string("[test.cpp:1]: Base class Base doesn't have a virtual destructor\n"), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Base { };\n"
|
||||
"class Derived : Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void virtualDestructor3()
|
||||
{
|
||||
// Base class has a destructor, but it's not virtual
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : public Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : private Fred, public Base { public: ~Derived() { (void)11; } };");
|
||||
ASSERT_EQUALS( std::string("[test.cpp:1]: The destructor for the base class Base is not virtual\n"), errout.str() );
|
||||
}
|
||||
|
||||
void virtualDestructor4()
|
||||
{
|
||||
// Derived class doesn't have a destructor => no error
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : public Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
|
||||
checkVirtualDestructor("class Base { public: ~Base(); };\n"
|
||||
"class Derived : private Fred, public Base { };");
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestClass )
|
||||
|
|
|
@ -1,326 +1,326 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkclass.h"
|
||||
#include "testsuite.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestConstructors : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestConstructors() : TestFixture("TestConstructors")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check class constructors..
|
||||
Settings settings;
|
||||
settings._checkCodingStyle = true;
|
||||
CheckClass checkClass( &tokenizer, settings, this );
|
||||
checkClass.CheckConstructors();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( simple1 );
|
||||
TEST_CASE( simple2 );
|
||||
TEST_CASE( simple3 );
|
||||
TEST_CASE( simple4 );
|
||||
|
||||
TEST_CASE( initvar_with_this ); // BUG 2190300
|
||||
TEST_CASE( initvar_if ); // BUG 2190290
|
||||
TEST_CASE( initvar_operator_eq1 ); // BUG 2190376
|
||||
TEST_CASE( initvar_operator_eq2 ); // BUG 2190376
|
||||
TEST_CASE( initvar_operator_eq3 );
|
||||
TEST_CASE( initvar_same_classname ); // BUG 2208157
|
||||
TEST_CASE( initvar_chained_assign ); // BUG 2270433
|
||||
TEST_CASE( initvar_2constructors ); // BUG 2270353
|
||||
|
||||
TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor
|
||||
|
||||
TEST_CASE( initvar_destructor ); // No variables need to be initialized in a destructor
|
||||
}
|
||||
|
||||
|
||||
void simple1()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
std::string actual( errout.str() );
|
||||
std::string expected( "[test.cpp:1] The class 'Fred' has no constructor\n" );
|
||||
ASSERT_EQUALS( expected, actual );
|
||||
}
|
||||
|
||||
|
||||
void simple2()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred() { }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void simple3()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
" int i;\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:7] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void simple4()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
" Fred(int _i);\n"
|
||||
" int i;\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }\n"
|
||||
"Fred::Fred(int _i)\n"
|
||||
"{\n"
|
||||
" i = _i;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:8] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void initvar_with_this()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred()\n"
|
||||
" { this->i = 0; }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_if()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred()\n"
|
||||
" {\n"
|
||||
" if (true)\n"
|
||||
" i = 0;\n"
|
||||
" else\n"
|
||||
" i = 1;\n"
|
||||
" }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_operator_eq1()
|
||||
{
|
||||
// Bug 2190376 - False positive, Uninitialized member variable with operator=
|
||||
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" int i;\n"
|
||||
"\n"
|
||||
"public:\n"
|
||||
" Fred()\n"
|
||||
" { i = 0; }\n"
|
||||
"\n"
|
||||
" Fred(const Fred &fred)\n"
|
||||
" { *this = fred; }\n"
|
||||
"\n"
|
||||
" const Fred & operator=(const Fred &fred)\n"
|
||||
" { i = fred.i; return *this; }\n"
|
||||
"};\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
|
||||
void initvar_operator_eq2()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred() { i = 0; }\n"
|
||||
" void operator=() { }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_operator_eq3()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred() { Init(); }\n"
|
||||
" void operator=() { Init(); }\n"
|
||||
"private:\n"
|
||||
" Init() { i = 0; }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_same_classname()
|
||||
{
|
||||
// Bug 2208157 - False positive: Uninitialized variable, same class name
|
||||
|
||||
check( "void func1()\n"
|
||||
"{\n"
|
||||
" class Fred\n"
|
||||
" {\n"
|
||||
" int a;\n"
|
||||
" Fred() { a = 0; }\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void func2()\n"
|
||||
"{\n"
|
||||
" class Fred\n"
|
||||
" {\n"
|
||||
" int b;\n"
|
||||
" Fred() { b = 0; }\n"
|
||||
" };\n"
|
||||
"}\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
void initvar_chained_assign()
|
||||
{
|
||||
// Bug 2270433 - Uninitialized variable false positive on chained assigns
|
||||
|
||||
check( "class c\n"
|
||||
"{\n"
|
||||
" c();\n"
|
||||
"\n"
|
||||
" int m_iMyInt1;\n"
|
||||
" int m_iMyInt2;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"c::c()\n"
|
||||
"{\n"
|
||||
" m_iMyInt1 = m_iMyInt2 = 0;\n"
|
||||
"}\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
|
||||
void initvar_2constructors()
|
||||
{
|
||||
check( "class c\n"
|
||||
"{\n"
|
||||
" c();\n"
|
||||
" c(bool b);"
|
||||
"\n"
|
||||
" void InitInt();\n"
|
||||
"\n"
|
||||
" int m_iMyInt;\n"
|
||||
" int m_bMyBool;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"c::c()\n"
|
||||
"{\n"
|
||||
" m_bMyBool = false;\n"
|
||||
" InitInt();"
|
||||
"}\n"
|
||||
"\n"
|
||||
"c::c(bool b)\n"
|
||||
"{\n"
|
||||
" m_bMyBool = b;\n"
|
||||
" InitInt();\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void c::InitInt()\n"
|
||||
"{\n"
|
||||
" m_iMyInt = 0;\n"
|
||||
"}\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
|
||||
void initvar_private_constructor()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" int var;\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_destructor()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" int var;\n"
|
||||
"public:\n"
|
||||
" Fred() : var(0) {}\n"
|
||||
" ~Fred() {}\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestConstructors )
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkclass.h"
|
||||
#include "testsuite.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestConstructors : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestConstructors() : TestFixture("TestConstructors")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check class constructors..
|
||||
Settings settings;
|
||||
settings._checkCodingStyle = true;
|
||||
CheckClass checkClass( &tokenizer, settings, this );
|
||||
checkClass.CheckConstructors();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( simple1 );
|
||||
TEST_CASE( simple2 );
|
||||
TEST_CASE( simple3 );
|
||||
TEST_CASE( simple4 );
|
||||
|
||||
TEST_CASE( initvar_with_this ); // BUG 2190300
|
||||
TEST_CASE( initvar_if ); // BUG 2190290
|
||||
TEST_CASE( initvar_operator_eq1 ); // BUG 2190376
|
||||
TEST_CASE( initvar_operator_eq2 ); // BUG 2190376
|
||||
TEST_CASE( initvar_operator_eq3 );
|
||||
TEST_CASE( initvar_same_classname ); // BUG 2208157
|
||||
TEST_CASE( initvar_chained_assign ); // BUG 2270433
|
||||
TEST_CASE( initvar_2constructors ); // BUG 2270353
|
||||
|
||||
TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor
|
||||
|
||||
TEST_CASE( initvar_destructor ); // No variables need to be initialized in a destructor
|
||||
}
|
||||
|
||||
|
||||
void simple1()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
std::string actual( errout.str() );
|
||||
std::string expected( "[test.cpp:1] The class 'Fred' has no constructor\n" );
|
||||
ASSERT_EQUALS( expected, actual );
|
||||
}
|
||||
|
||||
|
||||
void simple2()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred() { }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void simple3()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
" int i;\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:7] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void simple4()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
" Fred(int _i);\n"
|
||||
" int i;\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }\n"
|
||||
"Fred::Fred(int _i)\n"
|
||||
"{\n"
|
||||
" i = _i;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:8] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
void initvar_with_this()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred()\n"
|
||||
" { this->i = 0; }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_if()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred()\n"
|
||||
" {\n"
|
||||
" if (true)\n"
|
||||
" i = 0;\n"
|
||||
" else\n"
|
||||
" i = 1;\n"
|
||||
" }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_operator_eq1()
|
||||
{
|
||||
// Bug 2190376 - False positive, Uninitialized member variable with operator=
|
||||
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" int i;\n"
|
||||
"\n"
|
||||
"public:\n"
|
||||
" Fred()\n"
|
||||
" { i = 0; }\n"
|
||||
"\n"
|
||||
" Fred(const Fred &fred)\n"
|
||||
" { *this = fred; }\n"
|
||||
"\n"
|
||||
" const Fred & operator=(const Fred &fred)\n"
|
||||
" { i = fred.i; return *this; }\n"
|
||||
"};\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
|
||||
void initvar_operator_eq2()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred() { i = 0; }\n"
|
||||
" void operator=() { }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5] Uninitialized member variable 'Fred::i'\n"), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_operator_eq3()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" Fred() { Init(); }\n"
|
||||
" void operator=() { Init(); }\n"
|
||||
"private:\n"
|
||||
" Init() { i = 0; }\n"
|
||||
" int i;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_same_classname()
|
||||
{
|
||||
// Bug 2208157 - False positive: Uninitialized variable, same class name
|
||||
|
||||
check( "void func1()\n"
|
||||
"{\n"
|
||||
" class Fred\n"
|
||||
" {\n"
|
||||
" int a;\n"
|
||||
" Fred() { a = 0; }\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void func2()\n"
|
||||
"{\n"
|
||||
" class Fred\n"
|
||||
" {\n"
|
||||
" int b;\n"
|
||||
" Fred() { b = 0; }\n"
|
||||
" };\n"
|
||||
"}\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
void initvar_chained_assign()
|
||||
{
|
||||
// Bug 2270433 - Uninitialized variable false positive on chained assigns
|
||||
|
||||
check( "class c\n"
|
||||
"{\n"
|
||||
" c();\n"
|
||||
"\n"
|
||||
" int m_iMyInt1;\n"
|
||||
" int m_iMyInt2;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"c::c()\n"
|
||||
"{\n"
|
||||
" m_iMyInt1 = m_iMyInt2 = 0;\n"
|
||||
"}\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
|
||||
void initvar_2constructors()
|
||||
{
|
||||
check( "class c\n"
|
||||
"{\n"
|
||||
" c();\n"
|
||||
" c(bool b);"
|
||||
"\n"
|
||||
" void InitInt();\n"
|
||||
"\n"
|
||||
" int m_iMyInt;\n"
|
||||
" int m_bMyBool;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"c::c()\n"
|
||||
"{\n"
|
||||
" m_bMyBool = false;\n"
|
||||
" InitInt();"
|
||||
"}\n"
|
||||
"\n"
|
||||
"c::c(bool b)\n"
|
||||
"{\n"
|
||||
" m_bMyBool = b;\n"
|
||||
" InitInt();\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void c::InitInt()\n"
|
||||
"{\n"
|
||||
" m_iMyInt = 0;\n"
|
||||
"}\n" );
|
||||
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), err );
|
||||
}
|
||||
|
||||
|
||||
void initvar_private_constructor()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" int var;\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void initvar_destructor()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" int var;\n"
|
||||
"public:\n"
|
||||
" Fred() : var(0) {}\n"
|
||||
" ~Fred() {}\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestConstructors )
|
||||
|
|
300
testdivision.cpp
300
testdivision.cpp
|
@ -1,150 +1,150 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
// Check for dangerous division..
|
||||
// such as "svar / uvar". Treating "svar" as unsigned data is not good
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestDivision : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestDivision() : TestFixture("TestDivision")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unsigned divisions..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckUnsignedDivision();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( division1 );
|
||||
TEST_CASE( division2 );
|
||||
TEST_CASE( division3 );
|
||||
TEST_CASE( division4 );
|
||||
TEST_CASE( division5 );
|
||||
TEST_CASE( division6 );
|
||||
TEST_CASE( division7 );
|
||||
}
|
||||
|
||||
void division1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int ivar = -2;\n"
|
||||
" unsigned int uvar = 2;\n"
|
||||
" return ivar / uvar;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division2()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int ivar = -2;\n"
|
||||
" unsigned int uvar = 2;\n"
|
||||
" return uvar / ivar;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division3()
|
||||
{
|
||||
check( "typedef int s32;\n"
|
||||
"typedef unsigned int u32;\n"
|
||||
"void f()\n"
|
||||
"{\n"
|
||||
" s32 ivar = -2;\n"
|
||||
" u32 uvar = 2;\n"
|
||||
" return uvar / ivar;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:7]: Warning: Division with signed and unsigned operators\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division4()
|
||||
{
|
||||
check( "void f1()\n"
|
||||
"{\n"
|
||||
" int i1;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void f2(unsigned int i1)\n"
|
||||
"{\n"
|
||||
" unsigned int i2;\n"
|
||||
" result = i2 / i1;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void division5()
|
||||
{
|
||||
check( "#define USER_HASH (16)\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int val = 32;\n"
|
||||
" val = val / USER_HASH;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void division6()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int val = 32;\n"
|
||||
" int i = val / -2;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division7()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int val = 32;\n"
|
||||
" int i = -96 / val;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestDivision )
|
||||
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
// Check for dangerous division..
|
||||
// such as "svar / uvar". Treating "svar" as unsigned data is not good
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestDivision : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestDivision() : TestFixture("TestDivision")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unsigned divisions..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckUnsignedDivision();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( division1 );
|
||||
TEST_CASE( division2 );
|
||||
TEST_CASE( division3 );
|
||||
TEST_CASE( division4 );
|
||||
TEST_CASE( division5 );
|
||||
TEST_CASE( division6 );
|
||||
TEST_CASE( division7 );
|
||||
}
|
||||
|
||||
void division1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int ivar = -2;\n"
|
||||
" unsigned int uvar = 2;\n"
|
||||
" return ivar / uvar;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division2()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" int ivar = -2;\n"
|
||||
" unsigned int uvar = 2;\n"
|
||||
" return uvar / ivar;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:5]: Warning: Division with signed and unsigned operators\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division3()
|
||||
{
|
||||
check( "typedef int s32;\n"
|
||||
"typedef unsigned int u32;\n"
|
||||
"void f()\n"
|
||||
"{\n"
|
||||
" s32 ivar = -2;\n"
|
||||
" u32 uvar = 2;\n"
|
||||
" return uvar / ivar;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:7]: Warning: Division with signed and unsigned operators\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division4()
|
||||
{
|
||||
check( "void f1()\n"
|
||||
"{\n"
|
||||
" int i1;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void f2(unsigned int i1)\n"
|
||||
"{\n"
|
||||
" unsigned int i2;\n"
|
||||
" result = i2 / i1;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void division5()
|
||||
{
|
||||
check( "#define USER_HASH (16)\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int val = 32;\n"
|
||||
" val = val / USER_HASH;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void division6()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int val = 32;\n"
|
||||
" int i = val / -2;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
|
||||
}
|
||||
|
||||
void division7()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int val = 32;\n"
|
||||
" int i = -96 / val;\n"
|
||||
);
|
||||
ASSERT_EQUALS( std::string("[test.cpp:4]: Unsigned division. The result will be wrong.\n"), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestDivision )
|
||||
|
||||
|
||||
|
|
|
@ -1,53 +1,53 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "testsuite.h"
|
||||
#include "filelister.h"
|
||||
|
||||
class TestFileLister : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestFileLister() : TestFixture("TestFileLister")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( simplify_path );
|
||||
}
|
||||
|
||||
void simplify_path()
|
||||
{
|
||||
ASSERT_EQUALS( std::string( "index.h" ), FileLister::simplifyPath( "index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/path/" ), FileLister::simplifyPath( "/path/" ) );
|
||||
ASSERT_EQUALS( std::string( "/" ), FileLister::simplifyPath( "/" ) );
|
||||
ASSERT_EQUALS( std::string( "./index.h" ), FileLister::simplifyPath( "./index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "../index.h" ), FileLister::simplifyPath( "../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other/../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other///././../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "../path/index.h" ), FileLister::simplifyPath( "../path/other/../index.h" ) );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestFileLister )
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "testsuite.h"
|
||||
#include "filelister.h"
|
||||
|
||||
class TestFileLister : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestFileLister() : TestFixture("TestFileLister")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( simplify_path );
|
||||
}
|
||||
|
||||
void simplify_path()
|
||||
{
|
||||
ASSERT_EQUALS( std::string( "index.h" ), FileLister::simplifyPath( "index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/path/" ), FileLister::simplifyPath( "/path/" ) );
|
||||
ASSERT_EQUALS( std::string( "/" ), FileLister::simplifyPath( "/" ) );
|
||||
ASSERT_EQUALS( std::string( "./index.h" ), FileLister::simplifyPath( "./index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "../index.h" ), FileLister::simplifyPath( "../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other/../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "/index.h" ), FileLister::simplifyPath( "/path/../other///././../index.h" ) );
|
||||
ASSERT_EQUALS( std::string( "../path/index.h" ), FileLister::simplifyPath( "../path/other/../index.h" ) );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestFileLister )
|
||||
|
|
|
@ -1,105 +1,105 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "testsuite.h"
|
||||
#include "checkfunctionusage.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestFunctionUsage : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestFunctionUsage() : TestFixture("TestFunctionUsage")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( incondition );
|
||||
TEST_CASE( return1 );
|
||||
TEST_CASE( callback1 );
|
||||
TEST_CASE( else1 );
|
||||
}
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused functions..
|
||||
CheckFunctionUsage checkFunctionUsage(this);
|
||||
checkFunctionUsage.parseTokens( tokenizer );
|
||||
checkFunctionUsage.check();
|
||||
}
|
||||
|
||||
void incondition()
|
||||
{
|
||||
check( "int f1()\n"
|
||||
"{\n"
|
||||
" if (f1())\n"
|
||||
" { }\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void return1()
|
||||
{
|
||||
check( "int f1()\n"
|
||||
"{\n"
|
||||
" return f1();\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void callback1()
|
||||
{
|
||||
check( "void f1()\n"
|
||||
"{\n"
|
||||
" void (*f)() = cond ? f1 : NULL;\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void else1()
|
||||
{
|
||||
check( "void f1()\n"
|
||||
"{\n"
|
||||
" if (cond) ;\n"
|
||||
" else f1();\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestFunctionUsage )
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "testsuite.h"
|
||||
#include "checkfunctionusage.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestFunctionUsage : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestFunctionUsage() : TestFixture("TestFunctionUsage")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( incondition );
|
||||
TEST_CASE( return1 );
|
||||
TEST_CASE( callback1 );
|
||||
TEST_CASE( else1 );
|
||||
}
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused functions..
|
||||
CheckFunctionUsage checkFunctionUsage(this);
|
||||
checkFunctionUsage.parseTokens( tokenizer );
|
||||
checkFunctionUsage.check();
|
||||
}
|
||||
|
||||
void incondition()
|
||||
{
|
||||
check( "int f1()\n"
|
||||
"{\n"
|
||||
" if (f1())\n"
|
||||
" { }\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void return1()
|
||||
{
|
||||
check( "int f1()\n"
|
||||
"{\n"
|
||||
" return f1();\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void callback1()
|
||||
{
|
||||
check( "void f1()\n"
|
||||
"{\n"
|
||||
" void (*f)() = cond ? f1 : NULL;\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void else1()
|
||||
{
|
||||
check( "void f1()\n"
|
||||
"{\n"
|
||||
" if (cond) ;\n"
|
||||
" else f1();\n"
|
||||
"}\n" );
|
||||
std::string err( errout.str() );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestFunctionUsage )
|
||||
|
||||
|
|
|
@ -1,91 +1,91 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Check for unused variables..
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "testsuite.h"
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestIncompleteStatement : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestIncompleteStatement() : TestFixture("TestIncompleteStatement")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused variables..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckIncompleteStatement();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( test1 );
|
||||
TEST_CASE( test2 );
|
||||
}
|
||||
|
||||
void test1()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" const char def[] =\n"
|
||||
"#ifdef ABC\n"
|
||||
" \"abc\";\n"
|
||||
"#else\n"
|
||||
" \"not abc\";\n"
|
||||
"#endif\n"
|
||||
"}\n" );
|
||||
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
// Todo: remove the ';' before the string
|
||||
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" ;\"abc\";\n"
|
||||
"}\n" );
|
||||
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant code: Found a statement that begins with string constant\n"), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestIncompleteStatement )
|
||||
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Check for unused variables..
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "testsuite.h"
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestIncompleteStatement : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestIncompleteStatement() : TestFixture("TestIncompleteStatement")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused variables..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckIncompleteStatement();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( test1 );
|
||||
TEST_CASE( test2 );
|
||||
}
|
||||
|
||||
void test1()
|
||||
{
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" const char def[] =\n"
|
||||
"#ifdef ABC\n"
|
||||
" \"abc\";\n"
|
||||
"#else\n"
|
||||
" \"not abc\";\n"
|
||||
"#endif\n"
|
||||
"}\n" );
|
||||
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
// Todo: remove the ';' before the string
|
||||
|
||||
check( "void foo()\n"
|
||||
"{\n"
|
||||
" ;\"abc\";\n"
|
||||
"}\n" );
|
||||
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant code: Found a statement that begins with string constant\n"), errout.str() );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestIncompleteStatement )
|
||||
|
||||
|
||||
|
|
2452
testmemleak.cpp
2452
testmemleak.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,446 +1,446 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
// The preprocessor that c++check uses is a bit special. Instead of generating
|
||||
// the code for a known configuration, it generates the code for each configuration.
|
||||
|
||||
|
||||
#include "testsuite.h"
|
||||
#include "preprocessor.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class TestPreprocessor : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestPreprocessor() : TestFixture("TestPreprocessor")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
// Just read the code into a string. Perform simple cleanup of the code
|
||||
TEST_CASE(readCode);
|
||||
|
||||
// The bug that started the whole work with the new preprocessor
|
||||
TEST_CASE( Bug2190219 );
|
||||
|
||||
TEST_CASE( test1 );
|
||||
TEST_CASE( test2 );
|
||||
TEST_CASE( test3 );
|
||||
TEST_CASE( test4 );
|
||||
TEST_CASE( test5 );
|
||||
|
||||
TEST_CASE( comments1 );
|
||||
|
||||
TEST_CASE( if0 );
|
||||
TEST_CASE( if1 );
|
||||
|
||||
TEST_CASE( elif );
|
||||
|
||||
TEST_CASE( include1 );
|
||||
|
||||
TEST_CASE( if_cond1 );
|
||||
|
||||
TEST_CASE( multiline );
|
||||
}
|
||||
|
||||
|
||||
void readCode()
|
||||
{
|
||||
const char code[] = " \t a //\n"
|
||||
" #aa\t /* remove this */\tb \r\n";
|
||||
Preprocessor p;
|
||||
std::istringstream istr(code);
|
||||
std::string codestr( p.read(istr,"") );
|
||||
ASSERT_EQUALS( "a \n#aa b \n", codestr );
|
||||
}
|
||||
|
||||
|
||||
bool cmpmaps(const std::map<std::string, std::string> &m1, const std::map<std::string, std::string> &m2)
|
||||
{
|
||||
// Begin by checking the sizes
|
||||
if ( m1.size() != m2.size() )
|
||||
return false;
|
||||
|
||||
// Check each item in the maps..
|
||||
for ( std::map<std::string,std::string>::const_iterator it1 = m1.begin(); it1 != m1.end(); ++it1 )
|
||||
{
|
||||
std::string s1 = it1->first;
|
||||
std::map<std::string,std::string>::const_iterator it2 = m2.find(s1);
|
||||
if ( it2 == m2.end() )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
std::string s1 = it1->second;
|
||||
std::string s2 = it2->second;
|
||||
if ( s1 != s2 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// No diffs were found
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Bug2190219()
|
||||
{
|
||||
const char filedata[] = "int main()\n"
|
||||
"{\n"
|
||||
"#ifdef __cplusplus\n"
|
||||
" int* flags = new int[10];\n"
|
||||
"#else\n"
|
||||
" int* flags = (int*)malloc((10)*sizeof(int));\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
"#ifdef __cplusplus\n"
|
||||
" delete [] flags;\n"
|
||||
"#else\n"
|
||||
" free(flags);\n"
|
||||
"#endif\n"
|
||||
"}\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "int main()\n"
|
||||
"{\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"int* flags = (int*)malloc((10)*sizeof(int));\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"free(flags);\n"
|
||||
"\n"
|
||||
"}\n";
|
||||
|
||||
expected["__cplusplus"] = "int main()\n"
|
||||
"{\n"
|
||||
"\n"
|
||||
"int* flags = new int[10];\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"delete [] flags;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"}\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
void test1()
|
||||
{
|
||||
const char filedata[] = "#ifdef WIN32 \n"
|
||||
" abcdef\n"
|
||||
"#else \n"
|
||||
" qwerty\n"
|
||||
"#endif \n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\nqwerty\n\n";
|
||||
expected["WIN32"] = "\nabcdef\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
const char filedata[] = "# ifndef WIN32\n"
|
||||
" \" # ifdef WIN32\" // a comment\n"
|
||||
" # else \n"
|
||||
" qwerty\n"
|
||||
" # endif \n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected["WIN32"] = "\n\n\nqwerty\n\n";
|
||||
expected[""] = "\n\" # ifdef WIN32\"\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test3()
|
||||
{
|
||||
const char filedata[] = "#ifdef ABC\n"
|
||||
"a\n"
|
||||
"#ifdef DEF\n"
|
||||
"b\n"
|
||||
"#endif\n"
|
||||
"c\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n\n\n\n";
|
||||
expected["ABC"] = "\na\n\n\n\nc\n\n";
|
||||
expected["ABC;DEF"] = "\na\n\nb\n\nc\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test4()
|
||||
{
|
||||
const char filedata[] = "#ifdef ABC\n"
|
||||
"A\n"
|
||||
"#endif\t\n"
|
||||
"#ifdef ABC\n"
|
||||
"A\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n\n\n";
|
||||
expected["ABC"] = "\nA\n\n\nA\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test5()
|
||||
{
|
||||
const char filedata[] = "#ifdef ABC\n"
|
||||
"A\n"
|
||||
"#else\n"
|
||||
"B\n"
|
||||
"#ifdef DEF\n"
|
||||
"C\n"
|
||||
"#endif\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\nB\n\n\n\n\n";
|
||||
expected["ABC"] = "\nA\n\n\n\n\n\n\n";
|
||||
expected["DEF"] = "\n\n\nB\n\nC\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void comments1()
|
||||
{
|
||||
const char filedata[] = "/*\n"
|
||||
"#ifdef WIN32\n"
|
||||
"#endif\n"
|
||||
"*/\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void if0()
|
||||
{
|
||||
const char filedata[] = " # if /* comment */ 0 // comment\n"
|
||||
"#ifdef WIN32\n"
|
||||
"#endif\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void if1()
|
||||
{
|
||||
const char filedata[] = " # if /* comment */ 1 // comment\n"
|
||||
"ABC\n"
|
||||
" # endif \n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\nABC\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
void elif()
|
||||
{
|
||||
const char filedata[] = "#if DEF1\n"
|
||||
"ABC\n"
|
||||
"#elif DEF2\n"
|
||||
"DEF\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n\n";
|
||||
expected["DEF1"] = "\nABC\n\n\n\n";
|
||||
expected["DEF2"] = "\n\n\nDEF\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void include1()
|
||||
{
|
||||
const char filedata[] = " # include \"abcd.h\" // abcd\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "#include \"abcd.h\"\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void if_cond1()
|
||||
{
|
||||
const char filedata[] = "#if LIBVER>100\n"
|
||||
" A\n"
|
||||
"#else\n"
|
||||
" B\n"
|
||||
"#endif\n";
|
||||
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\nB\n\n";
|
||||
expected["LIBVER>100"] = "\nA\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
void multiline()
|
||||
{
|
||||
const char filedata[] = "#define str \"abc\" \\ \n"
|
||||
" \"def\" \\ \n"
|
||||
" \"ghi\" \n";
|
||||
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "#define str \"abc\" \"def\" \"ghi\"\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestPreprocessor )
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
// The preprocessor that c++check uses is a bit special. Instead of generating
|
||||
// the code for a known configuration, it generates the code for each configuration.
|
||||
|
||||
|
||||
#include "testsuite.h"
|
||||
#include "preprocessor.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class TestPreprocessor : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestPreprocessor() : TestFixture("TestPreprocessor")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
// Just read the code into a string. Perform simple cleanup of the code
|
||||
TEST_CASE(readCode);
|
||||
|
||||
// The bug that started the whole work with the new preprocessor
|
||||
TEST_CASE( Bug2190219 );
|
||||
|
||||
TEST_CASE( test1 );
|
||||
TEST_CASE( test2 );
|
||||
TEST_CASE( test3 );
|
||||
TEST_CASE( test4 );
|
||||
TEST_CASE( test5 );
|
||||
|
||||
TEST_CASE( comments1 );
|
||||
|
||||
TEST_CASE( if0 );
|
||||
TEST_CASE( if1 );
|
||||
|
||||
TEST_CASE( elif );
|
||||
|
||||
TEST_CASE( include1 );
|
||||
|
||||
TEST_CASE( if_cond1 );
|
||||
|
||||
TEST_CASE( multiline );
|
||||
}
|
||||
|
||||
|
||||
void readCode()
|
||||
{
|
||||
const char code[] = " \t a //\n"
|
||||
" #aa\t /* remove this */\tb \r\n";
|
||||
Preprocessor p;
|
||||
std::istringstream istr(code);
|
||||
std::string codestr( p.read(istr,"") );
|
||||
ASSERT_EQUALS( "a \n#aa b \n", codestr );
|
||||
}
|
||||
|
||||
|
||||
bool cmpmaps(const std::map<std::string, std::string> &m1, const std::map<std::string, std::string> &m2)
|
||||
{
|
||||
// Begin by checking the sizes
|
||||
if ( m1.size() != m2.size() )
|
||||
return false;
|
||||
|
||||
// Check each item in the maps..
|
||||
for ( std::map<std::string,std::string>::const_iterator it1 = m1.begin(); it1 != m1.end(); ++it1 )
|
||||
{
|
||||
std::string s1 = it1->first;
|
||||
std::map<std::string,std::string>::const_iterator it2 = m2.find(s1);
|
||||
if ( it2 == m2.end() )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
std::string s1 = it1->second;
|
||||
std::string s2 = it2->second;
|
||||
if ( s1 != s2 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// No diffs were found
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Bug2190219()
|
||||
{
|
||||
const char filedata[] = "int main()\n"
|
||||
"{\n"
|
||||
"#ifdef __cplusplus\n"
|
||||
" int* flags = new int[10];\n"
|
||||
"#else\n"
|
||||
" int* flags = (int*)malloc((10)*sizeof(int));\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
"#ifdef __cplusplus\n"
|
||||
" delete [] flags;\n"
|
||||
"#else\n"
|
||||
" free(flags);\n"
|
||||
"#endif\n"
|
||||
"}\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "int main()\n"
|
||||
"{\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"int* flags = (int*)malloc((10)*sizeof(int));\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"free(flags);\n"
|
||||
"\n"
|
||||
"}\n";
|
||||
|
||||
expected["__cplusplus"] = "int main()\n"
|
||||
"{\n"
|
||||
"\n"
|
||||
"int* flags = new int[10];\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"delete [] flags;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"}\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
void test1()
|
||||
{
|
||||
const char filedata[] = "#ifdef WIN32 \n"
|
||||
" abcdef\n"
|
||||
"#else \n"
|
||||
" qwerty\n"
|
||||
"#endif \n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\nqwerty\n\n";
|
||||
expected["WIN32"] = "\nabcdef\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
const char filedata[] = "# ifndef WIN32\n"
|
||||
" \" # ifdef WIN32\" // a comment\n"
|
||||
" # else \n"
|
||||
" qwerty\n"
|
||||
" # endif \n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected["WIN32"] = "\n\n\nqwerty\n\n";
|
||||
expected[""] = "\n\" # ifdef WIN32\"\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test3()
|
||||
{
|
||||
const char filedata[] = "#ifdef ABC\n"
|
||||
"a\n"
|
||||
"#ifdef DEF\n"
|
||||
"b\n"
|
||||
"#endif\n"
|
||||
"c\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n\n\n\n";
|
||||
expected["ABC"] = "\na\n\n\n\nc\n\n";
|
||||
expected["ABC;DEF"] = "\na\n\nb\n\nc\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test4()
|
||||
{
|
||||
const char filedata[] = "#ifdef ABC\n"
|
||||
"A\n"
|
||||
"#endif\t\n"
|
||||
"#ifdef ABC\n"
|
||||
"A\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n\n\n";
|
||||
expected["ABC"] = "\nA\n\n\nA\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void test5()
|
||||
{
|
||||
const char filedata[] = "#ifdef ABC\n"
|
||||
"A\n"
|
||||
"#else\n"
|
||||
"B\n"
|
||||
"#ifdef DEF\n"
|
||||
"C\n"
|
||||
"#endif\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\nB\n\n\n\n\n";
|
||||
expected["ABC"] = "\nA\n\n\n\n\n\n\n";
|
||||
expected["DEF"] = "\n\n\nB\n\nC\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void comments1()
|
||||
{
|
||||
const char filedata[] = "/*\n"
|
||||
"#ifdef WIN32\n"
|
||||
"#endif\n"
|
||||
"*/\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void if0()
|
||||
{
|
||||
const char filedata[] = " # if /* comment */ 0 // comment\n"
|
||||
"#ifdef WIN32\n"
|
||||
"#endif\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
void if1()
|
||||
{
|
||||
const char filedata[] = " # if /* comment */ 1 // comment\n"
|
||||
"ABC\n"
|
||||
" # endif \n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\nABC\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
void elif()
|
||||
{
|
||||
const char filedata[] = "#if DEF1\n"
|
||||
"ABC\n"
|
||||
"#elif DEF2\n"
|
||||
"DEF\n"
|
||||
"#endif\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\n\n\n";
|
||||
expected["DEF1"] = "\nABC\n\n\n\n";
|
||||
expected["DEF2"] = "\n\n\nDEF\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void include1()
|
||||
{
|
||||
const char filedata[] = " # include \"abcd.h\" // abcd\n";
|
||||
|
||||
// Expected result..
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "#include \"abcd.h\"\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void if_cond1()
|
||||
{
|
||||
const char filedata[] = "#if LIBVER>100\n"
|
||||
" A\n"
|
||||
"#else\n"
|
||||
" B\n"
|
||||
"#endif\n";
|
||||
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "\n\n\nB\n\n";
|
||||
expected["LIBVER>100"] = "\nA\n\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
|
||||
void multiline()
|
||||
{
|
||||
const char filedata[] = "#define str \"abc\" \\ \n"
|
||||
" \"def\" \\ \n"
|
||||
" \"ghi\" \n";
|
||||
|
||||
std::map<std::string, std::string> expected;
|
||||
expected[""] = "#define str \"abc\" \"def\" \"ghi\"\n\n\n";
|
||||
|
||||
// Preprocess => actual result..
|
||||
std::istringstream istr(filedata);
|
||||
std::map<std::string, std::string> actual;
|
||||
Preprocessor preprocessor;
|
||||
preprocessor.preprocess( istr, actual, "" );
|
||||
|
||||
// Compare results..
|
||||
ASSERT_EQUALS( true, cmpmaps(actual, expected));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestPreprocessor )
|
||||
|
|
|
@ -1,87 +1,87 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
// Check for dangerous division..
|
||||
// such as "svar / uvar". Treating "svar" as unsigned data is not good
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestRedundantIf : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestRedundantIf() : TestFixture("TestRedundantIf")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for redundant condition..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.redundantCondition2();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( remove1 );
|
||||
TEST_CASE( remove2 );
|
||||
}
|
||||
|
||||
void remove1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
// Check for dangerous division..
|
||||
// such as "svar / uvar". Treating "svar" as unsigned data is not good
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestRedundantIf : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestRedundantIf() : TestFixture("TestRedundantIf")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for redundant condition..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.redundantCondition2();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( remove1 );
|
||||
TEST_CASE( remove2 );
|
||||
}
|
||||
|
||||
void remove1()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" if (haystack.find(needle) != haystack.end())\n"
|
||||
" haystack.remove(needle);"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
|
||||
}
|
||||
|
||||
void remove2()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" haystack.remove(needle);"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
|
||||
}
|
||||
|
||||
void remove2()
|
||||
{
|
||||
check( "void f()\n"
|
||||
"{\n"
|
||||
" if (haystack.find(needle) != haystack.end())\n"
|
||||
" {\n"
|
||||
" haystack.remove(needle);\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestRedundantIf )
|
||||
|
||||
|
||||
" {\n"
|
||||
" haystack.remove(needle);\n"
|
||||
" }\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:3]: Redundant condition found. The remove function in the STL will not do anything if element doesn't exist\n"), errout.str() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestRedundantIf )
|
||||
|
||||
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "testsuite.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
TestFixture::runTests( (argc==2) ? argv[1] : NULL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "testsuite.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
TestFixture::runTests( (argc==2) ? argv[1] : NULL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,73 +1,73 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "testsuite.h"
|
||||
#include "tokenize.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestSimplifyTokens : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestSimplifyTokens() : TestFixture("TestSimplifyTokens")
|
||||
{ }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( cast0 );
|
||||
TEST_CASE( sizeof1 );
|
||||
}
|
||||
|
||||
std::string tok(const char code[])
|
||||
{
|
||||
std::istringstream istr(code);
|
||||
Tokenizer tokenizer;
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
std::string ret;
|
||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||
{
|
||||
ret += tok->str() + " ";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cast0()
|
||||
{
|
||||
const char code1[] = " if ( p == (char *)0 ) ";
|
||||
const char code2[] = " if ( p == 0 ) ";
|
||||
ASSERT_EQUALS( tok(code1), tok(code2) );
|
||||
}
|
||||
|
||||
void sizeof1()
|
||||
{
|
||||
const char code1[] = " struct ABC *abc = malloc(sizeof(*abc)); ";
|
||||
const char code2[] = " struct ABC *abc = malloc(100); ";
|
||||
ASSERT_EQUALS( tok(code1), tok(code2) );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestSimplifyTokens )
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "testsuite.h"
|
||||
#include "tokenize.h"
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestSimplifyTokens : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestSimplifyTokens() : TestFixture("TestSimplifyTokens")
|
||||
{ }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( cast0 );
|
||||
TEST_CASE( sizeof1 );
|
||||
}
|
||||
|
||||
std::string tok(const char code[])
|
||||
{
|
||||
std::istringstream istr(code);
|
||||
Tokenizer tokenizer;
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
std::string ret;
|
||||
for ( const TOKEN *tok = tokenizer.tokens(); tok; tok = tok->next() )
|
||||
{
|
||||
ret += tok->str() + " ";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cast0()
|
||||
{
|
||||
const char code1[] = " if ( p == (char *)0 ) ";
|
||||
const char code2[] = " if ( p == 0 ) ";
|
||||
ASSERT_EQUALS( tok(code1), tok(code2) );
|
||||
}
|
||||
|
||||
void sizeof1()
|
||||
{
|
||||
const char code1[] = " struct ABC *abc = malloc(sizeof(*abc)); ";
|
||||
const char code2[] = " struct ABC *abc = malloc(100); ";
|
||||
ASSERT_EQUALS( tok(code1), tok(code2) );
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestSimplifyTokens )
|
||||
|
|
332
testsuite.cpp
332
testsuite.cpp
|
@ -1,178 +1,178 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
std::ostringstream errout;
|
||||
|
||||
/**
|
||||
* TestRegistry
|
||||
**/
|
||||
|
||||
class TestRegistry
|
||||
{
|
||||
private:
|
||||
std::list<TestFixture *> _tests;
|
||||
|
||||
public:
|
||||
static TestRegistry &theInstance()
|
||||
{
|
||||
static TestRegistry testreg;
|
||||
return testreg;
|
||||
}
|
||||
|
||||
void addTest( TestFixture *t )
|
||||
{
|
||||
_tests.push_back( t );
|
||||
}
|
||||
|
||||
const std::list<TestFixture *> &tests() const
|
||||
{
|
||||
return _tests;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TestFixture
|
||||
**/
|
||||
|
||||
std::ostringstream TestFixture::errmsg;
|
||||
unsigned int TestFixture::countTests;
|
||||
|
||||
TestFixture::TestFixture(const std::string &_name) : classname(_name)
|
||||
{
|
||||
TestRegistry::theInstance().addTest(this);
|
||||
}
|
||||
|
||||
|
||||
bool TestFixture::runTest(const char testname[])
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
std::ostringstream errout;
|
||||
|
||||
/**
|
||||
* TestRegistry
|
||||
**/
|
||||
|
||||
class TestRegistry
|
||||
{
|
||||
private:
|
||||
std::list<TestFixture *> _tests;
|
||||
|
||||
public:
|
||||
static TestRegistry &theInstance()
|
||||
{
|
||||
static TestRegistry testreg;
|
||||
return testreg;
|
||||
}
|
||||
|
||||
void addTest( TestFixture *t )
|
||||
{
|
||||
_tests.push_back( t );
|
||||
}
|
||||
|
||||
const std::list<TestFixture *> &tests() const
|
||||
{
|
||||
return _tests;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TestFixture
|
||||
**/
|
||||
|
||||
std::ostringstream TestFixture::errmsg;
|
||||
unsigned int TestFixture::countTests;
|
||||
|
||||
TestFixture::TestFixture(const std::string &_name) : classname(_name)
|
||||
{
|
||||
TestRegistry::theInstance().addTest(this);
|
||||
}
|
||||
|
||||
|
||||
bool TestFixture::runTest(const char testname[])
|
||||
{
|
||||
if ( testToRun.empty() || testToRun == testname )
|
||||
{
|
||||
countTests++;
|
||||
std::cout << classname << "::" << testname << "\n";
|
||||
{
|
||||
countTests++;
|
||||
std::cout << classname << "::" << testname << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string writestr( const std::string &str )
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << "\"";
|
||||
for (unsigned int i = 0; i < str.length(); ++i)
|
||||
{
|
||||
char ch = str[i];
|
||||
if ( ch == '\n' )
|
||||
ostr << "\\n";
|
||||
else if ( ch == '\t' )
|
||||
ostr << "\\t";
|
||||
else if ( ch == '\"' )
|
||||
ostr << "\\\"";
|
||||
else
|
||||
ostr << std::string(1, ch);
|
||||
}
|
||||
ostr << "\"";
|
||||
return ostr.str();
|
||||
}
|
||||
|
||||
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
|
||||
{
|
||||
if ( expected != actual )
|
||||
{
|
||||
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
|
||||
<< "Expected:" << std::endl
|
||||
<< writestr(expected) << std::endl
|
||||
<< "Actual:" << std::endl
|
||||
<< writestr(actual) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TestFixture::assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual)
|
||||
{
|
||||
std::ostringstream ostr1;
|
||||
ostr1 << expected;
|
||||
std::ostringstream ostr2;
|
||||
ostr2 << actual;
|
||||
assertEquals( filename, linenr, ostr1.str(), ostr2.str() );
|
||||
}
|
||||
|
||||
void TestFixture::printTests()
|
||||
{
|
||||
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
|
||||
|
||||
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
|
||||
{
|
||||
std::cout << (*it)->classname << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string writestr( const std::string &str )
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << "\"";
|
||||
for (unsigned int i = 0; i < str.length(); ++i)
|
||||
{
|
||||
char ch = str[i];
|
||||
if ( ch == '\n' )
|
||||
ostr << "\\n";
|
||||
else if ( ch == '\t' )
|
||||
ostr << "\\t";
|
||||
else if ( ch == '\"' )
|
||||
ostr << "\\\"";
|
||||
else
|
||||
ostr << std::string(1, ch);
|
||||
}
|
||||
ostr << "\"";
|
||||
return ostr.str();
|
||||
}
|
||||
|
||||
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
|
||||
{
|
||||
if ( expected != actual )
|
||||
{
|
||||
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
|
||||
<< "Expected:" << std::endl
|
||||
<< writestr(expected) << std::endl
|
||||
<< "Actual:" << std::endl
|
||||
<< writestr(actual) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TestFixture::assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual)
|
||||
{
|
||||
std::ostringstream ostr1;
|
||||
ostr1 << expected;
|
||||
std::ostringstream ostr2;
|
||||
ostr2 << actual;
|
||||
assertEquals( filename, linenr, ostr1.str(), ostr2.str() );
|
||||
}
|
||||
|
||||
void TestFixture::printTests()
|
||||
{
|
||||
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
|
||||
|
||||
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
|
||||
{
|
||||
std::cout << (*it)->classname << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TestFixture::run(const std::string &str)
|
||||
{
|
||||
testToRun = str;
|
||||
run();
|
||||
}
|
||||
|
||||
void TestFixture::runTests(const char cmd[])
|
||||
{
|
||||
std::string classname(cmd ? cmd : "");
|
||||
std::string testname("");
|
||||
if ( classname.find("::") != std::string::npos )
|
||||
{
|
||||
testname = classname.substr( classname.find("::") + 2 );
|
||||
classname.erase( classname.find("::") );
|
||||
}
|
||||
|
||||
countTests = 0;
|
||||
errmsg.str("");
|
||||
|
||||
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
|
||||
|
||||
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
|
||||
{
|
||||
|
||||
void TestFixture::runTests(const char cmd[])
|
||||
{
|
||||
std::string classname(cmd ? cmd : "");
|
||||
std::string testname("");
|
||||
if ( classname.find("::") != std::string::npos )
|
||||
{
|
||||
testname = classname.substr( classname.find("::") + 2 );
|
||||
classname.erase( classname.find("::") );
|
||||
}
|
||||
|
||||
countTests = 0;
|
||||
errmsg.str("");
|
||||
|
||||
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
|
||||
|
||||
for ( std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it )
|
||||
{
|
||||
if ( classname.empty() || (*it)->classname == classname )
|
||||
{
|
||||
{
|
||||
(*it)->run(testname);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n\nTesting Complete\nNumber of tests: " << countTests << "\n";
|
||||
|
||||
std::cerr << errmsg.str();
|
||||
}
|
||||
|
||||
|
||||
void TestFixture::reportErr( const std::string &errmsg)
|
||||
{
|
||||
errout << errmsg << std::endl;
|
||||
}
|
||||
|
||||
void TestFixture::reportOut( const std::string &outmsg)
|
||||
{
|
||||
// These can probably be ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n\nTesting Complete\nNumber of tests: " << countTests << "\n";
|
||||
|
||||
std::cerr << errmsg.str();
|
||||
}
|
||||
|
||||
|
||||
void TestFixture::reportErr( const std::string &errmsg)
|
||||
{
|
||||
errout << errmsg << std::endl;
|
||||
}
|
||||
|
||||
void TestFixture::reportOut( const std::string &outmsg)
|
||||
{
|
||||
// These can probably be ignored
|
||||
}
|
||||
|
|
116
testsuite.h
116
testsuite.h
|
@ -1,61 +1,61 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include <sstream>
|
||||
#include "errorlogger.h"
|
||||
|
||||
class TOKEN;
|
||||
|
||||
class TestFixture : public ErrorLogger
|
||||
{
|
||||
private:
|
||||
static std::ostringstream errmsg;
|
||||
static unsigned int countTests;
|
||||
|
||||
protected:
|
||||
std::string classname;
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include <sstream>
|
||||
#include "errorlogger.h"
|
||||
|
||||
class TOKEN;
|
||||
|
||||
class TestFixture : public ErrorLogger
|
||||
{
|
||||
private:
|
||||
static std::ostringstream errmsg;
|
||||
static unsigned int countTests;
|
||||
|
||||
protected:
|
||||
std::string classname;
|
||||
std::string testToRun;
|
||||
|
||||
virtual void run() = 0;
|
||||
|
||||
bool runTest(const char testname[]);
|
||||
void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual);
|
||||
void assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual);
|
||||
|
||||
public:
|
||||
virtual void reportErr( const std::string &errmsg);
|
||||
|
||||
virtual void reportOut( const std::string &outmsg);
|
||||
|
||||
virtual void run() = 0;
|
||||
|
||||
bool runTest(const char testname[]);
|
||||
void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual);
|
||||
void assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual);
|
||||
|
||||
public:
|
||||
virtual void reportErr( const std::string &errmsg);
|
||||
|
||||
virtual void reportOut( const std::string &outmsg);
|
||||
|
||||
void run(const std::string &str);
|
||||
|
||||
TestFixture(const std::string &_name);
|
||||
virtual ~TestFixture() { }
|
||||
|
||||
static void printTests();
|
||||
static void runTests(const char cmd[]);
|
||||
};
|
||||
|
||||
|
||||
#define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME ();
|
||||
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
||||
#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance; }
|
||||
|
||||
|
||||
TestFixture(const std::string &_name);
|
||||
virtual ~TestFixture() { }
|
||||
|
||||
static void printTests();
|
||||
static void runTests(const char cmd[]);
|
||||
};
|
||||
|
||||
|
||||
#define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME ();
|
||||
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
||||
#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance; }
|
||||
|
||||
|
|
122
testtoken.cpp
122
testtoken.cpp
|
@ -1,61 +1,61 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "testsuite.h"
|
||||
#include "token.h"
|
||||
|
||||
extern std::ostringstream errout;
|
||||
class TestTOKEN : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestTOKEN() : TestFixture("TestTOKEN")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( nextprevious );
|
||||
|
||||
}
|
||||
|
||||
void nextprevious()
|
||||
{
|
||||
TOKEN *token = new TOKEN;
|
||||
token->setstr( "1" );
|
||||
token->insertToken( "2" );
|
||||
token->next()->insertToken( "3" );
|
||||
TOKEN *last = token->next()->next();
|
||||
ASSERT_EQUALS( token->str(), "1" );
|
||||
ASSERT_EQUALS( token->next()->str(), "2" );
|
||||
ASSERT_EQUALS( token->next()->next()->str(), "3" );
|
||||
if( last->next() )
|
||||
ASSERT_EQUALS( "Null was expected", "" );
|
||||
|
||||
ASSERT_EQUALS( last->str(), "3" );
|
||||
ASSERT_EQUALS( last->previous()->str(), "2" );
|
||||
ASSERT_EQUALS( last->previous()->previous()->str(), "1" );
|
||||
if( token->previous() )
|
||||
ASSERT_EQUALS( "Null was expected", "" );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestTOKEN )
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "testsuite.h"
|
||||
#include "token.h"
|
||||
|
||||
extern std::ostringstream errout;
|
||||
class TestTOKEN : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestTOKEN() : TestFixture("TestTOKEN")
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( nextprevious );
|
||||
|
||||
}
|
||||
|
||||
void nextprevious()
|
||||
{
|
||||
TOKEN *token = new TOKEN;
|
||||
token->setstr( "1" );
|
||||
token->insertToken( "2" );
|
||||
token->next()->insertToken( "3" );
|
||||
TOKEN *last = token->next()->next();
|
||||
ASSERT_EQUALS( token->str(), "1" );
|
||||
ASSERT_EQUALS( token->next()->str(), "2" );
|
||||
ASSERT_EQUALS( token->next()->next()->str(), "3" );
|
||||
if( last->next() )
|
||||
ASSERT_EQUALS( "Null was expected", "" );
|
||||
|
||||
ASSERT_EQUALS( last->str(), "3" );
|
||||
ASSERT_EQUALS( last->previous()->str(), "2" );
|
||||
ASSERT_EQUALS( last->previous()->previous()->str(), "1" );
|
||||
if( token->previous() )
|
||||
ASSERT_EQUALS( "Null was expected", "" );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestTOKEN )
|
||||
|
|
1012
testtokenize.cpp
1012
testtokenize.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,120 +1,120 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkclass.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestUnusedPrivateFunction : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestUnusedPrivateFunction() : TestFixture("TestUnusedPrivateFunction")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( test1 );
|
||||
|
||||
// [ 2236547 ] False positive --style unused function, called via pointer
|
||||
TEST_CASE( func_pointer );
|
||||
}
|
||||
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused private functions..
|
||||
Settings settings;
|
||||
settings._checkCodingStyle = true;
|
||||
CheckClass checkClass( &tokenizer, settings, this );
|
||||
checkClass.CheckUnusedPrivateFunctions();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test1()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" unsigned int f();\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }\n"
|
||||
"\n"
|
||||
"unsigned int Fred::f()\n"
|
||||
"{ }\n" );
|
||||
|
||||
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'f'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void func_pointer()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" typedef void (*testfp)();\n"
|
||||
"\n"
|
||||
" testfp get()\n"
|
||||
" {\n"
|
||||
" return test;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static void test()\n"
|
||||
" { }\n"
|
||||
"\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"Fred::Fred()\n"
|
||||
"{}\n" );
|
||||
|
||||
std::string str( errout.str() );
|
||||
|
||||
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'get'\n"), str );
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestUnusedPrivateFunction )
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "tokenize.h"
|
||||
#include "checkclass.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestUnusedPrivateFunction : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestUnusedPrivateFunction() : TestFixture("TestUnusedPrivateFunction")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( test1 );
|
||||
|
||||
// [ 2236547 ] False positive --style unused function, called via pointer
|
||||
TEST_CASE( func_pointer );
|
||||
}
|
||||
|
||||
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused private functions..
|
||||
Settings settings;
|
||||
settings._checkCodingStyle = true;
|
||||
CheckClass checkClass( &tokenizer, settings, this );
|
||||
checkClass.CheckUnusedPrivateFunctions();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test1()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" unsigned int f();\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"Fred::Fred()\n"
|
||||
"{ }\n"
|
||||
"\n"
|
||||
"unsigned int Fred::f()\n"
|
||||
"{ }\n" );
|
||||
|
||||
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'f'\n"), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void func_pointer()
|
||||
{
|
||||
check( "class Fred\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" typedef void (*testfp)();\n"
|
||||
"\n"
|
||||
" testfp get()\n"
|
||||
" {\n"
|
||||
" return test;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static void test()\n"
|
||||
" { }\n"
|
||||
"\n"
|
||||
"public:\n"
|
||||
" Fred();\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"Fred::Fred()\n"
|
||||
"{}\n" );
|
||||
|
||||
std::string str( errout.str() );
|
||||
|
||||
ASSERT_EQUALS( std::string("Class 'Fred', unused private function: 'get'\n"), str );
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestUnusedPrivateFunction )
|
||||
|
||||
|
|
|
@ -1,184 +1,184 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Check for unused variables..
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "testsuite.h"
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
|
||||
#include <sstream>
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestUnusedVar : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestUnusedVar() : TestFixture("TestUnusedVar")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused variables..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckStructMemberUsage();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( structmember1 );
|
||||
TEST_CASE( structmember2 );
|
||||
TEST_CASE( structmember3 );
|
||||
|
||||
TEST_CASE( localvar1 );
|
||||
TEST_CASE( localvar2 );
|
||||
TEST_CASE( localvar3 );
|
||||
TEST_CASE( localvar4 );
|
||||
}
|
||||
|
||||
void structmember1()
|
||||
{
|
||||
check( "struct abc\n"
|
||||
"{\n"
|
||||
" int a;\n"
|
||||
" int b;\n"
|
||||
" int c;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: struct member 'abc::a' is never read\n"
|
||||
"[test.cpp:3]: struct member 'abc::b' is never read\n"
|
||||
"[test.cpp:4]: struct member 'abc::c' is never read\n"), errout.str() );
|
||||
}
|
||||
|
||||
void structmember2()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" int a;\n"
|
||||
" int b;\n"
|
||||
" int c;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" struct ABC abc;\n"
|
||||
" int a = abc.a;\n"
|
||||
" int b = abc.b;\n"
|
||||
" int c = abc.c;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void structmember3()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" int a;\n"
|
||||
" int b;\n"
|
||||
" int c;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static struct ABC abc[] = { {1, 2, 3} };\n"
|
||||
"\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" int a = abc[0].a;\n"
|
||||
" int b = abc[0].b;\n"
|
||||
" int c = abc[0].c;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void functionVariableUsage( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused variables..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.functionVariableUsage();
|
||||
}
|
||||
|
||||
void localvar1()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
||||
}
|
||||
|
||||
void localvar2()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i;\n"
|
||||
" return i;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is not assigned a value\n"), errout.str() );
|
||||
}
|
||||
|
||||
void localvar3()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i;\n"
|
||||
" if ( abc )\n"
|
||||
" ;\n"
|
||||
" else i = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
||||
}
|
||||
|
||||
void localvar4()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i = 0;\n"
|
||||
" f(i);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestUnusedVar )
|
||||
|
||||
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Check for unused variables..
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include "testsuite.h"
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
|
||||
#include <sstream>
|
||||
extern std::ostringstream errout;
|
||||
|
||||
class TestUnusedVar : public TestFixture
|
||||
{
|
||||
public:
|
||||
TestUnusedVar() : TestFixture("TestUnusedVar")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void check( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused variables..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.CheckStructMemberUsage();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TEST_CASE( structmember1 );
|
||||
TEST_CASE( structmember2 );
|
||||
TEST_CASE( structmember3 );
|
||||
|
||||
TEST_CASE( localvar1 );
|
||||
TEST_CASE( localvar2 );
|
||||
TEST_CASE( localvar3 );
|
||||
TEST_CASE( localvar4 );
|
||||
}
|
||||
|
||||
void structmember1()
|
||||
{
|
||||
check( "struct abc\n"
|
||||
"{\n"
|
||||
" int a;\n"
|
||||
" int b;\n"
|
||||
" int c;\n"
|
||||
"};\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: struct member 'abc::a' is never read\n"
|
||||
"[test.cpp:3]: struct member 'abc::b' is never read\n"
|
||||
"[test.cpp:4]: struct member 'abc::c' is never read\n"), errout.str() );
|
||||
}
|
||||
|
||||
void structmember2()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" int a;\n"
|
||||
" int b;\n"
|
||||
" int c;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" struct ABC abc;\n"
|
||||
" int a = abc.a;\n"
|
||||
" int b = abc.b;\n"
|
||||
" int c = abc.c;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
void structmember3()
|
||||
{
|
||||
check( "struct ABC\n"
|
||||
"{\n"
|
||||
" int a;\n"
|
||||
" int b;\n"
|
||||
" int c;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static struct ABC abc[] = { {1, 2, 3} };\n"
|
||||
"\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" int a = abc[0].a;\n"
|
||||
" int b = abc[0].b;\n"
|
||||
" int c = abc[0].c;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void functionVariableUsage( const char code[] )
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize( istr, "test.cpp" );
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
// Check for unused variables..
|
||||
CheckOther checkOther( &tokenizer, this );
|
||||
checkOther.functionVariableUsage();
|
||||
}
|
||||
|
||||
void localvar1()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
||||
}
|
||||
|
||||
void localvar2()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i;\n"
|
||||
" return i;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is not assigned a value\n"), errout.str() );
|
||||
}
|
||||
|
||||
void localvar3()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i;\n"
|
||||
" if ( abc )\n"
|
||||
" ;\n"
|
||||
" else i = 0;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
||||
}
|
||||
|
||||
void localvar4()
|
||||
{
|
||||
functionVariableUsage( "void foo()\n"
|
||||
"{\n"
|
||||
" int i = 0;\n"
|
||||
" f(i);\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string(""), errout.str() );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST( TestUnusedVar )
|
||||
|
||||
|
||||
|
|
860
token.cpp
860
token.cpp
|
@ -1,436 +1,436 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "token.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#include <ctype.h> // isalpha, isdigit
|
||||
#endif
|
||||
|
||||
TOKEN::TOKEN()
|
||||
{
|
||||
_fileIndex = 0;
|
||||
_cstr = 0;
|
||||
_str = "";
|
||||
_linenr = 0;
|
||||
_next = 0;
|
||||
_previous = 0;
|
||||
_varId = 0;
|
||||
_isName = false;
|
||||
_isNumber = false;
|
||||
}
|
||||
|
||||
TOKEN::~TOKEN()
|
||||
{
|
||||
std::free(_cstr);
|
||||
}
|
||||
|
||||
void TOKEN::setstr( const char s[] )
|
||||
{
|
||||
_str = s;
|
||||
std::free(_cstr);
|
||||
#ifndef _MSC_VER
|
||||
_cstr = strdup(s);
|
||||
#else
|
||||
_cstr = _strdup(s);
|
||||
#endif
|
||||
_isName = bool(_str[0]=='_' || isalpha(_str[0]));
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#include "token.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#include <ctype.h> // isalpha, isdigit
|
||||
#endif
|
||||
|
||||
TOKEN::TOKEN()
|
||||
{
|
||||
_fileIndex = 0;
|
||||
_cstr = 0;
|
||||
_str = "";
|
||||
_linenr = 0;
|
||||
_next = 0;
|
||||
_previous = 0;
|
||||
_varId = 0;
|
||||
_isName = false;
|
||||
_isNumber = false;
|
||||
}
|
||||
|
||||
TOKEN::~TOKEN()
|
||||
{
|
||||
std::free(_cstr);
|
||||
}
|
||||
|
||||
void TOKEN::setstr( const char s[] )
|
||||
{
|
||||
_str = s;
|
||||
std::free(_cstr);
|
||||
#ifndef _MSC_VER
|
||||
_cstr = strdup(s);
|
||||
#else
|
||||
_cstr = _strdup(s);
|
||||
#endif
|
||||
_isName = bool(_str[0]=='_' || isalpha(_str[0]));
|
||||
_isNumber = bool(isdigit(_str[0]) != 0);
|
||||
_varId = 0;
|
||||
}
|
||||
|
||||
void TOKEN::combineWithNext(const char str1[], const char str2[])
|
||||
{
|
||||
if (!(_next))
|
||||
return;
|
||||
if (_str!=str1 || _next->_str!=str2)
|
||||
return;
|
||||
|
||||
std::string newstr(std::string(str1) + std::string(str2));
|
||||
setstr( newstr.c_str() );
|
||||
deleteNext();
|
||||
}
|
||||
|
||||
void TOKEN::deleteNext()
|
||||
{
|
||||
TOKEN *n = _next;
|
||||
_next = n->next();
|
||||
_varId = 0;
|
||||
}
|
||||
|
||||
void TOKEN::combineWithNext(const char str1[], const char str2[])
|
||||
{
|
||||
if (!(_next))
|
||||
return;
|
||||
if (_str!=str1 || _next->_str!=str2)
|
||||
return;
|
||||
|
||||
std::string newstr(std::string(str1) + std::string(str2));
|
||||
setstr( newstr.c_str() );
|
||||
deleteNext();
|
||||
}
|
||||
|
||||
void TOKEN::deleteNext()
|
||||
{
|
||||
TOKEN *n = _next;
|
||||
_next = n->next();
|
||||
delete n;
|
||||
if (_next)
|
||||
_next->previous(this);
|
||||
}
|
||||
|
||||
const TOKEN *TOKEN::tokAt(int index) const
|
||||
{
|
||||
const TOKEN *tok = this;
|
||||
while (index>0 && tok)
|
||||
{
|
||||
tok = tok->next();
|
||||
index--;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
const char *TOKEN::strAt(int index) const
|
||||
{
|
||||
const TOKEN *tok = this->tokAt(index);
|
||||
return tok ? tok->_cstr : "";
|
||||
}
|
||||
|
||||
int TOKEN::multiCompare( const char *needle, const char *haystack )
|
||||
{
|
||||
bool emptyStringFound = false;
|
||||
bool findNextOr = false;
|
||||
const char *haystackPointer = haystack;
|
||||
for( ; *needle; ++needle )
|
||||
{
|
||||
if( *needle == '|' )
|
||||
{
|
||||
// If needle and haystack are both at the end, we have a match.
|
||||
if( *haystackPointer == 0 )
|
||||
return 1;
|
||||
|
||||
haystackPointer = haystack;
|
||||
if( findNextOr )
|
||||
findNextOr = false;
|
||||
else
|
||||
emptyStringFound = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if( findNextOr )
|
||||
continue;
|
||||
|
||||
// If haystack and needle don't share the same character, reset
|
||||
// haystackpointer and find next '|' character.
|
||||
if( *haystackPointer != *needle )
|
||||
{
|
||||
haystackPointer = haystack;
|
||||
findNextOr = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// All characters in haystack and needle have matched this far
|
||||
haystackPointer++;
|
||||
}
|
||||
|
||||
// If both needle and haystack are at the end, then we have a match.
|
||||
if( *haystackPointer == 0 )
|
||||
return 1;
|
||||
|
||||
// If empty string was found or if last character in needle was '|'
|
||||
if( emptyStringFound || findNextOr == false )
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[], unsigned int varid)
|
||||
{
|
||||
const char *p = pattern;
|
||||
while ( *p )
|
||||
{
|
||||
// Skip spaces in pattern..
|
||||
while ( *p == ' ' )
|
||||
p++;
|
||||
|
||||
if (!tok)
|
||||
{
|
||||
// If we have no tokens, pattern "!!else" should return true
|
||||
if( isNotPattern( p ) )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract token from pattern..
|
||||
// TODO: Refactor this so there can't be buffer overflows
|
||||
char str[500];
|
||||
char *s = str;
|
||||
while (*p && *p!=' ')
|
||||
{
|
||||
*s = *p;
|
||||
s++;
|
||||
p++;
|
||||
}
|
||||
*s = 0;
|
||||
|
||||
// No token => Success!
|
||||
if (str[0] == 0)
|
||||
return true;
|
||||
|
||||
bool useVar1;
|
||||
// Any symbolname..
|
||||
if (strcmp(str,"%var%")==0 || strcmp(str,"%type%")==0)
|
||||
{
|
||||
if (!tok->isName())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Accept any token
|
||||
else if (strcmp(str,"%any%")==0 )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Variable name..
|
||||
else if ((useVar1 = (strcmp(str,"%var1%")==0)) || strcmp(str,"%var2%")==0)
|
||||
{
|
||||
const char **varname = useVar1 ? varname1 : varname2;
|
||||
|
||||
if ( ! varname )
|
||||
return false;
|
||||
|
||||
if (tok->_str != varname[0])
|
||||
return false;
|
||||
|
||||
for ( int i = 1; varname[i]; i++ )
|
||||
{
|
||||
if ( !(tok->tokAt(2)) )
|
||||
return false;
|
||||
|
||||
if ( strcmp(tok->strAt( 1), ".") )
|
||||
return false;
|
||||
|
||||
if ( strcmp(tok->strAt( 2), varname[i]) )
|
||||
return false;
|
||||
|
||||
tok = tok->tokAt(2);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp(str,"%varid%")==0)
|
||||
{
|
||||
if ( tok->varId() != varid )
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (strcmp(str,"%num%")==0)
|
||||
{
|
||||
if ( ! tok->isNumber() )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
else if (strcmp(str,"%str%")==0)
|
||||
{
|
||||
if ( tok->_str[0] != '\"' )
|
||||
return false;
|
||||
}
|
||||
|
||||
// [.. => search for a one-character token..
|
||||
else if (str[0]=='[' && strchr(str, ']') && tok->_str[1] == 0)
|
||||
{
|
||||
*strrchr(str, ']') = 0;
|
||||
if ( strchr( str + 1, tok->_str[0] ) == 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse multi options, such as void|int|char (accept token which is one of these 3)
|
||||
else if ( strchr(str, '|') && strlen( str ) > 2 )
|
||||
{
|
||||
int res = multiCompare( str, tok->_cstr );
|
||||
if( res == 0 )
|
||||
{
|
||||
// Empty alternative matches, use the same token on next round
|
||||
continue;
|
||||
}
|
||||
else if( res == -1 )
|
||||
{
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse "not" options. Token can be anything except the given one
|
||||
else if( isNotPattern( str ) )
|
||||
{
|
||||
if( strcmp( tok->aaaa(), &(str[2]) ) == 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (str != tok->_str)
|
||||
return false;
|
||||
|
||||
tok = tok->next();
|
||||
}
|
||||
|
||||
// The end of the pattern has been reached and nothing wrong has been found
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TOKEN::isNotPattern( const char *pattern )
|
||||
{
|
||||
if( pattern && strlen(pattern) > 2 && pattern[0] == '!' && pattern[1] == '!' )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TOKEN::isName() const
|
||||
{
|
||||
return _isName;
|
||||
}
|
||||
|
||||
bool TOKEN::isNumber() const
|
||||
{
|
||||
return _isNumber;
|
||||
}
|
||||
|
||||
bool TOKEN::isStandardType() const
|
||||
{
|
||||
bool ret = false;
|
||||
const char *type[] = {"bool","char","short","int","long","float","double",0};
|
||||
for (int i = 0; type[i]; i++)
|
||||
ret |= (_str == type[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const TOKEN *TOKEN::findmatch(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[])
|
||||
{
|
||||
for ( ; tok; tok = tok->next())
|
||||
{
|
||||
if ( TOKEN::Match(tok, pattern, varname1, varname2) )
|
||||
return tok;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const TOKEN *TOKEN::findtoken(const TOKEN *tok1, const char *tokenstr[])
|
||||
{
|
||||
for (const TOKEN *ret = tok1; ret; ret = ret->next())
|
||||
{
|
||||
unsigned int i = 0;
|
||||
const TOKEN *tok = ret;
|
||||
while (tokenstr[i])
|
||||
{
|
||||
if (!tok)
|
||||
return NULL;
|
||||
if (*(tokenstr[i]) && (tokenstr[i] != tok->_str))
|
||||
break;
|
||||
tok = tok->next();
|
||||
i++;
|
||||
}
|
||||
if (!tokenstr[i])
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int TOKEN::varId() const
|
||||
{
|
||||
return _varId;
|
||||
}
|
||||
|
||||
void TOKEN::varId( unsigned int id )
|
||||
{
|
||||
_varId = id;
|
||||
}
|
||||
|
||||
TOKEN *TOKEN::next() const
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
void TOKEN::next( TOKEN *next )
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
TOKEN *TOKEN::previous() const
|
||||
{
|
||||
return _previous;
|
||||
}
|
||||
|
||||
void TOKEN::previous( TOKEN *previous )
|
||||
{
|
||||
_previous = previous;
|
||||
}
|
||||
|
||||
void TOKEN::insertToken( const char str[] )
|
||||
{
|
||||
TOKEN *newToken = new TOKEN;
|
||||
_next->previous(this);
|
||||
}
|
||||
|
||||
const TOKEN *TOKEN::tokAt(int index) const
|
||||
{
|
||||
const TOKEN *tok = this;
|
||||
while (index>0 && tok)
|
||||
{
|
||||
tok = tok->next();
|
||||
index--;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
const char *TOKEN::strAt(int index) const
|
||||
{
|
||||
const TOKEN *tok = this->tokAt(index);
|
||||
return tok ? tok->_cstr : "";
|
||||
}
|
||||
|
||||
int TOKEN::multiCompare( const char *needle, const char *haystack )
|
||||
{
|
||||
bool emptyStringFound = false;
|
||||
bool findNextOr = false;
|
||||
const char *haystackPointer = haystack;
|
||||
for( ; *needle; ++needle )
|
||||
{
|
||||
if( *needle == '|' )
|
||||
{
|
||||
// If needle and haystack are both at the end, we have a match.
|
||||
if( *haystackPointer == 0 )
|
||||
return 1;
|
||||
|
||||
haystackPointer = haystack;
|
||||
if( findNextOr )
|
||||
findNextOr = false;
|
||||
else
|
||||
emptyStringFound = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if( findNextOr )
|
||||
continue;
|
||||
|
||||
// If haystack and needle don't share the same character, reset
|
||||
// haystackpointer and find next '|' character.
|
||||
if( *haystackPointer != *needle )
|
||||
{
|
||||
haystackPointer = haystack;
|
||||
findNextOr = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// All characters in haystack and needle have matched this far
|
||||
haystackPointer++;
|
||||
}
|
||||
|
||||
// If both needle and haystack are at the end, then we have a match.
|
||||
if( *haystackPointer == 0 )
|
||||
return 1;
|
||||
|
||||
// If empty string was found or if last character in needle was '|'
|
||||
if( emptyStringFound || findNextOr == false )
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool TOKEN::Match(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[], unsigned int varid)
|
||||
{
|
||||
const char *p = pattern;
|
||||
while ( *p )
|
||||
{
|
||||
// Skip spaces in pattern..
|
||||
while ( *p == ' ' )
|
||||
p++;
|
||||
|
||||
if (!tok)
|
||||
{
|
||||
// If we have no tokens, pattern "!!else" should return true
|
||||
if( isNotPattern( p ) )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract token from pattern..
|
||||
// TODO: Refactor this so there can't be buffer overflows
|
||||
char str[500];
|
||||
char *s = str;
|
||||
while (*p && *p!=' ')
|
||||
{
|
||||
*s = *p;
|
||||
s++;
|
||||
p++;
|
||||
}
|
||||
*s = 0;
|
||||
|
||||
// No token => Success!
|
||||
if (str[0] == 0)
|
||||
return true;
|
||||
|
||||
bool useVar1;
|
||||
// Any symbolname..
|
||||
if (strcmp(str,"%var%")==0 || strcmp(str,"%type%")==0)
|
||||
{
|
||||
if (!tok->isName())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Accept any token
|
||||
else if (strcmp(str,"%any%")==0 )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Variable name..
|
||||
else if ((useVar1 = (strcmp(str,"%var1%")==0)) || strcmp(str,"%var2%")==0)
|
||||
{
|
||||
const char **varname = useVar1 ? varname1 : varname2;
|
||||
|
||||
if ( ! varname )
|
||||
return false;
|
||||
|
||||
if (tok->_str != varname[0])
|
||||
return false;
|
||||
|
||||
for ( int i = 1; varname[i]; i++ )
|
||||
{
|
||||
if ( !(tok->tokAt(2)) )
|
||||
return false;
|
||||
|
||||
if ( strcmp(tok->strAt( 1), ".") )
|
||||
return false;
|
||||
|
||||
if ( strcmp(tok->strAt( 2), varname[i]) )
|
||||
return false;
|
||||
|
||||
tok = tok->tokAt(2);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp(str,"%varid%")==0)
|
||||
{
|
||||
if ( tok->varId() != varid )
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (strcmp(str,"%num%")==0)
|
||||
{
|
||||
if ( ! tok->isNumber() )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
else if (strcmp(str,"%str%")==0)
|
||||
{
|
||||
if ( tok->_str[0] != '\"' )
|
||||
return false;
|
||||
}
|
||||
|
||||
// [.. => search for a one-character token..
|
||||
else if (str[0]=='[' && strchr(str, ']') && tok->_str[1] == 0)
|
||||
{
|
||||
*strrchr(str, ']') = 0;
|
||||
if ( strchr( str + 1, tok->_str[0] ) == 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse multi options, such as void|int|char (accept token which is one of these 3)
|
||||
else if ( strchr(str, '|') && strlen( str ) > 2 )
|
||||
{
|
||||
int res = multiCompare( str, tok->_cstr );
|
||||
if( res == 0 )
|
||||
{
|
||||
// Empty alternative matches, use the same token on next round
|
||||
continue;
|
||||
}
|
||||
else if( res == -1 )
|
||||
{
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse "not" options. Token can be anything except the given one
|
||||
else if( isNotPattern( str ) )
|
||||
{
|
||||
if( strcmp( tok->aaaa(), &(str[2]) ) == 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (str != tok->_str)
|
||||
return false;
|
||||
|
||||
tok = tok->next();
|
||||
}
|
||||
|
||||
// The end of the pattern has been reached and nothing wrong has been found
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TOKEN::isNotPattern( const char *pattern )
|
||||
{
|
||||
if( pattern && strlen(pattern) > 2 && pattern[0] == '!' && pattern[1] == '!' )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TOKEN::isName() const
|
||||
{
|
||||
return _isName;
|
||||
}
|
||||
|
||||
bool TOKEN::isNumber() const
|
||||
{
|
||||
return _isNumber;
|
||||
}
|
||||
|
||||
bool TOKEN::isStandardType() const
|
||||
{
|
||||
bool ret = false;
|
||||
const char *type[] = {"bool","char","short","int","long","float","double",0};
|
||||
for (int i = 0; type[i]; i++)
|
||||
ret |= (_str == type[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const TOKEN *TOKEN::findmatch(const TOKEN *tok, const char pattern[], const char *varname1[], const char *varname2[])
|
||||
{
|
||||
for ( ; tok; tok = tok->next())
|
||||
{
|
||||
if ( TOKEN::Match(tok, pattern, varname1, varname2) )
|
||||
return tok;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const TOKEN *TOKEN::findtoken(const TOKEN *tok1, const char *tokenstr[])
|
||||
{
|
||||
for (const TOKEN *ret = tok1; ret; ret = ret->next())
|
||||
{
|
||||
unsigned int i = 0;
|
||||
const TOKEN *tok = ret;
|
||||
while (tokenstr[i])
|
||||
{
|
||||
if (!tok)
|
||||
return NULL;
|
||||
if (*(tokenstr[i]) && (tokenstr[i] != tok->_str))
|
||||
break;
|
||||
tok = tok->next();
|
||||
i++;
|
||||
}
|
||||
if (!tokenstr[i])
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int TOKEN::varId() const
|
||||
{
|
||||
return _varId;
|
||||
}
|
||||
|
||||
void TOKEN::varId( unsigned int id )
|
||||
{
|
||||
_varId = id;
|
||||
}
|
||||
|
||||
TOKEN *TOKEN::next() const
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
void TOKEN::next( TOKEN *next )
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
TOKEN *TOKEN::previous() const
|
||||
{
|
||||
return _previous;
|
||||
}
|
||||
|
||||
void TOKEN::previous( TOKEN *previous )
|
||||
{
|
||||
_previous = previous;
|
||||
}
|
||||
|
||||
void TOKEN::insertToken( const char str[] )
|
||||
{
|
||||
TOKEN *newToken = new TOKEN;
|
||||
newToken->setstr( str );
|
||||
newToken->_linenr = _linenr;
|
||||
newToken->_fileIndex = _fileIndex;
|
||||
if( this->next() )
|
||||
{
|
||||
newToken->next( this->next() );
|
||||
newToken->next()->previous( newToken );
|
||||
}
|
||||
newToken->_fileIndex = _fileIndex;
|
||||
if( this->next() )
|
||||
{
|
||||
newToken->next( this->next() );
|
||||
newToken->next()->previous( newToken );
|
||||
}
|
||||
|
||||
this->next( newToken );
|
||||
newToken->previous( this );
|
||||
}
|
||||
|
||||
void TOKEN::eraseTokens( TOKEN *begin, const TOKEN *end )
|
||||
{
|
||||
if ( ! begin )
|
||||
return;
|
||||
|
||||
while ( begin->next() && begin->next() != end )
|
||||
{
|
||||
begin->deleteNext();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int TOKEN::fileIndex() const
|
||||
{
|
||||
return _fileIndex;
|
||||
}
|
||||
|
||||
void TOKEN::fileIndex( unsigned int fileIndex )
|
||||
{
|
||||
_fileIndex = fileIndex;
|
||||
}
|
||||
|
||||
unsigned int TOKEN::linenr() const
|
||||
{
|
||||
return _linenr;
|
||||
}
|
||||
|
||||
void TOKEN::linenr( unsigned int linenr )
|
||||
{
|
||||
_linenr = linenr;
|
||||
}
|
||||
|
||||
void TOKEN::printOut( const char *title ) const
|
||||
{
|
||||
std::cout << std::endl << "###";
|
||||
if ( title )
|
||||
std::cout << " " << title << " ";
|
||||
else
|
||||
std::cout << "########";
|
||||
|
||||
std::cout << "###" << std::endl;
|
||||
for( const TOKEN *t = this; t; t = t->next() )
|
||||
{
|
||||
std::cout << t->linenr() << ": " << t->str();
|
||||
if ( t->varId() )
|
||||
std::cout << " ("<< t->varId() <<")";
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
this->next( newToken );
|
||||
newToken->previous( this );
|
||||
}
|
||||
|
||||
void TOKEN::eraseTokens( TOKEN *begin, const TOKEN *end )
|
||||
{
|
||||
if ( ! begin )
|
||||
return;
|
||||
|
||||
while ( begin->next() && begin->next() != end )
|
||||
{
|
||||
begin->deleteNext();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int TOKEN::fileIndex() const
|
||||
{
|
||||
return _fileIndex;
|
||||
}
|
||||
|
||||
void TOKEN::fileIndex( unsigned int fileIndex )
|
||||
{
|
||||
_fileIndex = fileIndex;
|
||||
}
|
||||
|
||||
unsigned int TOKEN::linenr() const
|
||||
{
|
||||
return _linenr;
|
||||
}
|
||||
|
||||
void TOKEN::linenr( unsigned int linenr )
|
||||
{
|
||||
_linenr = linenr;
|
||||
}
|
||||
|
||||
void TOKEN::printOut( const char *title ) const
|
||||
{
|
||||
std::cout << std::endl << "###";
|
||||
if ( title )
|
||||
std::cout << " " << title << " ";
|
||||
else
|
||||
std::cout << "########";
|
||||
|
||||
std::cout << "###" << std::endl;
|
||||
for( const TOKEN *t = this; t; t = t->next() )
|
||||
{
|
||||
std::cout << t->linenr() << ": " << t->str();
|
||||
if ( t->varId() )
|
||||
std::cout << " ("<< t->varId() <<")";
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
366
token.h
366
token.h
|
@ -1,183 +1,183 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef TOKEN_H
|
||||
#define TOKEN_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class TOKEN
|
||||
{
|
||||
public:
|
||||
TOKEN();
|
||||
~TOKEN();
|
||||
void setstr( const char s[] );
|
||||
|
||||
const std::string &str() const
|
||||
{ return _str; }
|
||||
|
||||
const char *aaaa() const
|
||||
{ return _cstr; }
|
||||
|
||||
char aaaa0() const
|
||||
{ return _cstr[0]; }
|
||||
|
||||
char aaaa1() const
|
||||
{ return _cstr[1]; }
|
||||
|
||||
|
||||
/**
|
||||
* Combine two tokens that belong to each other.
|
||||
* Ex: "<" and "=" may become "<="
|
||||
*/
|
||||
void combineWithNext(const char str1[], const char str2[]);
|
||||
|
||||
/**
|
||||
* Unlink and delete next token.
|
||||
*/
|
||||
void deleteNext();
|
||||
|
||||
/**
|
||||
* Returns token in given index, related to this token.
|
||||
* For example index 1 would return next token, and 2
|
||||
* would return next from that one.
|
||||
*/
|
||||
const TOKEN *tokAt(int index) const;
|
||||
|
||||
const char *strAt(int index) const;
|
||||
|
||||
/**
|
||||
* Match given token (or list of tokens) to a pattern list.
|
||||
*
|
||||
* Possible patterns
|
||||
* "%any%" any token
|
||||
* "%var%" any token which is a name or type e.g. "hello" or "int"
|
||||
* "%num%" Any numeric token, e.g. "23"
|
||||
* "%str%" Any token starting with "-character (C-string).
|
||||
* "%var1%" Match with parameter varname1
|
||||
* "%var2%" Match with parameter varname2
|
||||
* "%varid%" Match with parameter varid
|
||||
* "[abc]" Any of the characters 'a' or 'b' or 'c'
|
||||
* "int|void|char" Any of the strings, int, void or char
|
||||
* "int|void|char|" Any of the strings, int, void or char or empty string
|
||||
* "!!else" No tokens or any token that is not "else".
|
||||
* "someRandomText" If token contains "someRandomText".
|
||||
*
|
||||
* The patterns can be also combined to compare to multiple tokens at once
|
||||
* by separating tokens with a space, e.g.
|
||||
* ") const|void {" will return true if first token is ')' next token is either
|
||||
* "const" or "void" and token after that is '{'. If even one of the tokens does not
|
||||
* match its pattern, false is returned.
|
||||
*
|
||||
* @param tok List of tokens to be compared to the pattern
|
||||
* @param pattern The pattern where tokens are compared, e.g. "const"
|
||||
* or ") const|volatile| {".
|
||||
* @param varname1 Used with pattern "%var1%" and "%var2%"
|
||||
* @param varname2 Used with pattern "%var1%" and "%var2%"
|
||||
* @return true if given token matches with given pattern
|
||||
* false if given token does not match with given pattern
|
||||
*/
|
||||
static bool Match(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0, unsigned int varid=0);
|
||||
|
||||
bool isName() const;
|
||||
bool isNumber() const;
|
||||
bool isStandardType() const;
|
||||
static const TOKEN *findmatch(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0);
|
||||
static const TOKEN *findtoken(const TOKEN *tok1, const char *tokenstr[]);
|
||||
|
||||
/**
|
||||
* Needle is build from multiple alternatives. If one of
|
||||
* them is equal to haystack, return value is 1. If there
|
||||
* are no matches, but one alternative to needle is empty
|
||||
* string, return value is 0. If needle was not found, return
|
||||
* value is -1.
|
||||
*
|
||||
* @param needle e.g. "one|two" or "|one|two"
|
||||
* @param haystack e.g. "one", "two" or "invalid"
|
||||
* @return 1 if needle is found from the haystack
|
||||
* 0 if needle was empty string
|
||||
* -1 if needle was not found
|
||||
*/
|
||||
static int multiCompare( const char *needle, const char *haystack );
|
||||
|
||||
|
||||
unsigned int linenr() const;
|
||||
void linenr( unsigned int linenr );
|
||||
|
||||
unsigned int fileIndex() const;
|
||||
void fileIndex( unsigned int fileIndex );
|
||||
|
||||
TOKEN *next() const;
|
||||
|
||||
|
||||
/**
|
||||
* Delete tokens between begin and end. E.g. if begin = 1
|
||||
* and end = 5, tokens 2,3 and 4 would be erased.
|
||||
*
|
||||
* @param begin Tokens after this will be erased.
|
||||
* @param end Tokens before this will be erased.
|
||||
*/
|
||||
static void eraseTokens( TOKEN *begin, const TOKEN *end );
|
||||
|
||||
/**
|
||||
* Insert new token after this token. This function will handle
|
||||
* relations between next and previous token also.
|
||||
* @param str String for the new token.
|
||||
*/
|
||||
void insertToken( const char str[] );
|
||||
|
||||
TOKEN *previous() const;
|
||||
|
||||
|
||||
unsigned int varId() const;
|
||||
void varId( unsigned int id );
|
||||
|
||||
/**
|
||||
* For debugging purposes, prints token and all tokens
|
||||
* followed by it.
|
||||
* @param title Title for the printout or use default parameter or 0
|
||||
* for no title.
|
||||
*/
|
||||
void printOut( const char *title = 0 ) const;
|
||||
|
||||
private:
|
||||
void next( TOKEN *next );
|
||||
void previous( TOKEN *previous );
|
||||
|
||||
/**
|
||||
* Return true if pattern is e.g. "!!else".
|
||||
* See Match() for more info.
|
||||
*
|
||||
* @param pattern Pattern to match, e.g. "if ; !!else"
|
||||
* @return true if pattern starts with "!!" and contains 3
|
||||
* or more characters.
|
||||
*/
|
||||
static bool isNotPattern( const char *pattern );
|
||||
|
||||
std::string _str;
|
||||
char * _cstr;
|
||||
bool _isName;
|
||||
bool _isNumber;
|
||||
unsigned int _varId;
|
||||
TOKEN *_next;
|
||||
TOKEN *_previous;
|
||||
unsigned int _fileIndex;
|
||||
unsigned int _linenr;
|
||||
};
|
||||
|
||||
#endif // TOKEN_H
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
#ifndef TOKEN_H
|
||||
#define TOKEN_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class TOKEN
|
||||
{
|
||||
public:
|
||||
TOKEN();
|
||||
~TOKEN();
|
||||
void setstr( const char s[] );
|
||||
|
||||
const std::string &str() const
|
||||
{ return _str; }
|
||||
|
||||
const char *aaaa() const
|
||||
{ return _cstr; }
|
||||
|
||||
char aaaa0() const
|
||||
{ return _cstr[0]; }
|
||||
|
||||
char aaaa1() const
|
||||
{ return _cstr[1]; }
|
||||
|
||||
|
||||
/**
|
||||
* Combine two tokens that belong to each other.
|
||||
* Ex: "<" and "=" may become "<="
|
||||
*/
|
||||
void combineWithNext(const char str1[], const char str2[]);
|
||||
|
||||
/**
|
||||
* Unlink and delete next token.
|
||||
*/
|
||||
void deleteNext();
|
||||
|
||||
/**
|
||||
* Returns token in given index, related to this token.
|
||||
* For example index 1 would return next token, and 2
|
||||
* would return next from that one.
|
||||
*/
|
||||
const TOKEN *tokAt(int index) const;
|
||||
|
||||
const char *strAt(int index) const;
|
||||
|
||||
/**
|
||||
* Match given token (or list of tokens) to a pattern list.
|
||||
*
|
||||
* Possible patterns
|
||||
* "%any%" any token
|
||||
* "%var%" any token which is a name or type e.g. "hello" or "int"
|
||||
* "%num%" Any numeric token, e.g. "23"
|
||||
* "%str%" Any token starting with "-character (C-string).
|
||||
* "%var1%" Match with parameter varname1
|
||||
* "%var2%" Match with parameter varname2
|
||||
* "%varid%" Match with parameter varid
|
||||
* "[abc]" Any of the characters 'a' or 'b' or 'c'
|
||||
* "int|void|char" Any of the strings, int, void or char
|
||||
* "int|void|char|" Any of the strings, int, void or char or empty string
|
||||
* "!!else" No tokens or any token that is not "else".
|
||||
* "someRandomText" If token contains "someRandomText".
|
||||
*
|
||||
* The patterns can be also combined to compare to multiple tokens at once
|
||||
* by separating tokens with a space, e.g.
|
||||
* ") const|void {" will return true if first token is ')' next token is either
|
||||
* "const" or "void" and token after that is '{'. If even one of the tokens does not
|
||||
* match its pattern, false is returned.
|
||||
*
|
||||
* @param tok List of tokens to be compared to the pattern
|
||||
* @param pattern The pattern where tokens are compared, e.g. "const"
|
||||
* or ") const|volatile| {".
|
||||
* @param varname1 Used with pattern "%var1%" and "%var2%"
|
||||
* @param varname2 Used with pattern "%var1%" and "%var2%"
|
||||
* @return true if given token matches with given pattern
|
||||
* false if given token does not match with given pattern
|
||||
*/
|
||||
static bool Match(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0, unsigned int varid=0);
|
||||
|
||||
bool isName() const;
|
||||
bool isNumber() const;
|
||||
bool isStandardType() const;
|
||||
static const TOKEN *findmatch(const TOKEN *tok, const char pattern[], const char *varname1[]=0, const char *varname2[]=0);
|
||||
static const TOKEN *findtoken(const TOKEN *tok1, const char *tokenstr[]);
|
||||
|
||||
/**
|
||||
* Needle is build from multiple alternatives. If one of
|
||||
* them is equal to haystack, return value is 1. If there
|
||||
* are no matches, but one alternative to needle is empty
|
||||
* string, return value is 0. If needle was not found, return
|
||||
* value is -1.
|
||||
*
|
||||
* @param needle e.g. "one|two" or "|one|two"
|
||||
* @param haystack e.g. "one", "two" or "invalid"
|
||||
* @return 1 if needle is found from the haystack
|
||||
* 0 if needle was empty string
|
||||
* -1 if needle was not found
|
||||
*/
|
||||
static int multiCompare( const char *needle, const char *haystack );
|
||||
|
||||
|
||||
unsigned int linenr() const;
|
||||
void linenr( unsigned int linenr );
|
||||
|
||||
unsigned int fileIndex() const;
|
||||
void fileIndex( unsigned int fileIndex );
|
||||
|
||||
TOKEN *next() const;
|
||||
|
||||
|
||||
/**
|
||||
* Delete tokens between begin and end. E.g. if begin = 1
|
||||
* and end = 5, tokens 2,3 and 4 would be erased.
|
||||
*
|
||||
* @param begin Tokens after this will be erased.
|
||||
* @param end Tokens before this will be erased.
|
||||
*/
|
||||
static void eraseTokens( TOKEN *begin, const TOKEN *end );
|
||||
|
||||
/**
|
||||
* Insert new token after this token. This function will handle
|
||||
* relations between next and previous token also.
|
||||
* @param str String for the new token.
|
||||
*/
|
||||
void insertToken( const char str[] );
|
||||
|
||||
TOKEN *previous() const;
|
||||
|
||||
|
||||
unsigned int varId() const;
|
||||
void varId( unsigned int id );
|
||||
|
||||
/**
|
||||
* For debugging purposes, prints token and all tokens
|
||||
* followed by it.
|
||||
* @param title Title for the printout or use default parameter or 0
|
||||
* for no title.
|
||||
*/
|
||||
void printOut( const char *title = 0 ) const;
|
||||
|
||||
private:
|
||||
void next( TOKEN *next );
|
||||
void previous( TOKEN *previous );
|
||||
|
||||
/**
|
||||
* Return true if pattern is e.g. "!!else".
|
||||
* See Match() for more info.
|
||||
*
|
||||
* @param pattern Pattern to match, e.g. "if ; !!else"
|
||||
* @return true if pattern starts with "!!" and contains 3
|
||||
* or more characters.
|
||||
*/
|
||||
static bool isNotPattern( const char *pattern );
|
||||
|
||||
std::string _str;
|
||||
char * _cstr;
|
||||
bool _isName;
|
||||
bool _isNumber;
|
||||
unsigned int _varId;
|
||||
TOKEN *_next;
|
||||
TOKEN *_previous;
|
||||
unsigned int _fileIndex;
|
||||
unsigned int _linenr;
|
||||
};
|
||||
|
||||
#endif // TOKEN_H
|
||||
|
|
2838
tokenize.cpp
2838
tokenize.cpp
File diff suppressed because it is too large
Load Diff
278
tokenize.h
278
tokenize.h
|
@ -1,139 +1,139 @@
|
|||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef tokenizeH
|
||||
#define tokenizeH
|
||||
//---------------------------------------------------------------------------
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
#include "token.h"
|
||||
|
||||
class Tokenizer
|
||||
{
|
||||
private:
|
||||
// Deallocate lists..
|
||||
void DeallocateTokens();
|
||||
|
||||
/**
|
||||
* Helper function for "tokenize". This recursively parses into included header files.
|
||||
*/
|
||||
void tokenizeCode(std::istream &code, const unsigned int FileIndex=0);
|
||||
|
||||
public:
|
||||
Tokenizer();
|
||||
~Tokenizer();
|
||||
|
||||
/**
|
||||
* Tokenize code
|
||||
* @param code input stream for code
|
||||
* @param FileName The filename
|
||||
*/
|
||||
void tokenize(std::istream &code, const char FileName[]);
|
||||
|
||||
/** Set variable id */
|
||||
void setVarId();
|
||||
|
||||
/** Simplify tokenlist */
|
||||
void simplifyTokenList();
|
||||
|
||||
|
||||
// Helper functions for handling the tokens list..
|
||||
|
||||
static void deleteTokens(TOKEN *tok);
|
||||
static const char *getParameterName( const TOKEN *ftok, int par );
|
||||
|
||||
static bool SameFileName( const char fname1[], const char fname2[] );
|
||||
|
||||
|
||||
std::string fileLine( const TOKEN *tok ) const;
|
||||
|
||||
// Return size.
|
||||
int SizeOfType(const char type[]) const;
|
||||
|
||||
void initTokens();
|
||||
|
||||
const std::vector<std::string> *getFiles() const;
|
||||
|
||||
void fillFunctionList();
|
||||
const TOKEN *GetFunctionTokenByName( const char funcname[] ) const;
|
||||
const TOKEN *tokens() const;
|
||||
|
||||
|
||||
#ifndef UNIT_TESTING
|
||||
private:
|
||||
#endif
|
||||
|
||||
struct DefineSymbol
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
struct DefineSymbol *next;
|
||||
};
|
||||
|
||||
void Define(const char Name[], const char Value[]);
|
||||
|
||||
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno);
|
||||
|
||||
/** Simplify conditions
|
||||
* @return true if something is modified
|
||||
* false if nothing is done.
|
||||
*/
|
||||
bool simplifyConditions();
|
||||
|
||||
/** Simplify casts
|
||||
* @return true if something is modified
|
||||
* false if nothing is done.
|
||||
*/
|
||||
bool simplifyCasts();
|
||||
|
||||
/** Simplify function calls - constant return value
|
||||
* @return true if something is modified
|
||||
* false if nothing is done.
|
||||
*/
|
||||
bool simplifyFunctionReturn();
|
||||
|
||||
/**
|
||||
* A simplify function that replaces a variable with its value in cases
|
||||
* when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
|
||||
*
|
||||
* @param token The token list to check and modify.
|
||||
* @return true if modifications to token-list are done.
|
||||
* false if no modifications are done.
|
||||
*/
|
||||
bool simplifyKnownVariables();
|
||||
|
||||
TOKEN *_gettok(TOKEN *tok, int index);
|
||||
|
||||
void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n);
|
||||
|
||||
TOKEN *_tokensBack;
|
||||
std::map<std::string, unsigned int> _typeSize;
|
||||
std::vector<const TOKEN *> _functionList;
|
||||
std::vector<std::string> _files;
|
||||
struct DefineSymbol * _dsymlist;
|
||||
TOKEN *_tokens;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
/*
|
||||
* c++check - c/c++ syntax checking
|
||||
* Copyright (C) 2007 Daniel Marjamäki
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef tokenizeH
|
||||
#define tokenizeH
|
||||
//---------------------------------------------------------------------------
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "settings.h"
|
||||
#include "errorlogger.h"
|
||||
#include "token.h"
|
||||
|
||||
class Tokenizer
|
||||
{
|
||||
private:
|
||||
// Deallocate lists..
|
||||
void DeallocateTokens();
|
||||
|
||||
/**
|
||||
* Helper function for "tokenize". This recursively parses into included header files.
|
||||
*/
|
||||
void tokenizeCode(std::istream &code, const unsigned int FileIndex=0);
|
||||
|
||||
public:
|
||||
Tokenizer();
|
||||
~Tokenizer();
|
||||
|
||||
/**
|
||||
* Tokenize code
|
||||
* @param code input stream for code
|
||||
* @param FileName The filename
|
||||
*/
|
||||
void tokenize(std::istream &code, const char FileName[]);
|
||||
|
||||
/** Set variable id */
|
||||
void setVarId();
|
||||
|
||||
/** Simplify tokenlist */
|
||||
void simplifyTokenList();
|
||||
|
||||
|
||||
// Helper functions for handling the tokens list..
|
||||
|
||||
static void deleteTokens(TOKEN *tok);
|
||||
static const char *getParameterName( const TOKEN *ftok, int par );
|
||||
|
||||
static bool SameFileName( const char fname1[], const char fname2[] );
|
||||
|
||||
|
||||
std::string fileLine( const TOKEN *tok ) const;
|
||||
|
||||
// Return size.
|
||||
int SizeOfType(const char type[]) const;
|
||||
|
||||
void initTokens();
|
||||
|
||||
const std::vector<std::string> *getFiles() const;
|
||||
|
||||
void fillFunctionList();
|
||||
const TOKEN *GetFunctionTokenByName( const char funcname[] ) const;
|
||||
const TOKEN *tokens() const;
|
||||
|
||||
|
||||
#ifndef UNIT_TESTING
|
||||
private:
|
||||
#endif
|
||||
|
||||
struct DefineSymbol
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
struct DefineSymbol *next;
|
||||
};
|
||||
|
||||
void Define(const char Name[], const char Value[]);
|
||||
|
||||
void addtoken(const char str[], const unsigned int lineno, const unsigned int fileno);
|
||||
|
||||
/** Simplify conditions
|
||||
* @return true if something is modified
|
||||
* false if nothing is done.
|
||||
*/
|
||||
bool simplifyConditions();
|
||||
|
||||
/** Simplify casts
|
||||
* @return true if something is modified
|
||||
* false if nothing is done.
|
||||
*/
|
||||
bool simplifyCasts();
|
||||
|
||||
/** Simplify function calls - constant return value
|
||||
* @return true if something is modified
|
||||
* false if nothing is done.
|
||||
*/
|
||||
bool simplifyFunctionReturn();
|
||||
|
||||
/**
|
||||
* A simplify function that replaces a variable with its value in cases
|
||||
* when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
|
||||
*
|
||||
* @param token The token list to check and modify.
|
||||
* @return true if modifications to token-list are done.
|
||||
* false if no modifications are done.
|
||||
*/
|
||||
bool simplifyKnownVariables();
|
||||
|
||||
TOKEN *_gettok(TOKEN *tok, int index);
|
||||
|
||||
void InsertTokens(TOKEN *dest, TOKEN *src, unsigned int n);
|
||||
|
||||
TOKEN *_tokensBack;
|
||||
std::map<std::string, unsigned int> _typeSize;
|
||||
std::vector<const TOKEN *> _functionList;
|
||||
std::vector<std::string> _files;
|
||||
struct DefineSymbol * _dsymlist;
|
||||
TOKEN *_tokens;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue