Merge branch 'master' of http://github.com/danmar/cppcheck
This commit is contained in:
commit
8ad863d650
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
||||||
# This file is generated by tools/dmake, do not edit.
|
# This file is generated by tools/dmake, do not edit.
|
||||||
|
|
||||||
ifndef CXXFLAGS
|
ifndef CXXFLAGS
|
||||||
CXXFLAGS=-Wall -Wextra -Wshadow -pedantic -Wno-long-long -Wfloat-equal -Wcast-qual -Wsign-conversion -g
|
CXXFLAGS=-DHAVE_DEPENDENCIES -Wall -Wextra -Wshadow -pedantic -Wno-long-long -Wfloat-equal -Wcast-qual -Wsign-conversion -g
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef CXX
|
ifndef CXX
|
||||||
|
|
|
@ -5,6 +5,7 @@ INCLUDEPATH += . ../lib
|
||||||
OBJECTS_DIR = temp
|
OBJECTS_DIR = temp
|
||||||
CONFIG += warn_on
|
CONFIG += warn_on
|
||||||
CONFIG -= qt app_bundle
|
CONFIG -= qt app_bundle
|
||||||
|
DEFINES += HAVE_DEPENDENCIES
|
||||||
|
|
||||||
BASEPATH = ../externals/tinyxml/
|
BASEPATH = ../externals/tinyxml/
|
||||||
include($$PWD/../externals/tinyxml/tinyxml.pri)
|
include($$PWD/../externals/tinyxml/tinyxml.pri)
|
||||||
|
|
|
@ -28,8 +28,10 @@
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "filelister.h"
|
#include "filelister.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DEPENDENCIES
|
||||||
// xml is used in rules
|
// xml is used in rules
|
||||||
#include <tinyxml.h>
|
#include <tinyxml.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static void AddFilesToList(const std::string& FileList, std::vector<std::string>& PathNames)
|
static void AddFilesToList(const std::string& FileList, std::vector<std::string>& PathNames)
|
||||||
{
|
{
|
||||||
|
@ -503,6 +505,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
|
||||||
_settings->_showtime = SHOWTIME_NONE;
|
_settings->_showtime = SHOWTIME_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DEPENDENCIES
|
||||||
// Rule given at command line
|
// Rule given at command line
|
||||||
else if (strncmp(argv[i], "--rule=", 7) == 0)
|
else if (strncmp(argv[i], "--rule=", 7) == 0)
|
||||||
{
|
{
|
||||||
|
@ -549,6 +552,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Print help
|
// Print help
|
||||||
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
|
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
|
||||||
|
|
|
@ -213,14 +213,11 @@ void MainWindow::DoCheckFiles(const QStringList &files)
|
||||||
QDir inf(mCurrentDirectory);
|
QDir inf(mCurrentDirectory);
|
||||||
const QString checkPath = inf.canonicalPath();
|
const QString checkPath = inf.canonicalPath();
|
||||||
mSettings->setValue(SETTINGS_CHECK_PATH, checkPath);
|
mSettings->setValue(SETTINGS_CHECK_PATH, checkPath);
|
||||||
EnableCheckButtons(false);
|
|
||||||
mUI.mActionSettings->setEnabled(false);
|
|
||||||
mUI.mActionOpenXML->setEnabled(false);
|
|
||||||
mUI.mResults->SetCheckDirectory(checkPath);
|
|
||||||
|
|
||||||
|
CheckLockDownUI(); // lock UI while checking
|
||||||
|
|
||||||
|
mUI.mResults->SetCheckDirectory(checkPath);
|
||||||
Settings checkSettings = GetCppcheckSettings();
|
Settings checkSettings = GetCppcheckSettings();
|
||||||
EnableProjectActions(false);
|
|
||||||
EnableProjectOpenActions(false);
|
|
||||||
mThread->Check(checkSettings, false);
|
mThread->Check(checkSettings, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,6 +397,15 @@ void MainWindow::CheckDone()
|
||||||
QApplication::alert(this, 3000);
|
QApplication::alert(this, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::CheckLockDownUI()
|
||||||
|
{
|
||||||
|
EnableCheckButtons(false);
|
||||||
|
mUI.mActionSettings->setEnabled(false);
|
||||||
|
mUI.mActionOpenXML->setEnabled(false);
|
||||||
|
EnableProjectActions(false);
|
||||||
|
EnableProjectOpenActions(false);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::ProgramSettings()
|
void MainWindow::ProgramSettings()
|
||||||
{
|
{
|
||||||
SettingsDialog dialog(mSettings, mApplications, mTranslation, this);
|
SettingsDialog dialog(mSettings, mApplications, mTranslation, this);
|
||||||
|
@ -418,7 +424,7 @@ void MainWindow::ProgramSettings()
|
||||||
void MainWindow::ReCheck()
|
void MainWindow::ReCheck()
|
||||||
{
|
{
|
||||||
ClearResults();
|
ClearResults();
|
||||||
EnableCheckButtons(false);
|
CheckLockDownUI(); // lock UI while checking
|
||||||
|
|
||||||
const int filesCount = mThread->GetPreviousFilesCount();
|
const int filesCount = mThread->GetPreviousFilesCount();
|
||||||
Q_ASSERT(filesCount > 0); // If no files should not be able to recheck
|
Q_ASSERT(filesCount > 0); // If no files should not be able to recheck
|
||||||
|
|
|
@ -206,6 +206,12 @@ protected slots:
|
||||||
*/
|
*/
|
||||||
void CheckDone();
|
void CheckDone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Lock down UI while checking
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void CheckLockDownUI();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Slot for enabling save and clear button
|
* @brief Slot for enabling save and clear button
|
||||||
*
|
*
|
||||||
|
|
|
@ -87,8 +87,9 @@ QStandardItem *ResultsTree::CreateNormalItem(const QString &name)
|
||||||
|
|
||||||
QStandardItem *ResultsTree::CreateLineNumberItem(const QString &linenumber)
|
QStandardItem *ResultsTree::CreateLineNumberItem(const QString &linenumber)
|
||||||
{
|
{
|
||||||
QStandardItem *item = new QStandardItem(linenumber);
|
QStandardItem *item = new QStandardItem();
|
||||||
item->setData(linenumber, Qt::ToolTipRole);
|
item->setData(QVariant(linenumber.toULongLong()), Qt::DisplayRole);
|
||||||
|
item->setToolTip(linenumber);
|
||||||
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||||
item->setEditable(false);
|
item->setEditable(false);
|
||||||
return item;
|
return item;
|
||||||
|
|
|
@ -464,6 +464,11 @@ void CheckBufferOverrun::parse_for_body(const Token *tok2, const ArrayInfo &arra
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: try to reduce false negatives. This is just a quick fix
|
||||||
|
// for TestBufferOverrun::array_index_for_question
|
||||||
|
if (tok2->str() == "?")
|
||||||
|
break;
|
||||||
|
|
||||||
if (Token::Match(tok2, "if|switch"))
|
if (Token::Match(tok2, "if|switch"))
|
||||||
{
|
{
|
||||||
if (bailoutIfSwitch(tok2, arrayInfo.varid))
|
if (bailoutIfSwitch(tok2, arrayInfo.varid))
|
||||||
|
|
|
@ -610,7 +610,9 @@ void CheckClass::privateFunctions()
|
||||||
if (!func->hasBody)
|
if (!func->hasBody)
|
||||||
{
|
{
|
||||||
// empty private copy constructors and assignment operators are OK
|
// empty private copy constructors and assignment operators are OK
|
||||||
if ((func->type == Function::eCopyConstructor || func->type == Function::eOperatorEqual) && func->access == Private)
|
if ((func->type == Function::eCopyConstructor ||
|
||||||
|
func->type == Function::eOperatorEqual) &&
|
||||||
|
func->access == Private)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
whole = false;
|
whole = false;
|
||||||
|
@ -630,88 +632,28 @@ void CheckClass::privateFunctions()
|
||||||
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func)
|
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func)
|
||||||
{
|
{
|
||||||
// Get private functions..
|
// Get private functions..
|
||||||
if (func->type == Function::eFunction &&
|
if (func->type == Function::eFunction && func->access == Private)
|
||||||
func->access == Private && func->hasBody)
|
|
||||||
FuncList.push_back(func->tokenDef);
|
FuncList.push_back(func->tokenDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all private functions are used..
|
// Check that all private functions are used..
|
||||||
bool HasFuncImpl = false;
|
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func)
|
||||||
bool inclass = false;
|
|
||||||
int indent_level = 0;
|
|
||||||
for (const Token *ftok = _tokenizer->tokens(); ftok; ftok = ftok->next())
|
|
||||||
{
|
{
|
||||||
if (ftok->str() == "{")
|
const Token *ftok = func->arg->link()->next();
|
||||||
++indent_level;
|
while (ftok->str() != "{")
|
||||||
else if (ftok->str() == "}")
|
|
||||||
{
|
|
||||||
if (indent_level > 0)
|
|
||||||
--indent_level;
|
|
||||||
if (indent_level == 0)
|
|
||||||
inclass = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (ftok->str() == "class" &&
|
|
||||||
ftok->next()->str() == classname &&
|
|
||||||
Token::Match(ftok->tokAt(2), ":|{"))
|
|
||||||
{
|
|
||||||
indent_level = 0;
|
|
||||||
inclass = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check member class functions to see what functions are used..
|
|
||||||
else if ((inclass && indent_level == 1 && Token::Match(ftok, "%var% (")) ||
|
|
||||||
(ftok->str() == classname && Token::Match(ftok->next(), ":: ~| %var% (")))
|
|
||||||
{
|
|
||||||
while (ftok && ftok->str() != ")")
|
|
||||||
ftok = ftok->next();
|
ftok = ftok->next();
|
||||||
if (!ftok)
|
const Token *etok = ftok->link();
|
||||||
break;
|
|
||||||
if (Token::Match(ftok, ") : %var% ("))
|
for (; ftok != etok; ftok = ftok->next())
|
||||||
{
|
{
|
||||||
while (!Token::Match(ftok->next(), "[{};]"))
|
if (Token::Match(ftok, "%var% ("))
|
||||||
{
|
|
||||||
if (Token::Match(ftok, "::|,|( %var% ,|)"))
|
|
||||||
{
|
{
|
||||||
// Remove function from FuncList
|
// Remove function from FuncList
|
||||||
std::list<const Token *>::iterator it = FuncList.begin();
|
std::list<const Token *>::iterator it = FuncList.begin();
|
||||||
while (it != FuncList.end())
|
while (it != FuncList.end())
|
||||||
{
|
{
|
||||||
if (ftok->next()->str() == (*it)->str())
|
if (ftok->str() == (*it)->str())
|
||||||
FuncList.erase(it++);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ftok = ftok->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!Token::Match(ftok, ") const| {"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ftok->fileIndex() == 0)
|
|
||||||
HasFuncImpl = true;
|
|
||||||
|
|
||||||
// Parse function..
|
|
||||||
int indentlevel2 = 0;
|
|
||||||
for (const Token *tok2 = ftok; tok2; tok2 = tok2->next())
|
|
||||||
{
|
|
||||||
if (tok2->str() == "{")
|
|
||||||
++indentlevel2;
|
|
||||||
else if (tok2->str() == "}")
|
|
||||||
{
|
|
||||||
--indentlevel2;
|
|
||||||
if (indentlevel2 < 1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (Token::Match(tok2, "%var% ("))
|
|
||||||
{
|
|
||||||
// Remove function from FuncList
|
|
||||||
std::list<const Token *>::iterator it = FuncList.begin();
|
|
||||||
while (it != FuncList.end())
|
|
||||||
{
|
|
||||||
if (tok2->str() == (*it)->str())
|
|
||||||
FuncList.erase(it++);
|
FuncList.erase(it++);
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
|
@ -719,9 +661,8 @@ void CheckClass::privateFunctions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
while (HasFuncImpl && !FuncList.empty())
|
while (!FuncList.empty())
|
||||||
{
|
{
|
||||||
// Final check; check if the function pointer is used somewhere..
|
// Final check; check if the function pointer is used somewhere..
|
||||||
const std::string _pattern("return|(|)|,|= " + FuncList.front()->str());
|
const std::string _pattern("return|(|)|,|= " + FuncList.front()->str());
|
||||||
|
|
|
@ -34,6 +34,38 @@ CheckOther instance;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CheckOther::checkIncrementBoolean()
|
||||||
|
{
|
||||||
|
if (!_settings->_checkCodingStyle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||||
|
{
|
||||||
|
if (Token::Match(tok, "%var% ++"))
|
||||||
|
{
|
||||||
|
if (tok->varId())
|
||||||
|
{
|
||||||
|
const Token *declTok = Token::findmatch(_tokenizer->tokens(), "bool %varid%", tok->varId());
|
||||||
|
if (declTok)
|
||||||
|
incrementBooleanError(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOther::incrementBooleanError(const Token *tok)
|
||||||
|
{
|
||||||
|
reportError(
|
||||||
|
tok,
|
||||||
|
Severity::style,
|
||||||
|
"incrementboolean",
|
||||||
|
"The use of a variable of type bool with the ++ postfix operator is always true and deprecated by the C++ Standard.\n"
|
||||||
|
"The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
void CheckOther::clarifyCalculation()
|
void CheckOther::clarifyCalculation()
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,6 +88,7 @@ public:
|
||||||
checkOther.checkCatchExceptionByValue();
|
checkOther.checkCatchExceptionByValue();
|
||||||
checkOther.checkMemsetZeroBytes();
|
checkOther.checkMemsetZeroBytes();
|
||||||
checkOther.checkIncorrectStringCompare();
|
checkOther.checkIncorrectStringCompare();
|
||||||
|
checkOther.checkIncrementBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Clarify calculation for ".. a * b ? .." */
|
/** @brief Clarify calculation for ".. a * b ? .." */
|
||||||
|
@ -184,6 +185,9 @@ public:
|
||||||
/** @brief %Check for using bad usage of strncmp and substr */
|
/** @brief %Check for using bad usage of strncmp and substr */
|
||||||
void checkIncorrectStringCompare();
|
void checkIncorrectStringCompare();
|
||||||
|
|
||||||
|
/** @brief %Check for using postfix increment on bool */
|
||||||
|
void checkIncrementBoolean();
|
||||||
|
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void cstyleCastError(const Token *tok);
|
void cstyleCastError(const Token *tok);
|
||||||
void dangerousUsageStrtolError(const Token *tok);
|
void dangerousUsageStrtolError(const Token *tok);
|
||||||
|
@ -209,6 +213,7 @@ public:
|
||||||
void memsetZeroBytesError(const Token *tok, const std::string &varname);
|
void memsetZeroBytesError(const Token *tok, const std::string &varname);
|
||||||
void sizeofForArrayParameterError(const Token *tok);
|
void sizeofForArrayParameterError(const Token *tok);
|
||||||
void incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string, const std::string &len);
|
void incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string, const std::string &len);
|
||||||
|
void incrementBooleanError(const Token *tok);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -249,6 +254,7 @@ public:
|
||||||
c.memsetZeroBytesError(0, "varname");
|
c.memsetZeroBytesError(0, "varname");
|
||||||
c.clarifyCalculationError(0);
|
c.clarifyCalculationError(0);
|
||||||
c.incorrectStringCompareError(0, "substr", "\"Hello World\"", "12");
|
c.incorrectStringCompareError(0, "substr", "\"Hello World\"", "12");
|
||||||
|
c.incrementBooleanError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string myName() const
|
std::string myName() const
|
||||||
|
@ -289,6 +295,7 @@ public:
|
||||||
"* mutual exclusion over || always evaluating to true\n"
|
"* mutual exclusion over || always evaluating to true\n"
|
||||||
"* exception caught by value instead of by reference\n"
|
"* exception caught by value instead of by reference\n"
|
||||||
"* Clarify calculation with parantheses\n"
|
"* Clarify calculation with parantheses\n"
|
||||||
|
"* using increment on boolean\n"
|
||||||
|
|
||||||
// optimisations
|
// optimisations
|
||||||
"* optimisation: detect post increment/decrement\n";
|
"* optimisation: detect post increment/decrement\n";
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
#ifndef __BORLANDC__
|
#ifdef HAVE_DEPENDENCIES
|
||||||
#define PCRE_STATIC
|
#define PCRE_STATIC
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -309,7 +309,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||||
(*it)->runSimplifiedChecks(&_tokenizer, &_settings, this);
|
(*it)->runSimplifiedChecks(&_tokenizer, &_settings, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __BORLANDC__
|
#ifdef HAVE_DEPENDENCIES
|
||||||
// Are there extra rules?
|
// Are there extra rules?
|
||||||
if (!_settings.rules.empty())
|
if (!_settings.rules.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,39 +109,19 @@ static std::string join(const std::list<std::string> &list, char separator)
|
||||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||||
std::string Preprocessor::read(std::istream &istr, const std::string &filename, Settings *settings)
|
std::string Preprocessor::read(std::istream &istr, const std::string &filename, Settings *settings)
|
||||||
{
|
{
|
||||||
// Get filedata from stream..
|
// ------------------------------------------------------------------------------------------
|
||||||
bool ignoreSpace = true;
|
//
|
||||||
|
|
||||||
// need space.. #if( => #if (
|
|
||||||
bool needSpace = false;
|
|
||||||
|
|
||||||
// handling <backspace><newline>
|
// handling <backspace><newline>
|
||||||
// when this is encountered the <backspace><newline> will be "skipped".
|
// when this is encountered the <backspace><newline> will be "skipped".
|
||||||
// on the next <newline>, extra newlines will be added
|
// on the next <newline>, extra newlines will be added
|
||||||
unsigned int newlines = 0;
|
|
||||||
|
|
||||||
std::ostringstream code;
|
std::ostringstream code;
|
||||||
|
unsigned int newlines = 0;
|
||||||
for (unsigned char ch = readChar(istr); istr.good(); ch = readChar(istr))
|
for (unsigned char ch = readChar(istr); istr.good(); ch = readChar(istr))
|
||||||
{
|
{
|
||||||
// Replace assorted special chars with spaces..
|
// Replace assorted special chars with spaces..
|
||||||
if (((ch & 0x80) == 0) && (ch != '\n') && (std::isspace(ch) || std::iscntrl(ch)))
|
if (((ch & 0x80) == 0) && (ch != '\n') && (std::isspace(ch) || std::iscntrl(ch)))
|
||||||
ch = ' ';
|
ch = ' ';
|
||||||
|
|
||||||
// Skip spaces after ' ' and after '#'
|
|
||||||
if (ch == ' ' && ignoreSpace)
|
|
||||||
continue;
|
|
||||||
ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '\n');
|
|
||||||
|
|
||||||
if (needSpace)
|
|
||||||
{
|
|
||||||
if (ch == '(' || ch == '!')
|
|
||||||
code << " ";
|
|
||||||
else if (!std::isalpha(ch))
|
|
||||||
needSpace = false;
|
|
||||||
}
|
|
||||||
if (ch == '#')
|
|
||||||
needSpace = true;
|
|
||||||
|
|
||||||
// <backspace><newline>..
|
// <backspace><newline>..
|
||||||
// for gcc-compatibility the trailing spaces should be ignored
|
// for gcc-compatibility the trailing spaces should be ignored
|
||||||
// for vs-compatibility the trailing spaces should be kept
|
// for vs-compatibility the trailing spaces should be kept
|
||||||
|
@ -178,8 +158,6 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename,
|
||||||
else
|
else
|
||||||
code << "\\";
|
code << "\\";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just some code..
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
code << char(ch);
|
code << char(ch);
|
||||||
|
@ -192,8 +170,124 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::string result = code.str();
|
||||||
|
code.str("");
|
||||||
|
|
||||||
return removeParantheses(removeComments(code.str(), filename, settings));
|
// ------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Remove all comments..
|
||||||
|
result = removeComments(result, filename, settings);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Clean up all preprocessor statements
|
||||||
|
result = preprocessCleanupDirectives(result);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Clean up preprocessor #if statements with Parantheses
|
||||||
|
result = removeParantheses(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Preprocessor::preprocessCleanupDirectives(const std::string &processedFile) const
|
||||||
|
{
|
||||||
|
std::ostringstream code;
|
||||||
|
std::istringstream sstr(processedFile);
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(sstr, line))
|
||||||
|
{
|
||||||
|
// Trim lines..
|
||||||
|
if (!line.empty() && line[0] == ' ')
|
||||||
|
line.erase(0, line.find_first_not_of(" "));
|
||||||
|
if (!line.empty() && line[line.size()-1] == ' ')
|
||||||
|
line.erase(line.find_last_not_of(" ") + 1);
|
||||||
|
|
||||||
|
// Preprocessor
|
||||||
|
if (!line.empty() && line[0] == '#')
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ESC_NONE,
|
||||||
|
ESC_SINGLE,
|
||||||
|
ESC_DOUBLE
|
||||||
|
} escapeStatus = ESC_NONE;
|
||||||
|
|
||||||
|
char prev = ' '; // hack to make it skip spaces between # and the directive
|
||||||
|
code << "#";
|
||||||
|
std::string::const_iterator i = line.begin();
|
||||||
|
i++;
|
||||||
|
|
||||||
|
// need space.. #if( => #if (
|
||||||
|
bool needSpace = true;
|
||||||
|
while (i != line.end())
|
||||||
|
{
|
||||||
|
// disable esc-mode
|
||||||
|
if (escapeStatus != ESC_NONE)
|
||||||
|
{
|
||||||
|
if (prev != '\\' && escapeStatus == ESC_SINGLE && *i == '\'')
|
||||||
|
{
|
||||||
|
escapeStatus = ESC_NONE;
|
||||||
|
}
|
||||||
|
if (prev != '\\' && escapeStatus == ESC_DOUBLE && *i == '"')
|
||||||
|
{
|
||||||
|
escapeStatus = ESC_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// enable esc-mode
|
||||||
|
if (escapeStatus == ESC_NONE && *i == '"')
|
||||||
|
escapeStatus = ESC_DOUBLE;
|
||||||
|
if (escapeStatus == ESC_NONE && *i == '\'')
|
||||||
|
escapeStatus = ESC_SINGLE;
|
||||||
|
}
|
||||||
|
// skip double whitespace between arguments
|
||||||
|
if (escapeStatus == ESC_NONE && prev == ' ' && *i == ' ')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Convert #if( to "#if ("
|
||||||
|
if (escapeStatus == ESC_NONE)
|
||||||
|
{
|
||||||
|
if (needSpace)
|
||||||
|
{
|
||||||
|
if (*i == '(' || *i == '!')
|
||||||
|
code << " ";
|
||||||
|
else if (!std::isalpha(*i))
|
||||||
|
needSpace = false;
|
||||||
|
}
|
||||||
|
if (*i == '#')
|
||||||
|
needSpace = true;
|
||||||
|
}
|
||||||
|
code << *i;
|
||||||
|
if (escapeStatus != ESC_NONE && prev == '\\' && *i == '\\')
|
||||||
|
{
|
||||||
|
prev = ' ';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev = *i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (escapeStatus != ESC_NONE)
|
||||||
|
{
|
||||||
|
// unmatched quotes.. compiler should probably complain about this..
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Do not mess with regular code..
|
||||||
|
code << line;
|
||||||
|
}
|
||||||
|
code << (sstr.eof()?"":"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return code.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasbom(const std::string &str)
|
static bool hasbom(const std::string &str)
|
||||||
|
@ -668,9 +762,6 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
|
||||||
|
|
||||||
processedFile = read(srcCodeStream, filename, _settings);
|
processedFile = read(srcCodeStream, filename, _settings);
|
||||||
|
|
||||||
// normalize the whitespaces of the file
|
|
||||||
preprocessWhitespaces(processedFile);
|
|
||||||
|
|
||||||
// Remove asm(...)
|
// Remove asm(...)
|
||||||
removeAsm(processedFile);
|
removeAsm(processedFile);
|
||||||
|
|
||||||
|
@ -1460,7 +1551,8 @@ std::string Preprocessor::getcode(const std::string &filedata, std::string cfg,
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match && line.compare(0, 8, "#define ") == 0)
|
if (!match && (line.compare(0, 8, "#define ") == 0 ||
|
||||||
|
line.compare(0, 6, "#undef") == 0))
|
||||||
{
|
{
|
||||||
// Remove define that is not part of this configuration
|
// Remove define that is not part of this configuration
|
||||||
line = "";
|
line = "";
|
||||||
|
@ -1635,15 +1727,7 @@ void Preprocessor::handleIncludes(std::string &code, const std::string &filePath
|
||||||
|
|
||||||
if (!processedFile.empty())
|
if (!processedFile.empty())
|
||||||
{
|
{
|
||||||
// Replace all tabs with spaces..
|
|
||||||
std::replace(processedFile.begin(), processedFile.end(), '\t', ' ');
|
|
||||||
|
|
||||||
// Remove all indentation..
|
|
||||||
if (!processedFile.empty() && processedFile[0] == ' ')
|
|
||||||
processedFile.erase(0, processedFile.find_first_not_of(" "));
|
|
||||||
|
|
||||||
// Remove space characters that are after or before new line character
|
// Remove space characters that are after or before new line character
|
||||||
processedFile = removeSpaceNearNL(processedFile);
|
|
||||||
processedFile = "#file \"" + filename + "\"\n" + processedFile + "\n#endfile";
|
processedFile = "#file \"" + filename + "\"\n" + processedFile + "\n#endfile";
|
||||||
code.insert(pos, processedFile);
|
code.insert(pos, processedFile);
|
||||||
|
|
||||||
|
@ -2048,12 +2132,14 @@ public:
|
||||||
|
|
||||||
else if (_params.empty())
|
else if (_params.empty())
|
||||||
{
|
{
|
||||||
std::string::size_type pos = _macro.find(" ");
|
std::string::size_type pos = _macro.find_first_of(" \"");
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
macrocode = "";
|
macrocode = "";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
macrocode = _macro.substr(pos + 1);
|
if (_macro[pos] == ' ')
|
||||||
|
pos++;
|
||||||
|
macrocode = _macro.substr(pos);
|
||||||
if ((pos = macrocode.find_first_of("\r\n")) != std::string::npos)
|
if ((pos = macrocode.find_first_of("\r\n")) != std::string::npos)
|
||||||
macrocode.erase(pos);
|
macrocode.erase(pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,6 @@ public:
|
||||||
* @param processedFile The data to be processed
|
* @param processedFile The data to be processed
|
||||||
*/
|
*/
|
||||||
static void preprocessWhitespaces(std::string &processedFile);
|
static void preprocessWhitespaces(std::string &processedFile);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -152,6 +151,12 @@ protected:
|
||||||
*/
|
*/
|
||||||
static std::string removeParantheses(const std::string &str);
|
static std::string removeParantheses(const std::string &str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clean up #-preprocessor lines (only)
|
||||||
|
* @param processedFile The data to be processed
|
||||||
|
*/
|
||||||
|
std::string preprocessCleanupDirectives(const std::string &processedFile) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string between double quote characters or \< \> characters.
|
* Returns the string between double quote characters or \< \> characters.
|
||||||
* @param str e.g. \code#include "menu.h"\endcode or \code#include <menu.h>\endcode
|
* @param str e.g. \code#include "menu.h"\endcode or \code#include <menu.h>\endcode
|
||||||
|
|
|
@ -509,7 +509,7 @@ void Tokenizer::duplicateDeclarationError(const Token *tok1, const Token *tok2,
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this statement is a duplicate definition
|
// check if this statement is a duplicate definition
|
||||||
bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name)
|
bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef)
|
||||||
{
|
{
|
||||||
// check for an end of definition
|
// check for an end of definition
|
||||||
const Token * tok = *tokPtr;
|
const Token * tok = *tokPtr;
|
||||||
|
@ -624,7 +624,11 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name)
|
||||||
int level = (tok->previous()->str() == "}") ? 1 : 0;
|
int level = (tok->previous()->str() == "}") ? 1 : 0;
|
||||||
while (tok && tok->previous() && (!Token::Match(tok->previous(), ";|{") || (level != 0)))
|
while (tok && tok->previous() && (!Token::Match(tok->previous(), ";|{") || (level != 0)))
|
||||||
{
|
{
|
||||||
if (tok->previous()->str() == "typedef")
|
if (tok->previous()->str() == "}")
|
||||||
|
{
|
||||||
|
tok = tok->previous()->link();
|
||||||
|
}
|
||||||
|
else if (tok->previous()->str() == "typedef")
|
||||||
{
|
{
|
||||||
duplicateTypedefError(*tokPtr, name, "Typedef");
|
duplicateTypedefError(*tokPtr, name, "Typedef");
|
||||||
return true;
|
return true;
|
||||||
|
@ -636,7 +640,14 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name)
|
||||||
}
|
}
|
||||||
else if (tok->previous()->str() == "struct")
|
else if (tok->previous()->str() == "struct")
|
||||||
{
|
{
|
||||||
if (tok->next()->str() != ";")
|
if (tok->strAt(-2) == "typedef" &&
|
||||||
|
tok->next()->str() == "{" &&
|
||||||
|
typeDef->strAt(3) != "{")
|
||||||
|
{
|
||||||
|
// declaration after forward declaration
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (tok->next()->str() != ";")
|
||||||
{
|
{
|
||||||
duplicateTypedefError(*tokPtr, name, "Struct");
|
duplicateTypedefError(*tokPtr, name, "Struct");
|
||||||
return true;
|
return true;
|
||||||
|
@ -1373,7 +1384,7 @@ void Tokenizer::simplifyTypedef()
|
||||||
{
|
{
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
}
|
}
|
||||||
else if (duplicateTypedef(&tok2, typeName))
|
else if (duplicateTypedef(&tok2, typeName, typeDef))
|
||||||
{
|
{
|
||||||
exitScope = scope;
|
exitScope = scope;
|
||||||
|
|
||||||
|
@ -6226,6 +6237,25 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
Token *tok3 = NULL;
|
Token *tok3 = NULL;
|
||||||
bool valueIsPointer = false;
|
bool valueIsPointer = false;
|
||||||
|
|
||||||
|
if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, pointeralias, indentlevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok2)
|
||||||
|
tok = tok2->previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token **_tok3, std::string &value, unsigned int &valueVarId, bool &valueIsPointer, bool floatvar)
|
||||||
|
{
|
||||||
|
Token *tok2 = *_tok2;
|
||||||
|
Token *tok3 = *_tok3;
|
||||||
|
|
||||||
if (Token::Match(tok2->tokAt(-2), "for ( %varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid))
|
if (Token::Match(tok2->tokAt(-2), "for ( %varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid))
|
||||||
{
|
{
|
||||||
// is there a "break" in the for loop?
|
// is there a "break" in the for loop?
|
||||||
|
@ -6248,7 +6278,7 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasbreak)
|
if (hasbreak)
|
||||||
break;
|
return false;
|
||||||
|
|
||||||
// no break => the value of the counter value is known after the for loop..
|
// no break => the value of the counter value is known after the for loop..
|
||||||
const std::string compareop = tok2->strAt(5);
|
const std::string compareop = tok2->strAt(5);
|
||||||
|
@ -6286,7 +6316,7 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
|
|
||||||
// float value should contain a "."
|
// float value should contain a "."
|
||||||
else if (tok2->tokAt(2)->isNumber() &&
|
else if (tok2->tokAt(2)->isNumber() &&
|
||||||
floatvars.find(tok2->varId()) != floatvars.end() &&
|
floatvar &&
|
||||||
value.find(".") == std::string::npos)
|
value.find(".") == std::string::npos)
|
||||||
{
|
{
|
||||||
value += ".0";
|
value += ".0";
|
||||||
|
@ -6297,8 +6327,17 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
|
|
||||||
tok3 = tok2->next();
|
tok3 = tok2->next();
|
||||||
}
|
}
|
||||||
|
*_tok2 = tok2;
|
||||||
|
*_tok3 = tok3;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel)
|
||||||
|
{
|
||||||
|
bool ret = false;;
|
||||||
|
|
||||||
Token* bailOutFromLoop = 0;
|
Token* bailOutFromLoop = 0;
|
||||||
int indentlevel3 = indentlevel; // indentlevel for tok3
|
int indentlevel3 = indentlevel;
|
||||||
bool ret3 = false;
|
bool ret3 = false;
|
||||||
for (; tok3; tok3 = tok3->next())
|
for (; tok3; tok3 = tok3->next())
|
||||||
{
|
{
|
||||||
|
@ -6311,11 +6350,11 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
--indentlevel3;
|
--indentlevel3;
|
||||||
if (indentlevel3 < indentlevel)
|
if (indentlevel3 < indentlevel)
|
||||||
{
|
{
|
||||||
if (Token::Match(tok2->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") &&
|
if (Token::Match((*tok2)->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") &&
|
||||||
tok2->tokAt(-5)->str() == tok2->tokAt(-3)->str())
|
(*tok2)->tokAt(-5)->str() == (*tok2)->tokAt(-3)->str())
|
||||||
{
|
{
|
||||||
tok2 = tok2->tokAt(-4);
|
(*tok2) = (*tok2)->tokAt(-4);
|
||||||
Token::eraseTokens(tok2, tok2->tokAt(5));
|
Token::eraseTokens((*tok2), (*tok2)->tokAt(5));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -6647,10 +6686,10 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
tok3->deleteNext();
|
tok3->deleteNext();
|
||||||
}
|
}
|
||||||
incdec(value, op);
|
incdec(value, op);
|
||||||
if (!Token::simpleMatch(tok2->tokAt(-2), "for ("))
|
if (!Token::simpleMatch((*tok2)->tokAt(-2), "for ("))
|
||||||
{
|
{
|
||||||
tok2->tokAt(2)->str(value);
|
(*tok2)->tokAt(2)->str(value);
|
||||||
tok2->tokAt(2)->varId(valueVarId);
|
(*tok2)->tokAt(2)->varId(valueVarId);
|
||||||
}
|
}
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
@ -6659,8 +6698,8 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
!Token::Match(tok3->tokAt(3), "[.[]"))
|
!Token::Match(tok3->tokAt(3), "[.[]"))
|
||||||
{
|
{
|
||||||
incdec(value, tok3->strAt(1));
|
incdec(value, tok3->strAt(1));
|
||||||
tok2->tokAt(2)->str(value);
|
(*tok2)->tokAt(2)->str(value);
|
||||||
tok2->tokAt(2)->varId(valueVarId);
|
(*tok2)->tokAt(2)->varId(valueVarId);
|
||||||
if (Token::Match(tok3, "[;{}] %any% %any% ;"))
|
if (Token::Match(tok3, "[;{}] %any% %any% ;"))
|
||||||
{
|
{
|
||||||
Token::eraseTokens(tok3, tok3->tokAt(3));
|
Token::eraseTokens(tok3, tok3->tokAt(3));
|
||||||
|
@ -6690,13 +6729,6 @@ bool Tokenizer::simplifyKnownVariables()
|
||||||
tok3->next()->varId(valueVarId);
|
tok3->next()->varId(valueVarId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok2)
|
|
||||||
tok = tok2->previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -308,6 +308,18 @@ public:
|
||||||
*/
|
*/
|
||||||
bool simplifyKnownVariables();
|
bool simplifyKnownVariables();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function for simplifyKnownVariables. Get data about an
|
||||||
|
* assigned variable.
|
||||||
|
*/
|
||||||
|
bool simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token **_tok3, std::string &value, unsigned int &valueVarId, bool &valueIsPointer, bool floatvar);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utility function for simplifyKnownVariables. Perform simplification
|
||||||
|
* of a given variable
|
||||||
|
*/
|
||||||
|
bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel);
|
||||||
|
|
||||||
/** Replace a "goto" with the statements */
|
/** Replace a "goto" with the statements */
|
||||||
void simplifyGoto();
|
void simplifyGoto();
|
||||||
|
|
||||||
|
@ -574,7 +586,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void duplicateEnumError(const Token *tok1, const Token *tok2, const std::string & type);
|
void duplicateEnumError(const Token *tok1, const Token *tok2, const std::string & type);
|
||||||
|
|
||||||
bool duplicateTypedef(Token **tokPtr, const Token *name);
|
bool duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef);
|
||||||
void duplicateTypedefError(const Token *tok1, const Token *tok2, const std::string & type);
|
void duplicateTypedefError(const Token *tok1, const Token *tok2, const std::string & type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -44,8 +44,11 @@ Compiling
|
||||||
|
|
||||||
g++ (for experts)
|
g++ (for experts)
|
||||||
=================
|
=================
|
||||||
If you just want to build Cppcheck then you can use this command:
|
If you just want to build Cppcheck without dependencies then you can use this command:
|
||||||
g++ -o cppcheck -lpcre -Ilib -Iexternals cli/*.cpp lib/*.cpp externals/tinyxml/*.cpp
|
g++ -o cppcheck -Ilib cli/*.cpp lib/*.cpp
|
||||||
|
|
||||||
|
If you want to use --rule and --rule-file then dependencies are needed:
|
||||||
|
g++ -o cppcheck -lpcre -DHAVE_DEPENDENCIES -Ilib -Iexternals cli/*.cpp lib/*.cpp externals/tinyxml/*.cpp
|
||||||
mingw
|
mingw
|
||||||
=====
|
=====
|
||||||
make LDFLAGS=-lshlwapi
|
make LDFLAGS=-lshlwapi
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
ASTYLE_VERSION="Artistic Style Version 2.01"
|
||||||
|
if [ "`astyle --version 2>&1`" != "${ASTYLE_VERSION}" ]; then
|
||||||
|
echo "You should use: ${ASTYLE_VERSION}";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
style="--style=ansi --lineend=linux --min-conditional-indent=0"
|
style="--style=ansi --lineend=linux --min-conditional-indent=0"
|
||||||
options="--pad-header --unpad-paren --suffix=none"
|
options="--pad-header --unpad-paren --suffix=none"
|
||||||
|
|
|
@ -116,6 +116,7 @@ private:
|
||||||
TEST_CASE(array_index_for_break); // FP: for,break
|
TEST_CASE(array_index_for_break); // FP: for,break
|
||||||
TEST_CASE(array_index_for); // FN: for,if
|
TEST_CASE(array_index_for); // FN: for,if
|
||||||
TEST_CASE(array_index_for_neq); // #2211: Using != in condition
|
TEST_CASE(array_index_for_neq); // #2211: Using != in condition
|
||||||
|
TEST_CASE(array_index_for_question); // #2561: for, ?:
|
||||||
|
|
||||||
TEST_CASE(buffer_overrun_1);
|
TEST_CASE(buffer_overrun_1);
|
||||||
TEST_CASE(buffer_overrun_2);
|
TEST_CASE(buffer_overrun_2);
|
||||||
|
@ -133,6 +134,7 @@ private:
|
||||||
TEST_CASE(buffer_overrun_14);
|
TEST_CASE(buffer_overrun_14);
|
||||||
TEST_CASE(buffer_overrun_15); // ticket #1787
|
TEST_CASE(buffer_overrun_15); // ticket #1787
|
||||||
TEST_CASE(buffer_overrun_16);
|
TEST_CASE(buffer_overrun_16);
|
||||||
|
TEST_CASE(buffer_overrun_17); // ticket #2548
|
||||||
TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch
|
TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch
|
||||||
|
|
||||||
// It is undefined behaviour to point out of bounds of an array
|
// It is undefined behaviour to point out of bounds of an array
|
||||||
|
@ -886,8 +888,8 @@ private:
|
||||||
" a[-1] = 0;\n" // negative index
|
" a[-1] = 0;\n" // negative index
|
||||||
" a[256] = 0;\n" // 256 > CHAR_MAX
|
" a[256] = 0;\n" // 256 > CHAR_MAX
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Array 'a[256]' index -1 out of bounds\n"
|
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[256]' index 256 out of bounds\n"
|
||||||
"[test.cpp:4]: (error) Array 'a[256]' index 256 out of bounds\n", errout.str());
|
"[test.cpp:3]: (error) Array 'a[256]' index -1 out of bounds\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
check("void f(signed char n) {\n"
|
check("void f(signed char n) {\n"
|
||||||
|
@ -1380,6 +1382,18 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) Buffer access out-of-bounds: a\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (error) Buffer access out-of-bounds: a\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void array_index_for_question()
|
||||||
|
{
|
||||||
|
// Ticket #2561 - using ?: inside for loop
|
||||||
|
check("void f() {\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" for (int i = 0; i != 10; ++i) {\n"
|
||||||
|
" i == 0 ? 0 : a[i-1];\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void buffer_overrun_1()
|
void buffer_overrun_1()
|
||||||
{
|
{
|
||||||
check("void f()\n"
|
check("void f()\n"
|
||||||
|
@ -1860,6 +1874,15 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void buffer_overrun_17() // ticket #2548
|
||||||
|
{
|
||||||
|
check("void f() {\n"
|
||||||
|
" char t[8];\n"
|
||||||
|
" sprintf(t, \"%s\", \"foo bar\");\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer access out-of-bounds\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void buffer_overrun_bailoutIfSwitch()
|
void buffer_overrun_bailoutIfSwitch()
|
||||||
{
|
{
|
||||||
// No false positive
|
// No false positive
|
||||||
|
|
|
@ -104,6 +104,8 @@ private:
|
||||||
TEST_CASE(clarifyCalculation);
|
TEST_CASE(clarifyCalculation);
|
||||||
|
|
||||||
TEST_CASE(incorrectStringCompare);
|
TEST_CASE(incorrectStringCompare);
|
||||||
|
|
||||||
|
TEST_CASE(incrementBoolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char *filename = NULL)
|
void check(const char code[], const char *filename = NULL)
|
||||||
|
@ -141,6 +143,7 @@ private:
|
||||||
checkOther.checkMemsetZeroBytes();
|
checkOther.checkMemsetZeroBytes();
|
||||||
checkOther.clarifyCalculation();
|
checkOther.clarifyCalculation();
|
||||||
checkOther.checkIncorrectStringCompare();
|
checkOther.checkIncorrectStringCompare();
|
||||||
|
checkOther.checkIncrementBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1892,6 +1895,23 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void incrementBoolean()
|
||||||
|
{
|
||||||
|
check("bool bValue = true;\n"
|
||||||
|
"bValue++;\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) The use of a variable of type bool with the ++ postfix operator is always true and deprecated by the C++ Standard.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(bool test){\n"
|
||||||
|
" test++;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) The use of a variable of type bool with the ++ postfix operator is always true and deprecated by the C++ Standard.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(int test){\n"
|
||||||
|
" test++;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestOther)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
|
@ -148,6 +148,8 @@ private:
|
||||||
TEST_CASE(macro_simple11);
|
TEST_CASE(macro_simple11);
|
||||||
TEST_CASE(macro_simple12);
|
TEST_CASE(macro_simple12);
|
||||||
TEST_CASE(macro_simple13);
|
TEST_CASE(macro_simple13);
|
||||||
|
TEST_CASE(macro_simple14);
|
||||||
|
TEST_CASE(macro_simple15);
|
||||||
TEST_CASE(macroInMacro);
|
TEST_CASE(macroInMacro);
|
||||||
TEST_CASE(macro_mismatch);
|
TEST_CASE(macro_mismatch);
|
||||||
TEST_CASE(macro_linenumbers);
|
TEST_CASE(macro_linenumbers);
|
||||||
|
@ -198,6 +200,11 @@ private:
|
||||||
TEST_CASE(endfile);
|
TEST_CASE(endfile);
|
||||||
|
|
||||||
TEST_CASE(redundant_config);
|
TEST_CASE(redundant_config);
|
||||||
|
|
||||||
|
TEST_CASE(testPreprocessorRead1);
|
||||||
|
TEST_CASE(testPreprocessorRead2);
|
||||||
|
TEST_CASE(testPreprocessorRead3);
|
||||||
|
TEST_CASE(testPreprocessorRead4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,7 +216,7 @@ private:
|
||||||
Preprocessor preprocessor(&settings, this);
|
Preprocessor preprocessor(&settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
std::string codestr(preprocessor.read(istr,"test.c",0));
|
std::string codestr(preprocessor.read(istr,"test.c",0));
|
||||||
ASSERT_EQUALS("a \n#aa b \n", codestr);
|
ASSERT_EQUALS("a\n#aa b\n", codestr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void readCode2()
|
void readCode2()
|
||||||
|
@ -323,7 +330,7 @@ private:
|
||||||
preprocessor.preprocess(istr, actual, "file.c");
|
preprocessor.preprocess(istr, actual, "file.c");
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
ASSERT_EQUALS("\n\" #ifdef WIN32\"\n\n\n\n", actual[""]);
|
ASSERT_EQUALS("\n\" # ifdef WIN32\"\n\n\n\n", actual[""]);
|
||||||
ASSERT_EQUALS("\n\n\nqwerty\n\n", actual["WIN32"]);
|
ASSERT_EQUALS("\n\n\nqwerty\n\n", actual["WIN32"]);
|
||||||
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
|
||||||
}
|
}
|
||||||
|
@ -1363,7 +1370,7 @@ private:
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
Settings settings;
|
Settings settings;
|
||||||
Preprocessor preprocessor(&settings, this);
|
Preprocessor preprocessor(&settings, this);
|
||||||
ASSERT_EQUALS("#define str \"abc\" \"def\" \n\nabcdef = str;\n", preprocessor.read(istr, "test.c", 0));
|
ASSERT_EQUALS("#define str \"abc\" \"def\"\n\nabcdef = str;\n", preprocessor.read(istr, "test.c", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void multiline2()
|
void multiline2()
|
||||||
|
@ -1576,6 +1583,20 @@ private:
|
||||||
ASSERT_EQUALS("\n\n", OurPreprocessor::expandMacros(filedata));
|
ASSERT_EQUALS("\n\n", OurPreprocessor::expandMacros(filedata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void macro_simple14()
|
||||||
|
{
|
||||||
|
const char filedata[] = "#define A \" a \"\n"
|
||||||
|
"printf(A);\n";
|
||||||
|
ASSERT_EQUALS("\nprintf(\" a \");\n", OurPreprocessor::expandMacros(filedata));
|
||||||
|
}
|
||||||
|
|
||||||
|
void macro_simple15()
|
||||||
|
{
|
||||||
|
const char filedata[] = "#define FOO\"foo\"\n"
|
||||||
|
"FOO\n";
|
||||||
|
ASSERT_EQUALS("\n\"foo\"\n", OurPreprocessor::expandMacros(filedata));
|
||||||
|
}
|
||||||
|
|
||||||
void macroInMacro()
|
void macroInMacro()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
@ -2462,6 +2483,25 @@ private:
|
||||||
ASSERT_EQUALS("\n\n1\n\n", actual[""]);
|
ASSERT_EQUALS("\n\n1\n\n", actual[""]);
|
||||||
ASSERT_EQUALS(1, (int)actual.size());
|
ASSERT_EQUALS(1, (int)actual.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char filedata[] = "#define A 1\n"
|
||||||
|
"#if 0\n"
|
||||||
|
"#undef A\n"
|
||||||
|
"#endif\n"
|
||||||
|
"A\n";
|
||||||
|
|
||||||
|
// Preprocess => actual result..
|
||||||
|
std::istringstream istr(filedata);
|
||||||
|
std::map<std::string, std::string> actual;
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings, this);
|
||||||
|
preprocessor.preprocess(istr, actual, "file.c");
|
||||||
|
|
||||||
|
// Compare results..
|
||||||
|
ASSERT_EQUALS("\n\n\n\n1\n", actual[""]);
|
||||||
|
ASSERT_EQUALS(1, (int)actual.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void define_ifndef1()
|
void define_ifndef1()
|
||||||
|
@ -2591,6 +2631,63 @@ private:
|
||||||
ASSERT_EQUALS("A;A;B is NOT checked", "A;A;B is NOT checked");
|
ASSERT_EQUALS("A;A;B is NOT checked", "A;A;B is NOT checked");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testPreprocessorRead1()
|
||||||
|
{
|
||||||
|
const std::string filedata("/*\n*/ # /*\n*/ defi\\\nne FO\\\nO 10\\\n20");
|
||||||
|
std::istringstream istr(filedata.c_str());
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings, this);
|
||||||
|
ASSERT_EQUALS("#define FOO 1020", preprocessor.read(istr, "test.cpp", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPreprocessorRead2()
|
||||||
|
{
|
||||||
|
const std::string filedata("\"foo\\\\\nbar\"");
|
||||||
|
std::istringstream istr(filedata.c_str());
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings, this);
|
||||||
|
ASSERT_EQUALS("\"foo\\bar\"", preprocessor.read(istr, "test.cpp", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPreprocessorRead3()
|
||||||
|
{
|
||||||
|
const std::string filedata("#define A \" a \"\n\" b\"");
|
||||||
|
std::istringstream istr(filedata.c_str());
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings, this);
|
||||||
|
ASSERT_EQUALS(filedata, preprocessor.read(istr, "test.cpp", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPreprocessorRead4()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// test < \\> < > (unescaped)
|
||||||
|
const std::string filedata("#define A \" \\\\\"/*space*/ \" \"");
|
||||||
|
std::istringstream istr(filedata.c_str());
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings, this);
|
||||||
|
ASSERT_EQUALS("#define A \" \\\\\" \" \"", preprocessor.read(istr, "test.cpp", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test <" \\\" "> (unescaped)
|
||||||
|
const std::string filedata("#define A \" \\\\\\\" \"");
|
||||||
|
std::istringstream istr(filedata.c_str());
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings, this);
|
||||||
|
ASSERT_EQUALS("#define A \" \\\\\\\" \"", preprocessor.read(istr, "test.cpp", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test <" \\\\"> <" "> (unescaped)
|
||||||
|
const std::string filedata("#define A \" \\\\\\\\\"/*space*/ \" \"");
|
||||||
|
std::istringstream istr(filedata.c_str());
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings, this);
|
||||||
|
ASSERT_EQUALS("#define A \" \\\\\\\\\" \" \"", preprocessor.read(istr, "test.cpp", 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestPreprocessor)
|
REGISTER_TEST(TestPreprocessor)
|
||||||
|
|
|
@ -235,6 +235,7 @@ private:
|
||||||
TEST_CASE(simplifyTypedef75); // ticket #2426
|
TEST_CASE(simplifyTypedef75); // ticket #2426
|
||||||
TEST_CASE(simplifyTypedef76); // ticket #2453
|
TEST_CASE(simplifyTypedef76); // ticket #2453
|
||||||
TEST_CASE(simplifyTypedef77); // ticket #2554
|
TEST_CASE(simplifyTypedef77); // ticket #2554
|
||||||
|
TEST_CASE(simplifyTypedef78); // ticket #2568
|
||||||
|
|
||||||
TEST_CASE(simplifyTypedefFunction1);
|
TEST_CASE(simplifyTypedefFunction1);
|
||||||
TEST_CASE(simplifyTypedefFunction2); // ticket #1685
|
TEST_CASE(simplifyTypedefFunction2); // ticket #1685
|
||||||
|
@ -3941,7 +3942,7 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n"
|
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n"
|
||||||
"[test.cpp:20] -> [test.cpp:1]: (style) Function parameter 'A' hides typedef with same name\n"
|
"[test.cpp:20] -> [test.cpp:1]: (style) Function parameter 'A' hides typedef with same name\n"
|
||||||
"[test.cpp:21] -> [test.cpp:1]: (style) Variable 'A' hides typedef with same name\n"
|
"[test.cpp:21] -> [test.cpp:1]: (style) Variable 'A' hides typedef with same name\n"
|
||||||
"[test.cpp:24] -> [test.cpp:1]: (style) Struct 'A' hides typedef with same name\n", errout.str());
|
"[test.cpp:24] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplifyTypedef36()
|
void simplifyTypedef36()
|
||||||
|
@ -4846,6 +4847,16 @@ private:
|
||||||
ASSERT_EQUALS(expected, sizeof_(code));
|
ASSERT_EQUALS(expected, sizeof_(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplifyTypedef78() // ticket #2568
|
||||||
|
{
|
||||||
|
const char code[] = "typedef struct A A_t;\n"
|
||||||
|
"A_t a;\n"
|
||||||
|
"typedef struct A { } A_t;\n"
|
||||||
|
"A_t a1;\n";
|
||||||
|
const std::string expected = "; struct A a ; struct A { } ; struct A a1 ;";
|
||||||
|
ASSERT_EQUALS(expected, sizeof_(code));
|
||||||
|
}
|
||||||
|
|
||||||
void simplifyTypedefFunction1()
|
void simplifyTypedefFunction1()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,6 +65,8 @@ private:
|
||||||
TEST_CASE(testDoesNotIdentifyMethodAsFirstFunctionArgument); // #2480
|
TEST_CASE(testDoesNotIdentifyMethodAsFirstFunctionArgument); // #2480
|
||||||
TEST_CASE(testDoesNotIdentifyMethodAsMiddleFunctionArgument);
|
TEST_CASE(testDoesNotIdentifyMethodAsMiddleFunctionArgument);
|
||||||
TEST_CASE(testDoesNotIdentifyMethodAsLastFunctionArgument);
|
TEST_CASE(testDoesNotIdentifyMethodAsLastFunctionArgument);
|
||||||
|
|
||||||
|
TEST_CASE(multiFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -549,6 +551,26 @@ private:
|
||||||
);
|
);
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void multiFile() // ticket #2567
|
||||||
|
{
|
||||||
|
check("#file \"test.h\"\n"
|
||||||
|
"struct Fred\n"
|
||||||
|
"{\n"
|
||||||
|
" Fred()\n"
|
||||||
|
" {\n"
|
||||||
|
" Init();\n"
|
||||||
|
" }\n"
|
||||||
|
"private:\n"
|
||||||
|
" void Init();\n"
|
||||||
|
"};\n"
|
||||||
|
"#endfile\n"
|
||||||
|
"void Fred::Init()\n"
|
||||||
|
"{\n"
|
||||||
|
"}\n");
|
||||||
|
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestUnusedPrivateFunction)
|
REGISTER_TEST(TestUnusedPrivateFunction)
|
||||||
|
|
|
@ -225,7 +225,7 @@ int main(int argc, char **argv)
|
||||||
// Makefile settings..
|
// Makefile settings..
|
||||||
if (release)
|
if (release)
|
||||||
{
|
{
|
||||||
makeConditionalVariable(fout, "CXXFLAGS", "-O2 -DNDEBUG -Wall");
|
makeConditionalVariable(fout, "CXXFLAGS", "-O2 -DNDEBUG -DHAVE_DEPENDENCIES -Wall");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -235,6 +235,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
// The _GLIBCXX_DEBUG doesn't work in cygwin
|
// The _GLIBCXX_DEBUG doesn't work in cygwin
|
||||||
makeConditionalVariable(fout, "CXXFLAGS",
|
makeConditionalVariable(fout, "CXXFLAGS",
|
||||||
|
"-DHAVE_DEPENDENCIES "
|
||||||
"-Wall "
|
"-Wall "
|
||||||
"-Wextra "
|
"-Wextra "
|
||||||
"-Wshadow "
|
"-Wshadow "
|
||||||
|
|
Loading…
Reference in New Issue