Merge branch 'master' of git@github.com:danmar/cppcheck

This commit is contained in:
Kimmo Varis 2009-06-04 12:46:27 +03:00
commit a574eb1012
15 changed files with 698 additions and 52 deletions

View File

@ -110,6 +110,7 @@ MainWindow::MainWindow() :
connect(&mActionAbout, SIGNAL(triggered()), this, SLOT(About()));
connect(&mThread, SIGNAL(Done()), this, SLOT(CheckDone()));
connect(&mResults, SIGNAL(GotResults()), this, SLOT(ResultsAdded()));
//Toolbar
QToolBar *toolbar = addToolBar("Toolbar");
@ -140,6 +141,9 @@ MainWindow::MainWindow() :
setWindowTitle(tr("Cppcheck"));
EnableCheckButtons(true);
mActionClearResults.setEnabled(false);
mActionSave.setEnabled(false);
}
MainWindow::~MainWindow()
@ -210,6 +214,7 @@ void MainWindow::DoCheckFiles(QFileDialog::FileMode mode)
mThread.SetFiles(RemoveUnacceptedFiles(fileNames));
mSettings.setValue(tr("Check path"), dialog.directory().absolutePath());
EnableCheckButtons(false);
mResults.SetCheckDirectory(dialog.directory().absolutePath());
mThread.Check(GetCppcheckSettings(), false);
}
}
@ -295,6 +300,9 @@ void MainWindow::ProgramSettings()
if (dialog.exec() == QDialog::Accepted)
{
dialog.SaveCheckboxValues();
mResults.UpdateSettings(dialog.ShowFullPath(),
dialog.SaveFullPath(),
dialog.SaveAllErrors());
}
}
@ -309,6 +317,8 @@ void MainWindow::ReCheck()
void MainWindow::ClearResults()
{
mResults.Clear();
mActionClearResults.setEnabled(false);
mActionSave.setEnabled(false);
}
void MainWindow::EnableCheckButtons(bool enable)
@ -396,9 +406,30 @@ void MainWindow::About()
void MainWindow::Save()
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Not implemented yet..."));
msgBox.setText(tr("Not implemented yet..."));
msgBox.exec();
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setAcceptMode(QFileDialog::AcceptSave);
QStringList filters;
filters << tr("XML files (*.xml)") << tr("Text files (*.txt)");
dialog.setNameFilters(filters);
if (dialog.exec())
{
QStringList list = dialog.selectedFiles();
if (list.size() > 0)
{
bool xml = (dialog.selectedNameFilter() == filters[0] && list[0].endsWith(".xml", Qt::CaseInsensitive));
mResults.Save(list[0], xml);
}
}
}
void MainWindow::ResultsAdded()
{
mActionClearResults.setEnabled(true);
mActionSave.setEnabled(true);
}

View File

@ -133,6 +133,12 @@ protected slots:
*
*/
void CheckDone();
/**
* @brief Slot for enabling save and clear button
*
*/
void ResultsAdded();
protected:
/**

View File

@ -22,11 +22,13 @@
#include <QMenu>
#include <QSignalMapper>
#include <QProcess>
#include <QDir>
ResultsTree::ResultsTree(QSettings &settings, ApplicationList &list) :
mSettings(settings),
mApplications(list),
mContextItem(0)
mContextItem(0),
mCheckPath("")
{
setModel(&mModel);
QStringList labels;
@ -58,7 +60,8 @@ void ResultsTree::AddErrorItem(const QString &file,
const QString &severity,
const QString &message,
const QStringList &files,
const QVariantList &lines)
const QVariantList &lines,
const QString &id)
{
Q_UNUSED(file);
@ -68,7 +71,7 @@ void ResultsTree::AddErrorItem(const QString &file,
return;
}
QString realfile = files[0];
QString realfile = StripPath(files[0], false);
if (realfile.isEmpty())
{
@ -93,6 +96,7 @@ void ResultsTree::AddErrorItem(const QString &file,
data["message"] = message;
data["files"] = files;
data["lines"] = lines;
data["id"] = id;
item->setData(QVariant(data));
@ -100,7 +104,7 @@ void ResultsTree::AddErrorItem(const QString &file,
for (int i = 1;i < files.size() && i < lines.size();i++)
{
AddBacktraceFiles(item,
files[i],
StripPath(files[i], false),
lines[i].toInt(),
severity,
message,
@ -143,6 +147,7 @@ QStandardItem *ResultsTree::AddBacktraceFiles(QStandardItem *parent,
setRowHidden(parent->rowCount() - 1, parent->index(), hide);
if (!icon.isEmpty())
{
list[0]->setIcon(QIcon(icon));
@ -200,6 +205,10 @@ void ResultsTree::LoadSettings()
QString temp = QString(tr("Result column %1 width")).arg(i);
setColumnWidth(i, mSettings.value(temp, 800 / mModel.columnCount()).toInt());
}
mSaveFullPath = mSettings.value(tr("Save full path"), false).toBool();
mSaveAllErrors = mSettings.value(tr("Save all errors"), false).toBool();
mShowFullPath = mSettings.value(tr("Show full path"), false).toBool();
}
void ResultsTree::SaveSettings()
@ -422,3 +431,251 @@ QString ResultsTree::SeverityToIcon(const QString &severity)
return "";
}
void ResultsTree::SaveResults(QTextStream &out, bool xml)
{
if (xml)
{
out << "<?xml version=\"1.0\"?>" << endl << "<results>" << endl;
}
for (int i = 0;i < mModel.rowCount();i++)
{
QStandardItem *item = mModel.item(i, 0);
SaveErrors(out, item, xml);
}
if (xml)
{
out << "</results>" << endl;
}
}
void ResultsTree::SaveErrors(QTextStream &out, QStandardItem *item, bool xml)
{
if (!item)
{
return;
}
//qDebug() << item->text() << "has" << item->rowCount() << "errors";
for (int i = 0;i < item->rowCount();i++)
{
QStandardItem *error = item->child(i, 0);
if (!error)
{
continue;
}
if (isRowHidden(i, item->index()) && !mSaveAllErrors)
{
continue;
}
//Get error's user data
QVariant userdata = error->data();
//Convert it to QVariantMap
QVariantMap data = userdata.toMap();
QString line;
QString severity = ShowTypeToString(VariantToShowType(data["severity"]));
QString message = data["message"].toString();
QString id = data["id"].toString();
QStringList files = data["files"].toStringList();
QVariantList lines = data["lines"].toList();
if (files.size() <= 0 || lines.size() <= 0 || lines.size() != files.size())
{
continue;
}
if (xml)
{
/*
Error example from the core program in xml
<error file="gui/test.cpp" line="14" id="mismatchAllocDealloc" severity="error" msg="Mismatching allocation and deallocation: k"/>
The callstack seems to be ignored here aswell, instead last item of the stack is used
*/
line = QString("<error file=\"%1\" line=\"%2\" id=\"%3\" severity=\"%4\" msg=\"%5\"/>").
arg(StripPath(files[files.size()-1], true)). //filename
arg(lines[lines.size()-1].toInt()). //line
arg(id). //ID
arg(severity). //severity
arg(message); //Message
}
else
{
/*
Error example from the core program in text
[gui/test.cpp:23] -> [gui/test.cpp:14]: (error) Mismatching allocation and deallocation: k
*/
for (int i = 0;i < lines.size();i++)
{
line += QString("[%1:%2]").arg(StripPath(files[i], true)).arg(lines[i].toInt());
if (i < lines.size() - 1 && lines.size() > 0)
{
line += " -> ";
}
if (i == lines.size() - 1)
{
line += ": ";
}
}
line += QString("(%1) %2").arg(severity).arg(message);
}
out << line << endl;
}
}
QString ResultsTree::ShowTypeToString(ShowTypes type)
{
switch (type)
{
case SHOW_ALL:
return "all";
break;
case SHOW_STYLE:
return "style";
break;
case SHOW_SECURITY:
return "security";
break;
case SHOW_UNUSED:
return "unused";
break;
case SHOW_ERRORS:
return "error";
break;
case SHOW_NONE:
return "";
break;
}
return "";
}
void ResultsTree::UpdateSettings(bool showFullPath,
bool saveFullPath,
bool saveAllErrors)
{
if (mShowFullPath != showFullPath)
{
mShowFullPath = showFullPath;
RefreshFilePaths();
}
mSaveFullPath = saveFullPath;
mSaveAllErrors = saveAllErrors;
}
void ResultsTree::SetCheckDirectory(const QString &dir)
{
mCheckPath = dir;
}
QString ResultsTree::StripPath(const QString &path, bool saving)
{
if ((!saving && mShowFullPath) || (saving && mSaveFullPath))
{
return QString(path);
}
QDir dir(mCheckPath);
return dir.relativeFilePath(path);
}
void ResultsTree::RefreshFilePaths(QStandardItem *item)
{
if (!item)
{
return;
}
//Mark that this file's path hasn't been updated yet
bool updated = false;
//Loop through all errors within this file
for (int i = 0;i < item->rowCount();i++)
{
//Get error i
QStandardItem *error = item->child(i, 0);
if (!error)
{
continue;
}
//Get error's user data
QVariant userdata = error->data();
//Convert it to QVariantMap
QVariantMap data = userdata.toMap();
//Get list of files
QStringList files = data["files"].toStringList();
//We should always have at least 1 file per error
if (files.size() == 0)
{
continue;
}
//Update this error's text
error->setText(StripPath(files[0], false));
//If this error has backtraces make sure the files list has enough filenames
if (error->rowCount() <= files.size() - 1)
{
//Loop through all files within the error
for (int j = 0;j < error->rowCount();j++)
{
//Get file
QStandardItem *file = error->child(j, 0);
if (!file)
{
continue;
}
//Update file's path
file->setText(StripPath(files[j+1], false));
}
}
//if the main file hasn't been updated yet, update it now
if (!updated)
{
updated = true;
item->setText(error->text());
}
}
}
void ResultsTree::RefreshFilePaths()
{
qDebug("Refreshing file paths");
//Go through all file items (these are parent items that contain the errors)
for (int i = 0;i < mModel.rowCount();i++)
{
RefreshFilePaths(mModel.item(i, 0));
}
}

View File

@ -27,7 +27,7 @@
#include <QContextMenuEvent>
#include "common.h"
#include "applicationlist.h"
#include <QTextStream>
/**
* @brief Cppcheck's results are shown in this tree
@ -53,7 +53,8 @@ public:
const QString &severity,
const QString &message,
const QStringList &files,
const QVariantList &lines);
const QVariantList &lines,
const QString &id);
/**
* @brief Clear all errors from the tree
@ -69,6 +70,29 @@ public:
* @param Should specified errors be shown (true) or hidden (false)
*/
void ShowResults(ShowTypes type, bool show);
/**
* @brief Save results to a text stream
*
*/
void SaveResults(QTextStream &out, bool xml);
/**
* @brief Update tree settings
*
* @param showFullPath Show full path of files in the tree
* @param saveFullPath Save full path of files in reports
* @param saveAllErrors Save all visible errors
*/
void UpdateSettings(bool showFullPath, bool saveFullPath, bool saveAllErrors);
/**
* @brief Set the directory we are checking
*
* This is used to split error file path to relative if necessary
* @param dir Directory we are checking
*/
void SetCheckDirectory(const QString &dir);
protected slots:
/**
* @brief Slot to quickstart an error with default application
@ -84,6 +108,38 @@ protected slots:
*/
void Context(int application);
protected:
/**
* @brief Hides/shows full file path on all error file items according to mShowFullPath
*
*/
void RefreshFilePaths();
/**
* @brief Hides/shows full file path on all error file items according to mShowFullPath
* @param item Parent item whose childrens paths to change
*/
void RefreshFilePaths(QStandardItem *item);
/**
* @brief Removes checking directory from given path if mShowFullPath is false
*
* @param path Path to remove checking directory
* @param saving are we saving? Check mSaveFullPath instead
* @return Path that has checking directory removed
*/
QString StripPath(const QString &path, bool saving);
/**
* @brief Save all errors under spesified item
*
* @param item Item whose errors to save
* @param xml Should errors be saved as xml (true) or as text (false)
*/
void SaveErrors(QTextStream &out, QStandardItem *item, bool xml);
/**
* @brief Convert a severity string to a icon filename
*
@ -151,6 +207,13 @@ protected:
*/
ShowTypes SeverityToShowType(const QString &severity);
/**
* @brief Convert ShowType to severity string
* @param type ShowType to convert
* @return ShowType converted to string
*/
QString ShowTypeToString(ShowTypes type);
/**
* @brief Load all settings
* Colum widths
@ -225,6 +288,30 @@ protected:
*
*/
QStandardItem *mContextItem;
/**
* @brief Should full path of files be shown (true) or relative (false)
*
*/
bool mShowFullPath;
/**
* @brief Should full path of files be saved
*
*/
bool mSaveFullPath;
/**
* @brief Save all errors (true) or only visible (false)
*
*/
bool mSaveAllErrors;
/**
* @brief Path we are currently checking
*
*/
QString mCheckPath;
private:
};

View File

@ -20,6 +20,7 @@
#include "resultsview.h"
#include <QDebug>
#include <QVBoxLayout>
#include <QFile>
ResultsView::ResultsView(QSettings &settings, ApplicationList &list)
{
@ -58,9 +59,11 @@ void ResultsView::Error(const QString &file,
const QString &severity,
const QString &message,
const QStringList &files,
const QVariantList &lines)
const QVariantList &lines,
const QString &id)
{
mTree->AddErrorItem(file, severity, message, files, lines);
mTree->AddErrorItem(file, severity, message, files, lines, id);
emit GotResults();
}
void ResultsView::ShowResults(ShowTypes type, bool show)
@ -77,3 +80,29 @@ void ResultsView::ExpandAllResults()
{
mTree->expandAll();
}
void ResultsView::Save(const QString &filename, bool xml)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
return;
}
QTextStream out(&file);
mTree->SaveResults(out, xml);
}
void ResultsView::UpdateSettings(bool showFullPath,
bool saveFullPath,
bool saveAllErrors)
{
mTree->UpdateSettings(showFullPath, saveFullPath, saveAllErrors);
}
void ResultsView::SetCheckDirectory(const QString &dir)
{
mTree->SetCheckDirectory(dir);
}

View File

@ -54,6 +54,41 @@ public:
*
*/
void Clear();
/**
* @brief Save results to a file
*
* @param filename Filename to save results to
* @param xml should results be saved as xml (true) or txt (false)
*/
void Save(const QString &filename, bool xml);
/**
* @brief Update tree settings
*
* @param showFullPath Show full path of files in the tree
* @param saveFullPath Save full path of files in reports
* @param saveAllErrors Save all visible errors
*/
void UpdateSettings(bool showFullPath, bool saveFullPath, bool saveAllErrors);
/**
* @brief Set the directory we are checking
*
* This is used to split error file path to relative if necessary
* @param dir Directory we are checking
*/
void SetCheckDirectory(const QString &dir);
signals:
/**
* @brief Signal to be emitted when we have results
*
*/
void GotResults();
public slots:
/**
@ -77,7 +112,8 @@ public slots:
const QString &severity,
const QString &message,
const QStringList &files,
const QVariantList &lines);
const QVariantList &lines,
const QString &error);
/**
* @brief Collapse all results in the result list.

View File

@ -83,6 +83,11 @@ SettingsDialog::SettingsDialog(QSettings &programSettings, ApplicationList &list
tr("Check force"),
false);
mShowFullPath = AddCheckbox(layout,
tr("Show full path of files"),
tr("Show full path"),
false);
general->setLayout(layout);
//Add tab for setting user startable applications
@ -121,6 +126,23 @@ SettingsDialog::SettingsDialog(QSettings &programSettings, ApplicationList &list
PopulateListWidget();
//report tab
QWidget *report = new QWidget();
tabs->addTab(report, tr("Reports"));
QVBoxLayout *reportlayout = new QVBoxLayout();
mSaveAllErrors = AddCheckbox(reportlayout,
tr("Save all errors when creating report"),
tr("Save all errors"),
false);
mSaveFullPath = AddCheckbox(reportlayout,
tr("Save full path to files in reports"),
tr("Save full path"),
false);
report->setLayout(reportlayout);
setLayout(dialoglayout);
setWindowTitle(tr("Settings"));
LoadSettings();
@ -181,6 +203,9 @@ void SettingsDialog::SaveCheckboxValues()
mSettings.setValue(tr("Check threads"), jobs);
SaveCheckboxValue(mForce, tr("Check force"));
SaveCheckboxValue(mSaveAllErrors, tr("Save all errors"));
SaveCheckboxValue(mSaveFullPath, tr("Save full path"));
SaveCheckboxValue(mShowFullPath, tr("Show full path"));
}
void SettingsDialog::SaveCheckboxValue(QCheckBox *box, const QString &name)
@ -259,4 +284,20 @@ void SettingsDialog::Ok()
accept();
}
bool SettingsDialog::ShowFullPath()
{
return CheckStateToBool(mShowFullPath->checkState());
}
bool SettingsDialog::SaveFullPath()
{
return CheckStateToBool(mSaveFullPath->checkState());
}
bool SettingsDialog::SaveAllErrors()
{
return CheckStateToBool(mSaveAllErrors->checkState());
}

View File

@ -50,6 +50,27 @@ public:
*/
void SaveCheckboxValues();
/**
* @brief Get checkbox value for mShowFullPath
*
* @return should full path of errors be shown in the tree
*/
bool ShowFullPath();
/**
* @brief Get checkbox value for mSaveFullPath
*
* @return should full path of files be saved when creating a report
*/
bool SaveFullPath();
/**
* @brief Get checkbox value for mSaveAllErrors
*
* @return should all errors be saved to report
*/
bool SaveAllErrors();
protected slots:
/**
* @brief Slot for clicking OK.
@ -152,6 +173,24 @@ protected:
*/
QCheckBox *mForce;
/**
* @brief Save all errors
*
*/
QCheckBox *mSaveAllErrors;
/**
* @brief Save full path of the file in error reports
*
*/
QCheckBox *mSaveFullPath;
/**
* @brief Show full path of file in results view
*
*/
QCheckBox *mShowFullPath;
/**
* @brief List of all applications that can be started when right clicking
* an error

View File

@ -138,12 +138,14 @@ void ThreadHandler::Initialize(ResultsView *view)
const QString &,
const QString &,
const QStringList &,
const QVariantList &)),
const QVariantList &,
const QString &)),
view, SLOT(Error(const QString &,
const QString &,
const QString &,
const QStringList &,
const QVariantList &)));
const QVariantList &,
const QString &)));
}

View File

@ -61,7 +61,8 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg)
QString(msg._severity.c_str()),
QString(msg._msg.c_str()),
files,
lines);
lines,
QString(msg._id.c_str()));

View File

@ -95,7 +95,8 @@ signals:
const QString &severity,
const QString &message,
const QStringList &files,
const QVariantList &lines);
const QVariantList &lines,
const QString &id);
protected:

View File

@ -1333,7 +1333,7 @@ void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope(const Token *Tok1, const c
MemoryLeak(result->tokAt(3), varname, alloctype, all);
}
else if ((result = Token::findmatch(tok, "alloc ; alloc|assign|return ;")) != NULL)
else if ((result = Token::findmatch(tok, "alloc ; alloc|assign|return callfunc| ;")) != NULL)
{
MemoryLeak(result->tokAt(2), varname, alloctype, all);
}

View File

@ -1723,6 +1723,17 @@ bool Tokenizer::simplifyConditions()
for (Token *tok = _tokens; tok; tok = tok->next())
{
if (Token::Match(tok, "! %num%") || Token::Match(tok, "! %bool%"))
{
if (tok->next()->str() == "0" || tok->next()->str() == "false")
tok->str("true");
else
tok->str("false");
tok->deleteNext();
ret = true;
}
if (Token::simpleMatch(tok, "( true &&") || Token::simpleMatch(tok, "&& true &&") || Token::simpleMatch(tok->next(), "&& true )"))
{
tok->deleteNext();
@ -2354,7 +2365,7 @@ bool Tokenizer::simplifyKnownVariables()
break;
// Using the variable in condition..
if (Token::Match(tok3, "(|==|!=|<|<=|>|>= %varid% )|==|!=|<|<=|>|>=", varid))
if (Token::Match(tok3, "(|!|==|!=|<|<=|>|>= %varid% )|==|!=|<|<=|>|>=", varid))
{
tok3 = tok3->next();
tok3->str(value.c_str());

View File

@ -1993,6 +1993,14 @@ private:
" }\n"
"}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Memory leak: p\n", errout.str());
check("void foo()\n"
"{\n"
" int *p = new int[100];\n"
" p = g();\n"
" delete [] p;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: p\n", errout.str());
}
void unknownFunction3()

View File

@ -479,6 +479,7 @@ private:
}
void simplifyKnownVariables1()
{
{
const char code[] = "void f()\n"
"{\n"
@ -500,6 +501,28 @@ private:
ASSERT_EQUALS(" void f ( ) { int a ; a = 10 ; if ( 10 ) ; }", ostr.str());
}
{
const char code[] = "void f()\n"
"{\n"
" int a = 10;\n"
" if (!a);\n"
"}\n";
// tokenize..
OurTokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.setVarId();
tokenizer.simplifyKnownVariables();
std::ostringstream ostr;
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
ostr << " " << tok->str();
ASSERT_EQUALS(" void f ( ) { int a ; a = 10 ; if ( ! 10 ) ; }", ostr.str());
}
}
void simplifyKnownVariables2()
{
const char code[] = "void f()\n"
@ -1701,13 +1724,14 @@ private:
}
void simplify_numeric_condition()
{
{
const char code[] =
"void f()\n"
"{\n"
"int x = 0;\n"
"if( !x || 0 )\n"
"{\n"
"{ g();\n"
"}\n"
"}";
@ -1722,7 +1746,80 @@ private:
std::ostringstream ostr;
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
ostr << " " << tok->str();
ASSERT_EQUALS(" void f ( ) { int x ; x = 0 ; if ( ! x ) { } }", ostr.str());
ASSERT_EQUALS(" void f ( ) { int x ; x = 0 ; { g ( ) ; } }", ostr.str());
}
{
const char code[] =
"void f()\n"
"{\n"
"int x = 1;\n"
"if( !x )\n"
"{ g();\n"
"}\n"
"}";
// tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.setVarId();
tokenizer.simplifyTokenList();
std::ostringstream ostr;
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
ostr << " " << tok->str();
ASSERT_EQUALS(" void f ( ) { int x ; x = 1 ; }", ostr.str());
}
{
const char code[] =
"void f()\n"
"{\n"
"bool x = true;\n"
"if( !x )\n"
"{ g();\n"
"}\n"
"}";
// tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.setVarId();
tokenizer.simplifyTokenList();
std::ostringstream ostr;
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
ostr << " " << tok->str();
ASSERT_EQUALS(" void f ( ) { bool x ; x = true ; }", ostr.str());
}
{
const char code[] =
"void f()\n"
"{\n"
"bool x = false;\n"
"if( !x )\n"
"{ g();\n"
"}\n"
"}";
// tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.setVarId();
tokenizer.simplifyTokenList();
std::ostringstream ostr;
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
ostr << " " << tok->str();
ASSERT_EQUALS(" void f ( ) { bool x ; x = false ; { g ( ) ; } }", ostr.str());
}
}
void tokenize_double()