This commit is contained in:
Sébastien Debrard 2011-02-12 11:38:56 +01:00
commit 8ad863d650
23 changed files with 929 additions and 609 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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
* *

View File

@ -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;

View File

@ -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))

View File

@ -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());

View File

@ -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()
{ {

View File

@ -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";

View File

@ -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())
{ {

View File

@ -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);
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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);
/** /**

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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);
} }
@ -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)

View File

@ -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()
{ {
{ {

View File

@ -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)

View File

@ -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 "