diff --git a/.gitignore b/.gitignore
index 32bf90c20..dc418d47a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,8 +29,8 @@ gui/*.qm
# Doxygen output folder
doxyoutput/
# qmake generated
-src/Makefile
-
-*.sdf
-ipch
-*.opensdf
\ No newline at end of file
+
+*.sdf
+ipch
+*.opensdf
+*.orig
diff --git a/gui/aboutdialog.cpp b/gui/aboutdialog.cpp
index 25db77990..2d1b800da 100644
--- a/gui/aboutdialog.cpp
+++ b/gui/aboutdialog.cpp
@@ -15,11 +15,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
#include
-#include
-#include
-#include
-#include
+#include
#include "aboutdialog.h"
AboutDialog::AboutDialog(const QString &version, QWidget *parent)
diff --git a/gui/aboutdialog.h b/gui/aboutdialog.h
index 8fac3c687..17d7021bc 100644
--- a/gui/aboutdialog.h
+++ b/gui/aboutdialog.h
@@ -21,9 +21,10 @@
#include
#include
-
#include "ui_about.h"
+class QWidget;
+
/// @addtogroup GUI
/// @{
diff --git a/gui/applicationdialog.cpp b/gui/applicationdialog.cpp
index 56df70886..320798417 100644
--- a/gui/applicationdialog.cpp
+++ b/gui/applicationdialog.cpp
@@ -16,14 +16,11 @@
* along with this program. If not, see .
*/
-#include "applicationdialog.h"
-#include
-#include
-#include
-#include
+#include
#include
#include
#include
+#include "applicationdialog.h"
ApplicationDialog::ApplicationDialog(const QString &name,
diff --git a/gui/applicationdialog.h b/gui/applicationdialog.h
index 3ec88846d..803b5b88e 100644
--- a/gui/applicationdialog.h
+++ b/gui/applicationdialog.h
@@ -21,8 +21,11 @@
#include
#include
+#include
#include "ui_application.h"
+class QWidget;
+
/// @addtogroup GUI
/// @{
diff --git a/gui/common.h b/gui/common.h
index d0226db95..c4fd7c070 100644
--- a/gui/common.h
+++ b/gui/common.h
@@ -58,6 +58,8 @@ ShowTypes;
#define SETTINGS_LANGUAGE "Application language"
#define SETTINGS_TOOLBARS_MAIN_SHOW "Toolbars/ShowStandard"
#define SETTINGS_TOOLBARS_VIEW_SHOW "Toolbars/ShowView"
+#define SETTINGS_LOG_VIEW_WIDTH "Log/View width"
+#define SETTINGS_LOG_VIEW_HEIGHT "Log/View height"
/// @}
#endif
diff --git a/gui/cppcheck_de.ts b/gui/cppcheck_de.ts
index fea41f30d..5edfbe623 100644
--- a/gui/cppcheck_de.ts
+++ b/gui/cppcheck_de.ts
@@ -124,19 +124,37 @@ kate -l(line) (file)
+
+ LogView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MainWindow
-
-
-
-
+
+
+
+
-
+
@@ -156,265 +174,275 @@ kate -l(line) (file)
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
diff --git a/gui/cppcheck_en.ts b/gui/cppcheck_en.ts
index 1aa29f33f..4773e5dd0 100644
--- a/gui/cppcheck_en.ts
+++ b/gui/cppcheck_en.ts
@@ -137,19 +137,37 @@ kate -l(line) (file)
Could not read the file: %1
+
+ LogView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MainWindow
-
-
-
-
+
+
+
+
Cppcheck
-
+
Standard
@@ -169,265 +187,275 @@ kate -l(line) (file)
-
+
&Check
-
+
&Edit
-
+
&License...
-
+
A&uthors...
-
+
&About...
-
+
&Files...
-
+
Ctrl+F
-
+
&Directory...
-
+
Ctrl+D
-
+
&Recheck files
-
+
Ctrl+R
-
+
&Stop
-
+
Esc
-
+
&Save results to file...
-
+
Ctrl+S
-
+
&Quit
-
+
&Clear results
-
+
&Preferences
-
+
Show style errors
-
+
Show common errors
-
+
&Check all
-
+
&Uncheck all
-
+
Collapse &all
-
+
&Expand all
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
&Language
-
+
&Help
-
+
Select files to check
-
+
Select directory to check
-
+
No suitable files found to check!
-
+
License
-
+
Authors
-
+
XML files (*.xml);;Text files (*.txt);;CSV files (*.csv)
-
+
Save the report file
-
-
+
+
XML files (*.xml)
-
+
-
+
-
+
Text files (*.txt)
-
+
-
+
Cppcheck - %1
-
+
%1
-
-
+
+
-
+
-
+
diff --git a/gui/cppcheck_fi.ts b/gui/cppcheck_fi.ts
index b71567a3d..9934038e9 100644
--- a/gui/cppcheck_fi.ts
+++ b/gui/cppcheck_fi.ts
@@ -139,19 +139,37 @@ kate -l(line) (file)
Tiedoston %1 lukeminen epäonnistui
+
+ LogView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MainWindow
-
-
-
-
+
+
+
+
Cppcheck
-
+
Vakio
@@ -171,265 +189,275 @@ kate -l(line) (file)
-
+
&Tarkista
-
+
&Muokkaa
-
+
&Lisenssi...
-
+
&Tekijät...
-
+
&Tietoa ohjelmasta Cppcheck...
-
+
&Tiedostot...
-
+
Ctrl+F
-
+
&Hakemisto...
-
+
Ctrl+D
-
+
Tarkista tiedostot &uudelleen
-
+
Ctrl+R
-
+
&Pysäytä
-
+
Esc
-
+
&Tallenna tulokset tiedostoon...
-
+
Ctrl+S
-
+
&Lopeta
-
+
&Tyhjennä tulokset
-
+
&Asetukset
-
+
Näytä tyylivirheet
-
+
Näytä yleiset virheet
-
+
&Valitse kaikki
-
+
&Poista kaikista valinta
-
+
&Pienennä kaikki
-
+
&Laajenna kaikki
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
&Kieli
-
+
&Ohje
-
+
Valitse tarkistettavat tiedostot
-
+
Valitse tarkistettava hakemisto
-
+
Tarkistettavaksi sopivia tiedostoja ei löytynyt!
-
+
Lisenssi
-
+
Tekijät
-
+
XML-tiedostot (*.xml);;Tekstitiedostot (*.txt);;CSV-tiedostot (*.csv)
-
+
Tallenna raportti
-
-
+
+
XML-tiedostot (*xml)
-
+
-
+
-
+
Tekstitiedostot (*.txt)
-
+
-
+
Cppcheck - %1
-
+
-
-
+
+
-
+
-
+
diff --git a/gui/cppcheck_nl.ts b/gui/cppcheck_nl.ts
index 552e12cf6..9f764d0b5 100644
--- a/gui/cppcheck_nl.ts
+++ b/gui/cppcheck_nl.ts
@@ -137,19 +137,37 @@ kate -l(line) (file)
Kon het bestand niet lezen: %1
+
+ LogView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MainWindow
-
-
-
-
+
+
+
+
Cppcheck
-
+
Standaard
@@ -169,265 +187,275 @@ kate -l(line) (file)
-
+
&Controleer
-
+
Be&werken
-
+
&Licentie...
-
+
A&uteurs...
-
+
&Over...
-
+
&Bestanden...
-
+
Ctrl+F
-
+
&Mappen...
-
+
Ctrl+D
-
+
&Opnieuw controleren
-
+
Ctrl+R
-
+
&Stop
-
+
Esc
-
+
&Resultaten opslaan...
-
+
Ctrl+S
-
+
&Afsluiten
-
+
&Resultaten wissen
-
+
&Voorkeuren
-
+
Toon stijl fouten
-
+
Toon gewone fouten
-
+
&Selecteer alles
-
+
Selecteer &niets
-
+
Alles Inkl&appen
-
+
Alles &Uitklappen
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
&Taal
-
+
&Help
-
+
Selecteer bestanden om te controleren
-
+
Selecteer een map om te controleren
-
+
Geen geschikte bestanden gevonden om te controleren!
-
+
Licentie
-
+
Auteurs
-
+
XML bestanden (*.xml);;Tekst bestanden (*.txt);;CSV bestanden (*.csv)
-
+
Rapport opslaan
-
-
+
+
XML bestanden (*.xml)
-
+
-
+
-
+
Tekst bestanden (*.txt)
-
+
-
+
Cppcheck - %1
-
+
%1
-
-
+
+
-
+
-
+
diff --git a/gui/cppcheck_pl.ts b/gui/cppcheck_pl.ts
index 9921d0b39..7df3ccc73 100644
--- a/gui/cppcheck_pl.ts
+++ b/gui/cppcheck_pl.ts
@@ -124,14 +124,32 @@ kate -l(line) (file)
+
+ LogView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MainWindow
-
-
-
-
+
+
+
+
@@ -151,275 +169,285 @@ kate -l(line) (file)
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
diff --git a/gui/cppcheck_ru.ts b/gui/cppcheck_ru.ts
index 833ba47e8..625c2562c 100644
--- a/gui/cppcheck_ru.ts
+++ b/gui/cppcheck_ru.ts
@@ -127,19 +127,37 @@ kate -l(line) (file)
Невозможно прочитать файл: %1
+
+ LogView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MainWindow
-
-
-
-
+
+
+
+
Cppcheck
-
+
@@ -159,265 +177,275 @@ kate -l(line) (file)
-
+
Проверить
-
+
Правка
-
+
Лицензия...
-
+
Авторы...
-
+
О программе...
-
+
Файлы...
-
+
Ctrl+F
-
+
Каталог...
-
+
Ctrl+D
-
+
-
+
Ctrl+R
-
+
Остановить
-
+
Esc
-
+
Сохранить отчёт в файл...
-
+
Ctrl+S
-
+
Выход
-
+
Очистить отчёт
-
+
Параметры
-
+
Показывать ошибки стиля
-
+
Показывать общие ошибки
-
+
Отметить все
-
+
Сбросить все
-
+
Свернуть все
-
+
Развернуть все
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
Язык
-
+
Помощь
-
+
Выберите файлы для проверки
-
+
Выберите каталог для проверки
-
+
-
+
Лицензия
-
+
Авторы
-
+
-
+
-
-
+
+
-
+
-
+
-
+
Текстовые файлы (*.txt)
-
+
-
+
Cppcheck - %1
-
+
-
-
+
+
-
+
-
+
diff --git a/gui/cppcheck_se.ts b/gui/cppcheck_se.ts
index 5f5ce21cd..f8c1260c6 100644
--- a/gui/cppcheck_se.ts
+++ b/gui/cppcheck_se.ts
@@ -137,19 +137,37 @@ kate -l(line) (file)
Kunde inte läsa filen: %1
+
+ LogView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MainWindow
-
-
-
-
+
+
+
+
Cppcheck
-
+
Standard
@@ -169,266 +187,276 @@ kate -l(line) (file)
Verktygsfält
-
+
&Check
-
+
&Redigera
-
+
&Licens...
-
+
&Utvecklat av...
-
+
&Om...
-
+
&Filer...
-
+
Ctrl+F
-
+
&Katalog...
-
+
Ctrl+D
-
+
Starta &om check
-
+
Ctrl+R
-
+
&Stoppa
-
+
Esc
-
+
&Spara resultat till fil...
-
+
Ctrl+S
-
+
&Avsluta
-
+
&Töm resultat
-
+
&Inställningar
-
+
Visa stilvarningar
-
+
Visa vanliga fel
-
+
&Kryssa alla
-
+
Kryssa &ur alla
-
+
Ingen bra översättning!
&Fäll ihop alla
-
+
&Expandera alla
-
+
&Standard
-
+
Standard poster
-
+
Verktygsfält
-
+
&Kategorier
-
+
Fel kategorier
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
&Innehåll
-
+
Kategorier
-
+
Öppna hjälp
-
+
F1
-
+
&Språk
-
+
&Hjälp
-
+
Välj filer att kontrollera
-
+
Välj katalog som skall kontrolleras
-
+
Inga lämpliga filer hittades!
-
+
Licens
-
+
Utvecklare
-
+
XML filer (*.xml);;Text filer (*.txt);;CSV filer (*.csv)
-
+
Spara rapport
-
-
+
+
XML filer (*.xml)
-
+
-
+
-
+
Text filer (*.txt)
-
+
CSV filer (*.csv)
-
+
Cppcheck - %1
-
+
-
-
+
+
-
+
-
+
diff --git a/gui/fileviewdialog.cpp b/gui/fileviewdialog.cpp
index f0d947ee2..5106ee9c2 100644
--- a/gui/fileviewdialog.cpp
+++ b/gui/fileviewdialog.cpp
@@ -16,14 +16,10 @@
* along with this program. If not, see .
*/
-#include
-#include
-#include
-#include
-#include
#include
#include
#include
+#include
#include "fileviewdialog.h"
FileViewDialog::FileViewDialog(const QString &file,
diff --git a/gui/fileviewdialog.h b/gui/fileviewdialog.h
index eaeeba738..876bf3e00 100644
--- a/gui/fileviewdialog.h
+++ b/gui/fileviewdialog.h
@@ -23,6 +23,9 @@
#include
#include "ui_file.h"
+class QWidget;
+class QTextEdit;
+
/// @addtogroup GUI
/// @{
diff --git a/gui/gui.pro b/gui/gui.pro
index 3e1de7f02..e4215cfe1 100644
--- a/gui/gui.pro
+++ b/gui/gui.pro
@@ -26,7 +26,8 @@ FORMS = main.ui \
settings.ui \
file.ui \
projectfile.ui \
- about.ui
+ about.ui \
+ logview.ui
TRANSLATIONS = cppcheck_fi.ts \
cppcheck_nl.ts \
@@ -60,7 +61,9 @@ HEADERS += mainwindow.h \
txtreport.h \
xmlreport.h \
translationhandler.h \
- csvreport.h
+ csvreport.h \
+ logview.h
+
SOURCES += main.cpp \
mainwindow.cpp\
checkthread.cpp \
@@ -81,7 +84,8 @@ SOURCES += main.cpp \
txtreport.cpp \
xmlreport.cpp \
translationhandler.cpp \
- csvreport.cpp
+ csvreport.cpp \
+ logview.cpp
win32 {
RC_FILE = cppcheck-gui.rc
diff --git a/gui/logview.cpp b/gui/logview.cpp
new file mode 100644
index 000000000..8d3b6856a
--- /dev/null
+++ b/gui/logview.cpp
@@ -0,0 +1,56 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2010 Daniel Marjamki and Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include "common.h"
+#include "logview.h"
+
+LogView::LogView(QSettings *programSettings, QWidget *parent)
+ : mSettings(programSettings)
+{
+ Q_UNUSED(parent);
+ mUI.setupUi(this);
+ setWindowFlags(Qt::Tool);
+
+ connect(mUI.mCloseButton, SIGNAL(clicked()), this, SLOT(CloseButtonClicked()));
+ connect(mUI.mClearButton, SIGNAL(clicked()), this, SLOT(ClearButtonClicked()));
+
+ resize(mSettings->value(SETTINGS_LOG_VIEW_WIDTH, 400).toInt(),
+ mSettings->value(SETTINGS_LOG_VIEW_HEIGHT, 300).toInt());
+}
+
+LogView::~LogView()
+{
+ mSettings->setValue(SETTINGS_LOG_VIEW_WIDTH, size().width());
+ mSettings->setValue(SETTINGS_LOG_VIEW_HEIGHT, size().height());
+}
+
+void LogView::AppendLine(const QString &line)
+{
+ mUI.mLogEdit->appendPlainText(line);
+}
+
+void LogView::CloseButtonClicked()
+{
+ close();
+}
+
+void LogView::ClearButtonClicked()
+{
+ mUI.mLogEdit->clear();
+}
diff --git a/gui/logview.h b/gui/logview.h
new file mode 100644
index 000000000..d56ae2ef6
--- /dev/null
+++ b/gui/logview.h
@@ -0,0 +1,75 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2010 Daniel Marjamki and Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef LOGVIEW_H
+#define LOGVIEW_H
+
+#include
+#include "ui_logview.h"
+
+class QSettings;
+
+/// @addtogroup GUI
+/// @{
+
+/**
+* @brief A tool window that shows checking log.
+*
+*/
+class LogView : public QWidget
+{
+ Q_OBJECT
+public:
+ LogView(QSettings *programSettings, QWidget *parent = 0);
+ ~LogView();
+
+ /**
+ * @brief Append new log file to view.
+ * @param line String to add.
+ *
+ */
+ void AppendLine(const QString &line);
+
+protected slots:
+
+ /**
+ * @brief Called when close button is clicked.
+ *
+ */
+ void CloseButtonClicked();
+
+ /**
+ * @brief Called when clear button is clicked.
+ *
+ */
+ void ClearButtonClicked();
+
+private:
+ Ui::LogView mUI;
+
+ /**
+ * @brief Settings
+ *
+ */
+ QSettings *mSettings;
+
+};
+
+/// @}
+
+#endif // LOGVIEW_H
diff --git a/gui/logview.ui b/gui/logview.ui
new file mode 100644
index 000000000..642e34436
--- /dev/null
+++ b/gui/logview.ui
@@ -0,0 +1,65 @@
+
+
+ LogView
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Qt::NoContextMenu
+
+
+ Checking Log
+
+
+ -
+
+
+ false
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Clear
+
+
+
+ -
+
+
+ Close
+
+
+
+
+
+
+
+
+
+
diff --git a/gui/main.ui b/gui/main.ui
index 939106b55..72f62b145 100644
--- a/gui/main.ui
+++ b/gui/main.ui
@@ -100,6 +100,7 @@
+
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
index 92fc5b056..2819355b2 100644
--- a/gui/mainwindow.cpp
+++ b/gui/mainwindow.cpp
@@ -33,6 +33,7 @@
#include "projectfile.h"
#include "project.h"
#include "report.h"
+#include "logview.h"
#include "../lib/filelister.h"
// HTMLHelp is only available in Windows
@@ -45,12 +46,15 @@ MainWindow::MainWindow() :
mSettings(new QSettings("Cppcheck", "Cppcheck-GUI", this)),
mApplications(new ApplicationList(this)),
mTranslation(new TranslationHandler(this)),
- mLanguages(new QActionGroup(this))
+ mLanguages(new QActionGroup(this)),
+ mLogView(NULL),
+ mExiting(false)
{
mUI.setupUi(this);
mUI.mResults->Initialize(mSettings, mApplications);
mThread = new ThreadHandler(this);
+ mLogView = new LogView(mSettings);
connect(mUI.mActionQuit, SIGNAL(triggered()), this, SLOT(close()));
connect(mUI.mActionCheckFiles, SIGNAL(triggered()), this, SLOT(CheckFiles()));
@@ -65,6 +69,7 @@ MainWindow::MainWindow() :
connect(mUI.mActionUncheckAll, SIGNAL(triggered()), this, SLOT(UncheckAll()));
connect(mUI.mActionCollapseAll, SIGNAL(triggered()), mUI.mResults, SLOT(CollapseAllResults()));
connect(mUI.mActionExpandAll, SIGNAL(triggered()), mUI.mResults, SLOT(ExpandAllResults()));
+ connect(mUI.mActionViewLog, SIGNAL(triggered()), this, SLOT(ShowLogView()));
connect(mUI.mActionRecheck, SIGNAL(triggered()), this, SLOT(ReCheck()));
@@ -114,6 +119,7 @@ MainWindow::MainWindow() :
MainWindow::~MainWindow()
{
+ delete mLogView;
}
void MainWindow::CreateLanguageMenuItems()
@@ -395,6 +401,12 @@ QStringList MainWindow::RemoveUnacceptedFiles(const QStringList &list)
void MainWindow::CheckDone()
{
+ if (mExiting)
+ {
+ close();
+ return;
+ }
+
mUI.mResults->CheckingFinished();
EnableCheckButtons(true);
mUI.mActionSettings->setEnabled(true);
@@ -518,10 +530,9 @@ void MainWindow::closeEvent(QCloseEvent *event)
// exiting it doesn't matter.
mThread->Stop();
SaveSettings();
- event->accept();
+ mExiting = true;
}
- else
- event->ignore();
+ event->ignore();
}
}
@@ -732,3 +743,21 @@ void MainWindow::NewProjectFile()
prj.Edit();
}
}
+
+void MainWindow::ShowLogView()
+{
+ if (mLogView == NULL)
+ mLogView = new LogView(mSettings);
+
+ mLogView->show();
+ if (!mLogView->isActiveWindow())
+ mLogView->activateWindow();
+}
+
+void MainWindow::Log(const QString &logline)
+{
+ if (mLogView)
+ {
+ mLogView->AppendLine(logline);
+ }
+}
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
index 1c8cae8b2..f49d6d3e5 100644
--- a/gui/mainwindow.h
+++ b/gui/mainwindow.h
@@ -32,6 +32,7 @@
#include "ui_main.h"
class ThreadHandler;
+class LogView;
/// @addtogroup GUI
/// @{
@@ -143,6 +144,12 @@ public slots:
*/
void OpenProjectFile();
+ /**
+ * @brief Slot for showing the log view.
+ *
+ */
+ void ShowLogView();
+
protected slots:
/**
@@ -190,6 +197,12 @@ protected slots:
*/
void OpenHelpContents();
+ /**
+ * @brief Add new line to log.
+ *
+ */
+ void Log(const QString &logline);
+
protected:
/**
@@ -325,6 +338,20 @@ protected:
*/
QString mCurrentDirectory;
+ /**
+ * @brief Log view..
+ */
+ LogView *mLogView;
+
+private:
+
+ /**
+ * @brief Are we exiting the cppcheck?
+ * If this is true then the cppcheck is waiting for check threads to exit
+ * so that the application can be closed.
+ */
+ bool mExiting;
+
};
/// @}
#endif // MAINWINDOW_H
diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp
index bbea6d44f..8d28b44b1 100644
--- a/gui/resultsview.cpp
+++ b/gui/resultsview.cpp
@@ -17,11 +17,11 @@
*/
#include
-#include
#include
#include
#include "erroritem.h"
#include "resultsview.h"
+#include "resultstree.h"
#include "report.h"
#include "txtreport.h"
#include "xmlreport.h"
diff --git a/gui/resultsview.h b/gui/resultsview.h
index bc81d28d1..cb66a5749 100644
--- a/gui/resultsview.h
+++ b/gui/resultsview.h
@@ -24,7 +24,6 @@
#include
#include
#include "../lib/errorlogger.h"
-#include "resultstree.h"
#include "common.h"
#include "report.h"
#include "ui_resultsview.h"
diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp
index 90f8fcb2f..1272ac687 100644
--- a/gui/settingsdialog.cpp
+++ b/gui/settingsdialog.cpp
@@ -17,13 +17,15 @@
*/
-#include "settingsdialog.h"
#include
#include
#include
#include
#include
+#include
+#include "settingsdialog.h"
#include "applicationdialog.h"
+#include "applicationlist.h"
#include "common.h"
SettingsDialog::SettingsDialog(QSettings *programSettings,
diff --git a/gui/settingsdialog.h b/gui/settingsdialog.h
index 86deebcce..e35239c0c 100644
--- a/gui/settingsdialog.h
+++ b/gui/settingsdialog.h
@@ -21,18 +21,13 @@
#define SETTINGSDIALOG_H
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "applicationlist.h"
-
-#include
#include
#include "ui_settings.h"
+class QSettings;
+class QWidget;
+class ApplicationList;
+
/// @addtogroup GUI
/// @{
diff --git a/gui/threadhandler.cpp b/gui/threadhandler.cpp
index 7ea918437..9b1bca96f 100644
--- a/gui/threadhandler.cpp
+++ b/gui/threadhandler.cpp
@@ -144,6 +144,8 @@ void ThreadHandler::Initialize(ResultsView *view)
connect(&mResults, SIGNAL(Error(const ErrorItem &)),
view, SLOT(Error(const ErrorItem &)));
+ connect(&mResults, SIGNAL(Log(const QString &)),
+ parent(), SLOT(Log(const QString &)));
}
void ThreadHandler::LoadSettings(QSettings &settings)
diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp
index 3484cffd5..ad249936b 100644
--- a/gui/threadresult.cpp
+++ b/gui/threadresult.cpp
@@ -33,7 +33,7 @@ ThreadResult::~ThreadResult()
void ThreadResult::reportOut(const std::string &outmsg)
{
- Q_UNUSED(outmsg);
+ emit Log(QString::fromStdString(outmsg));
}
void ThreadResult::FileChecked(const QString &file)
diff --git a/gui/threadresult.h b/gui/threadresult.h
index 7e6b1a618..80133a90e 100644
--- a/gui/threadresult.h
+++ b/gui/threadresult.h
@@ -93,6 +93,13 @@ signals:
*/
void Error(const ErrorItem &item);
+ /**
+ * @brief Signal of a new log message
+ *
+ * @param logline Log line
+ */
+ void Log(const QString &logline);
+
protected:
/**
diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp
index 27f65a23c..2669a1a89 100644
--- a/lib/checkclass.cpp
+++ b/lib/checkclass.cpp
@@ -41,11 +41,12 @@ CheckClass instance;
//---------------------------------------------------------------------------
-CheckClass::Var *CheckClass::getVarList(const Token *tok1, bool withClasses, bool isStruct)
+CheckClass::Var *CheckClass::getVarList(const Token *tok1)
{
// Get variable list..
Var *varlist = NULL;
unsigned int indentlevel = 0;
+ bool isStruct = tok1->str() == "struct";
bool priv = !isStruct;
for (const Token *tok = tok1; tok; tok = tok->next())
{
@@ -131,14 +132,13 @@ CheckClass::Var *CheckClass::getVarList(const Token *tok1, bool withClasses, boo
}
// Is it a variable declaration?
+ bool isClass = false;
if (Token::Match(next, "%type% %var% ;|:"))
{
- if (withClasses)
- varname = next->strAt(1);
- else if (next->isStandardType())
- varname = next->strAt(1);
- else if (Token::findmatch(_tokenizer->tokens(), ("enum " + next->str()).c_str()))
- varname = next->strAt(1);
+ if (!next->isStandardType())
+ isClass = true;
+
+ varname = next->strAt(1);
}
// Structure?
@@ -158,10 +158,9 @@ CheckClass::Var *CheckClass::getVarList(const Token *tok1, bool withClasses, boo
// Array?
else if (Token::Match(next, "%type% %var% [") && next->next()->str() != "operator")
{
- if (!withClasses && !next->isStandardType())
- {
- continue;
- }
+ if (!next->isStandardType())
+ isClass = true;
+
varname = next->strAt(1);
}
@@ -172,15 +171,17 @@ CheckClass::Var *CheckClass::getVarList(const Token *tok1, bool withClasses, boo
varname = next->strAt(4);
// std::string..
- else if (withClasses && Token::Match(next, "%type% :: %type% %var% ;"))
+ else if (Token::Match(next, "%type% :: %type% %var% ;"))
{
+ isClass = true;
varname = next->strAt(3);
}
// Container..
- else if (withClasses && (Token::Match(next, "%type% :: %type% <") ||
- Token::Match(next, "%type% <")))
+ else if (Token::Match(next, "%type% :: %type% <") ||
+ Token::Match(next, "%type% <"))
{
+ isClass = true;
// find matching ">"
int level = 0;
for (; next; next = next->next())
@@ -203,7 +204,7 @@ CheckClass::Var *CheckClass::getVarList(const Token *tok1, bool withClasses, boo
// If the varname was set in the if-blocks above, create a entry for this variable..
if (!varname.empty() && varname != "operator")
{
- Var *var = new Var(varname, false, priv, isMutable, isStatic, varlist);
+ Var *var = new Var(varname, false, priv, isMutable, isStatic, isClass, varlist);
varlist = var;
}
}
@@ -225,8 +226,10 @@ void CheckClass::initVar(Var *varlist, const std::string &varname)
}
//---------------------------------------------------------------------------
-void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *varlist, const std::string &classname, std::list &callstack, bool isStruct)
+void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *varlist, std::list &callstack)
{
+ const std::string &classname = tok1->next()->str();
+ bool isStruct = tok1->str() == "struct";
bool Assign = false;
unsigned int indentlevel = 0;
@@ -360,14 +363,22 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
if (ftok2)
{
callstack.push_back(ftok->str());
- initializeVarList(tok1, ftok2, varlist, classname, callstack, isStruct);
+ initializeVarList(tok1, ftok2, varlist, callstack);
callstack.pop_back();
}
else // there is a called member function, but it is not defined where we can find it, so we assume it initializes everything
{
// check if the function is part of this class..
- const Token *tok = Token::findmatch(_tokenizer->tokens(), ((isStruct ? std::string("struct ") : std::string("class ")) + classname + " {").c_str());
- for (tok = tok ? tok->tokAt(3) : 0; tok; tok = tok->next())
+ const Token *tok = Token::findmatch(_tokenizer->tokens(), (tok1->str() + " " + classname + " {|:").c_str());
+ bool derived = false;
+ while (tok && tok->str() != "{")
+ {
+ if (tok->str() == ":")
+ derived = true;
+ tok = tok->next();
+ }
+
+ for (tok = tok ? tok->next() : 0; tok; tok = tok->next())
{
if (tok->str() == "{")
{
@@ -381,13 +392,15 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
}
else if (tok->str() == ftok->str() || tok->str() == "friend")
{
- tok = 0;
- break;
+ if (tok->next()->str() == "(" || tok->str() == "friend")
+ {
+ tok = 0;
+ break;
+ }
}
}
-
// bail out..
- if (!tok)
+ if (!tok || derived)
{
for (Var *var = varlist; var; var = var->next)
var->init = true;
@@ -474,7 +487,7 @@ struct Constructor
bool isCopyConstructor;
};
-static bool argsMatch(const Token *first, const Token *second)
+static bool argsMatch(const Token *first, const Token *second, const std::string &path, unsigned int depth)
{
bool match = false;
while (first->str() == second->str())
@@ -517,6 +530,35 @@ static bool argsMatch(const Token *first, const Token *second)
first = first->tokAt(2);
}
+ // variable with class path
+ else if (depth && Token::Match(first->next(), "%var%"))
+ {
+ std::string param = path + first->next()->str();
+
+ if (Token::Match(second->next(), param.c_str()))
+ {
+ second = second->tokAt(depth * 2);
+ }
+ else if (depth > 1)
+ {
+ std::string short_path = path;
+
+ // remove last " :: "
+ short_path.resize(short_path.size() - 4);
+
+ // remove last name
+ while (!short_path.empty() && short_path[short_path.size() - 1] != ' ')
+ short_path.resize(short_path.size() - 1);
+
+ param = short_path + first->next()->str();
+
+ if (Token::Match(second->next(), param.c_str()))
+ {
+ second = second->tokAt((depth - 1) * 2);
+ }
+ }
+ }
+
first = first->next();
second = second->next();
}
@@ -619,6 +661,8 @@ void CheckClass::constructors()
int stack_index = spaceInfo.size() - 1;
std::string classPattern;
+ std::string classPath;
+ std::string searchPattern;
int offset1, offset2;
if (operatorEqual)
{
@@ -632,25 +676,25 @@ void CheckClass::constructors()
}
bool hasBody = false;
+ unsigned int depth = 0;
while (!hasBody && stack_index >= 0)
{
- classPattern = spaceInfo[stack_index].className + std::string(" :: ") + classPattern;
+ classPath = spaceInfo[stack_index].className + std::string(" :: ") + classPath;
+ searchPattern = classPath + classPattern;
offset2 += 2;
+ depth++;
// start looking at end of class
const Token *constructor_token = spaceInfo[stack_index].classEnd;
- while ((constructor_token = Token::findmatch(constructor_token, classPattern.c_str())) != NULL)
+ while ((constructor_token = Token::findmatch(constructor_token, searchPattern.c_str())) != NULL)
{
// skip destructor and other classes
if (!Token::Match(constructor_token->previous(), "~|::"))
{
- if (argsMatch(tok->tokAt(offset1), constructor_token->tokAt(offset2)))
+ if (argsMatch(tok->tokAt(offset1), constructor_token->tokAt(offset2), classPath, depth))
{
- if (operatorEqual || copyConstructor)
- constructorList.push_back(Constructor(constructor_token, access, true, operatorEqual, copyConstructor));
- else
- constructorList.push_front(Constructor(constructor_token, access, true, false, false));
+ constructorList.push_back(Constructor(constructor_token, access, true, operatorEqual, copyConstructor));
hasBody = true;
break;
@@ -669,10 +713,7 @@ void CheckClass::constructors()
// function body found?
if (!hasBody)
{
- if (operatorEqual || copyConstructor)
- constructorList.push_back(Constructor(tok, access, false, operatorEqual, copyConstructor));
- else
- constructorList.push_front(Constructor(tok, access, false, false, false));
+ constructorList.push_back(Constructor(tok, access, false, operatorEqual, copyConstructor));
}
tok = next->next();
@@ -684,10 +725,7 @@ void CheckClass::constructors()
// skip destructor and other classes
if (!Token::Match(tok->previous(), "~|::"))
{
- if (operatorEqual || copyConstructor)
- constructorList.push_back(Constructor(tok, access, true, operatorEqual, copyConstructor));
- else
- constructorList.push_front(Constructor(tok, access, true, false, false));
+ constructorList.push_back(Constructor(tok, access, true, operatorEqual, copyConstructor));
}
// skip over function body
@@ -700,8 +738,8 @@ void CheckClass::constructors()
}
}
- // Get variables that are not classes...
- Var *varlist = getVarList(tok1, false, isStruct);
+ // Get variables...
+ Var *varlist = getVarList(tok1);
// There are no constructors.
if (numConstructors == 0)
@@ -709,7 +747,7 @@ void CheckClass::constructors()
// If there is a private variable, there should be a constructor..
for (const Var *var = varlist; var; var = var->next)
{
- if (var->priv && !var->isStatic)
+ if (var->priv && !var->isClass && !var->isStatic)
{
noConstructorError(tok1, className, isStruct);
break;
@@ -718,37 +756,22 @@ void CheckClass::constructors()
}
std::list::const_iterator it;
- bool hasClasses = false;
for (it = constructorList.begin(); it != constructorList.end(); ++it)
{
- // check for end of regular constructors and start of copy constructors
- bool needClasses = it->isCopyConstructor || it->isOperatorEqual;
- if (needClasses != hasClasses)
- {
- hasClasses = needClasses;
-
- // Delete the varlist..
- while (varlist)
- {
- Var *nextvar = varlist->next;
- delete varlist;
- varlist = nextvar;
- }
-
- // Get variables including classes
- varlist = getVarList(tok1, true, isStruct);
- }
-
if (!it->hasBody)
continue;
std::list callstack;
- initializeVarList(tok1, it->token, varlist, className, callstack, isStruct);
+ initializeVarList(tok1, it->token, varlist, callstack);
// Check if any variables are uninitialized
for (Var *var = varlist; var; var = var->next)
{
+ // skip classes for regular constructor
+ if (var->isClass && !(it->isCopyConstructor || it->isOperatorEqual))
+ continue;
+
if (var->init || var->isStatic)
continue;
@@ -1696,11 +1719,123 @@ void CheckClass::thisSubtraction()
}
//---------------------------------------------------------------------------
+// check if this function is defined virtual in the base classes
+bool CheckClass::isVirtual(const std::vector &derivedFrom, const Token *functionToken) const
+{
+ // check each base class
+ for (unsigned int i = 0; i < derivedFrom.size(); ++i)
+ {
+ std::string className;
+
+ if (derivedFrom[i].find("::") != std::string::npos)
+ {
+ /** @todo handle nested base classes and namespaces */
+ }
+ else
+ className = derivedFrom[i];
+
+ std::string classPattern = std::string("class|struct ") + className + std::string(" {|:");
+
+ // find the base class
+ const Token *classToken = Token::findmatch(_tokenizer->tokens(), classPattern.c_str());
+
+ // find the function in the base class
+ if (classToken)
+ {
+ std::vector baseList;
+ const Token * tok = classToken;
+
+ while (tok->str() != "{")
+ {
+ // check for base classes
+ if (Token::Match(tok, ":|, public|protected|private"))
+ {
+ // jump to base class name
+ tok = tok->tokAt(2);
+
+ std::string base;
+
+ // handle nested base classea and namespacess
+ while (Token::Match(tok, "%var% ::"))
+ {
+ base += tok->str();
+ base += " :: ";
+ tok = tok->tokAt(2);
+ }
+
+ base += tok->str();
+
+ // save pattern for base class name
+ baseList.push_back(base);
+ }
+ tok = tok->next();
+ }
+
+ tok = tok->next();
+
+ for (; tok; tok = tok->next())
+ {
+ if (tok->str() == "{")
+ tok = tok->link();
+ else if (tok->str() == "}")
+ break;
+ else if (Token::Match(tok, "public:|protected:|private:"))
+ continue;
+ else if (tok->str() == "(")
+ tok = tok->link();
+ else if (tok->str() == "virtual")
+ {
+ // goto the function name
+ while (tok->next()->str() != "(")
+ tok = tok->next();
+
+ // do the function names match?
+ if (tok->str() == functionToken->str())
+ {
+ const Token *temp1 = tok->previous();
+ const Token *temp2 = functionToken->previous();
+ bool returnMatch = true;
+
+ // check for matching return parameters
+ while (temp1->str() != "virtual")
+ {
+ if (temp1->str() != temp2->str())
+ {
+ returnMatch = false;
+ break;
+ }
+
+ temp1 = temp1->previous();
+ temp2 = temp2->previous();
+ }
+
+ // check for matching function parameters
+ if (returnMatch && argsMatch(tok->tokAt(2), functionToken->tokAt(2), std::string(""), 0))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ if (!baseList.empty())
+ {
+ if (isVirtual(baseList, functionToken))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
struct NestInfo
{
std::string className;
- const Token * classEnd;
+ const Token *classStart;
+ const Token *classEnd;
int levelEnd;
+ std::vector derivedFrom;
};
// Can a function be const?
@@ -1722,23 +1857,47 @@ void CheckClass::checkConst()
if (level == nestInfo.back().levelEnd)
nestInfo.pop_back();
}
- else if (Token::Match(tok, "class|struct %var% {"))
+ else if (Token::Match(tok, "class|struct %var% {|:"))
{
const Token *classTok = tok;
+ NestInfo info;
// get class name..
std::string classname(tok->strAt(1));
+ info.className = classname;
+ info.classStart = tok;
- // goto initial {'
+ // goto initial '{'
while (tok && tok->str() != "{")
+ {
+ // check for base classes
+ if (Token::Match(tok, ":|, public|protected|private"))
+ {
+ // jump to base class name
+ tok = tok->tokAt(2);
+
+ std::string derivedFrom;
+
+ // handle derived base classes
+ while (Token::Match(tok, "%var% ::"))
+ {
+ derivedFrom += tok->str();
+ derivedFrom += " :: ";
+ tok = tok->tokAt(2);
+ }
+
+ derivedFrom += tok->str();
+
+ // save pattern for base class name
+ info.derivedFrom.push_back(derivedFrom);
+ }
tok = tok->next();
+ }
if (!tok)
break;
const Token *classEnd = tok->link();
- NestInfo info;
- info.className = classname;
info.classEnd = classEnd;
info.levelEnd = level++;
nestInfo.push_back(info);
@@ -1752,7 +1911,7 @@ void CheckClass::checkConst()
}
// Get class variables...
- varlist = getVarList(classTok, true, classTok->str() == "struct");
+ varlist = getVarList(classTok);
// parse in this class definition to see if there are any simple getter functions
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
@@ -1813,6 +1972,8 @@ void CheckClass::checkConst()
if (functionName == classname)
continue;
+ const Token *functionToken = tok2;
+
// goto the ')'
tok2 = tok2->next()->link();
if (!tok2)
@@ -1823,8 +1984,15 @@ void CheckClass::checkConst()
{
const Token *paramEnd = tok2;
+ // check if base class function is virtual
+ if (!info.derivedFrom.empty())
+ {
+ if (isVirtual(info.derivedFrom, functionToken))
+ continue;
+ }
+
// if nothing non-const was found. write error..
- if (checkConstFunc(classname, varlist, paramEnd))
+ if (checkConstFunc(info.className, info.derivedFrom, varlist, paramEnd))
{
for (int i = nestInfo.size() - 2; i >= 0; i--)
classname = std::string(nestInfo[i].className + "::" + classname);
@@ -1834,6 +2002,13 @@ void CheckClass::checkConst()
}
else if (Token::simpleMatch(tok2, ") ;")) // not inline
{
+ // check if base class function is virtual
+ if (!info.derivedFrom.empty())
+ {
+ if (isVirtual(info.derivedFrom, functionToken))
+ continue;
+ }
+
for (int i = nestInfo.size() - 1; i >= 0; i--)
{
const Token *found = nestInfo[i].classEnd;
@@ -1852,7 +2027,7 @@ void CheckClass::checkConst()
if (sameFunc(namespaceLevel, tok2, paramEnd))
{
// if nothing non-const was found. write error..
- if (checkConstFunc(classname, varlist, paramEnd))
+ if (checkConstFunc(info.className, info.derivedFrom, varlist, paramEnd))
{
for (int k = nestInfo.size() - 2; k >= 0; k--)
classname = std::string(nestInfo[k].className + "::" + classname);
@@ -2079,7 +2254,7 @@ bool CheckClass::isMemberFunc(const Token *tok)
return false;
}
-bool CheckClass::isMemberVar(const std::string &classname, const Var *varlist, const Token *tok)
+bool CheckClass::isMemberVar(const std::string &classname, const std::vector &derivedFrom, const Var *varlist, const Token *tok)
{
while (tok->previous() && !Token::Match(tok->previous(), "}|{|;|public:|protected:|private:|return|:|?"))
{
@@ -2107,10 +2282,71 @@ bool CheckClass::isMemberVar(const std::string &classname, const Var *varlist, c
}
}
+ // not found in this class
+ if (!derivedFrom.empty())
+ {
+ // check each base class
+ for (unsigned int i = 0; i < derivedFrom.size(); ++i)
+ {
+ std::string className;
+
+ if (derivedFrom[i].find("::") != std::string::npos)
+ {
+ /** @todo handle nested base classes and namespaces */
+ }
+ else
+ className = derivedFrom[i];
+
+ std::string classPattern = std::string("class|struct ") + className + std::string(" {|:");
+
+ // find the base class
+ const Token *classToken = Token::findmatch(_tokenizer->tokens(), classPattern.c_str());
+
+ // find the function in the base class
+ if (classToken)
+ {
+ std::vector baseList;
+ const Token * tok1 = classToken;
+
+ while (tok1->str() != "{")
+ {
+ // check for base classes
+ if (Token::Match(tok1, ":|, public|protected|private"))
+ {
+ // jump to base class name
+ tok1 = tok1->tokAt(2);
+
+ std::string base;
+
+ // handle nested base classea and namespacess
+ while (Token::Match(tok1, "%var% ::"))
+ {
+ base += tok1->str();
+ base += " :: ";
+ tok1 = tok1->tokAt(2);
+ }
+
+ base += tok1->str();
+
+ // save pattern for base class name
+ baseList.push_back(base);
+ }
+ tok1 = tok1->next();
+ }
+
+ // Get class variables...
+ Var *varlist1 = getVarList(classToken);
+
+ if (isMemberVar(classToken->next()->str(), baseList, varlist1, tok))
+ return true;
+ }
+ }
+ }
+
return false;
}
-bool CheckClass::checkConstFunc(const std::string &classname, const Var *varlist, const Token *tok)
+bool CheckClass::checkConstFunc(const std::string &classname, const std::vector &derivedFrom, const Var *varlist, const Token *tok)
{
// if the function doesn't have any assignment nor function call,
// it can be a const function..
@@ -2132,7 +2368,7 @@ bool CheckClass::checkConstFunc(const std::string &classname, const Var *varlist
(tok1->str().find("=") == 1 &&
tok1->str().find_first_of("") == std::string::npos))
{
- if (isMemberVar(classname, varlist, tok1->previous()))
+ if (isMemberVar(classname, derivedFrom, varlist, tok1->previous()))
{
isconst = false;
break;
@@ -2140,7 +2376,7 @@ bool CheckClass::checkConstFunc(const std::string &classname, const Var *varlist
}
// streaming: <<
- else if (tok1->str() == "<<" && isMemberVar(classname, varlist, tok1->previous()))
+ else if (tok1->str() == "<<" && isMemberVar(classname, derivedFrom, varlist, tok1->previous()))
{
isconst = false;
break;
@@ -2154,7 +2390,7 @@ bool CheckClass::checkConstFunc(const std::string &classname, const Var *varlist
}
// function call..
- else if ((tok1->str() != "return" && Token::Match(tok1, "%var% (") && tok1->str() != "c_str") ||
+ else if ((Token::Match(tok1, "%var% (") && !Token::Match(tok1, "return|c_str|if")) ||
Token::Match(tok1, "%var% < %any% > ("))
{
isconst = false;
diff --git a/lib/checkclass.h b/lib/checkclass.h
index c26ab3775..0c0b811b5 100644
--- a/lib/checkclass.h
+++ b/lib/checkclass.h
@@ -109,12 +109,13 @@ private:
class Var
{
public:
- Var(const std::string &name_, bool init_ = false, bool priv_ = false, bool mutable_ = false, bool static_ = false, Var *next_ = 0)
+ Var(const std::string &name_, bool init_ = false, bool priv_ = false, bool mutable_ = false, bool static_ = false, bool class_ = false, Var *next_ = 0)
: name(name_),
init(init_),
priv(priv_),
isMutable(mutable_),
isStatic(static_),
+ isClass(class_),
next(next_)
{
}
@@ -134,6 +135,9 @@ private:
/** @brief is this variable static? */
bool isStatic;
+ /** @brief is this variable a class (or unknown type)? */
+ bool isClass;
+
/** @brief next Var item */
Var *next;
@@ -146,11 +150,9 @@ private:
* @param tok1 pointer to class declaration
* @param ftok pointer to the function that should be checked
* @param varlist variable list (the "init" flag will be set in these variables)
- * @param classname name of class
* @param callstack the function doesn't look into recursive function calls.
- * @param isStruct if this is a struct instead of a class
*/
- void initializeVarList(const Token *tok1, const Token *ftok, Var *varlist, const std::string &classname, std::list &callstack, bool isStruct);
+ void initializeVarList(const Token *tok1, const Token *ftok, Var *varlist, std::list &callstack);
/** @brief initialize a variable in the varlist */
void initVar(Var *varlist, const std::string &varname);
@@ -158,15 +160,16 @@ private:
/**
* @brief get varlist from a class definition
* @param tok1 pointer to class definition
- * @param withClasses if class variables should be extracted too.
- * @param isStruct is this a struct?
*/
- Var *getVarList(const Token *tok1, bool withClasses, bool isStruct);
+ Var *getVarList(const Token *tok1);
bool sameFunc(int nest, const Token *firstEnd, const Token *secondEnd);
bool isMemberFunc(const Token *tok);
- bool isMemberVar(const std::string &classname, const Var *varlist, const Token *tok);
- bool checkConstFunc(const std::string &classname, const Var *varlist, const Token *tok);
+ bool isMemberVar(const std::string &classname, const std::vector &derivedFrom, const Var *varlist, const Token *tok);
+ bool checkConstFunc(const std::string &classname, const std::vector &derivedFrom, const Var *varlist, const Token *tok);
+
+ /** @brief check if this function is virtual in the base classes */
+ bool isVirtual(const std::vector &derivedFrom, const Token *functionToken) const;
/**
* @brief Helper function for operatorEqRetRefThis that checks if there are errors
diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp
index fe3f25607..7bb15b0ee 100644
--- a/lib/checkmemoryleak.cpp
+++ b/lib/checkmemoryleak.cpp
@@ -2186,11 +2186,32 @@ void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string
void CheckMemoryLeakInFunction::checkReallocUsage()
{
const Token *tok = _tokenizer->tokens();
- for (; tok; tok = tok->next())
+ while ((tok = Token::findmatch(tok, ") const| {")))
{
- if (Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% ,"))
+ // Record the varid's of the function parameters
+ std::set parameterVarIds;
+ for (tok = tok->link(); tok && tok->str() != "{"; tok = tok->next())
{
- if (tok->varId() == tok->tokAt(4)->varId())
+ if (tok->varId() != 0)
+ parameterVarIds.insert(tok->varId());
+ }
+
+ // Search for the "var = realloc(var, 100);" pattern within this function
+ unsigned int indentlevel = 0;
+ for (tok = tok->next(); tok; tok = tok->next())
+ {
+ if (tok->str() == "{")
+ ++indentlevel;
+ else if (tok->str() == "}")
+ {
+ if (indentlevel == 0)
+ break;
+ --indentlevel;
+ }
+
+ if (Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% ,") &&
+ tok->varId() == tok->tokAt(4)->varId() &&
+ parameterVarIds.find(tok->varId()) == parameterVarIds.end())
{
memleakUponReallocFailureError(tok, tok->str());
}
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 0cab94dbf..ad36087a2 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -3395,6 +3395,22 @@ private:
// it is possible that the variable is initialized here
if (Token::Match(tok2->previous(), "[(,] %var% [,)]"))
bailouts.insert(tok2->varId());
+
+ // array initialization..
+ if (Token::Match(tok2->previous(), "[,(] %var% +"))
+ {
+ // if var is array, bailout
+ for (std::list::const_iterator it = checks.begin(); it != checks.end(); ++it)
+ {
+ if ((*it)->varId == tok2->varId())
+ {
+ const CheckUninitVar *c = dynamic_cast(*it);
+ if (c && c->array)
+ bailouts.insert(tok2->varId());
+ break;
+ }
+ }
+ }
}
}
@@ -3945,7 +3961,11 @@ void CheckOther::charBitOpError(const Token *tok)
void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
{
- reportError(tok, Severity::style, "variableScope", "The scope of the variable " + varname + " can be reduced");
+ reportError(tok,
+ Severity::style,
+ "variableScope",
+ "The scope of the variable " + varname + " can be reduced\n"
+ "Be very careful when you reduce the scope! The logical behaviour can be changed by mistake, for example when reducing the scope in a loop.");
}
void CheckOther::conditionAlwaysTrueFalse(const Token *tok, const std::string &truefalse)
diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp
index 92c3a556c..0ad8cfaf0 100644
--- a/lib/checkunusedfunctions.cpp
+++ b/lib/checkunusedfunctions.cpp
@@ -90,7 +90,7 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer)
// Multiple files => filename = "+"
else if (func.filename != tokenizer.getFiles()->at(0))
{
- func.filename = "+";
+ //func.filename = "+";
func.usedOtherFile |= func.usedSameFile;
}
}
diff --git a/lib/errorlogger.h b/lib/errorlogger.h
index 56772d9d7..248bbf5e3 100644
--- a/lib/errorlogger.h
+++ b/lib/errorlogger.h
@@ -16,10 +16,10 @@
* along with this program. If not, see .
*/
-// THIS FILE IS GENERATED BY MACHINE, SEE ../tools/errmsg.cpp !
#ifndef errorloggerH
#define errorloggerH
+
#include
#include
#include "settings.h"
@@ -168,189 +168,6 @@ public:
*/
virtual void reportStatus(unsigned int index, unsigned int max) = 0;
- static bool outOfBounds()
- {
- return true;
- }
-
- static bool stlOutOfBounds()
- {
- return true;
- }
-
- static bool noConstructor(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool uninitVar(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool unusedPrivateFunction(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool memsetClass()
- {
- return true;
- }
-
- static bool memsetStruct()
- {
- return true;
- }
-
- static bool operatorEq(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool virtualDestructor()
- {
- return true;
- }
-
- static bool mismatchAllocDealloc()
- {
- return true;
- }
-
- static bool memleak()
- {
- return true;
- }
-
- static bool resourceLeak()
- {
- return true;
- }
-
- static bool deallocDealloc()
- {
- return true;
- }
-
- static bool deallocuse()
- {
- return true;
- }
-
- static bool mismatchSize()
- {
- return true;
- }
-
- static bool cstyleCast(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool redundantIfDelete0(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool redundantIfRemove(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool dangerousUsageStrtol()
- {
- return true;
- }
-
- static bool ifNoAction(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool sprintfOverlappingData()
- {
- return true;
- }
-
-
- static bool udivError()
- {
- return true;
- }
-
-
- static bool unusedStructMember(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool passedByValue(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
- static bool constStatement(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool charArrayIndex(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool charBitOp(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool variableScope()
- {
- return false;
- }
-
- static bool conditionAlwaysTrueFalse(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool strPlusChar()
- {
- return true;
- }
-
-
- static bool returnLocalVariable()
- {
- return true;
- }
-
-
- static bool dangerousFunctionmktemp(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool dangerousFunctiongets(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
- static bool dangerousFunctionscanf(const Settings &s)
- {
- return s._checkCodingStyle;
- }
-
-
static std::string callStackToString(const std::list &callStack);
};
diff --git a/lib/executionpath.cpp b/lib/executionpath.cpp
index a7012aa59..846e3c5ff 100644
--- a/lib/executionpath.cpp
+++ b/lib/executionpath.cpp
@@ -192,6 +192,13 @@ static void checkExecutionPaths_(const Token *tok, std::list &c
if (tok->str() == "switch")
{
+ // parse condition
+ if (checks.size() > 10 || check->parseCondition(*tok->next(), checks))
+ {
+ ExecutionPath::bailOut(checks);
+ return;
+ }
+
const Token *tok2 = tok->next()->link();
if (Token::simpleMatch(tok2, ") { case"))
{
diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp
index 232d203dd..d3bc04705 100644
--- a/lib/preprocessor.cpp
+++ b/lib/preprocessor.cpp
@@ -1397,7 +1397,11 @@ void Preprocessor::handleIncludes(std::string &code, const std::string &filePath
if (headerType == 1 && !fileOpened)
{
filename = paths.back() + filename;
- fin.open(filename.c_str());
+
+ // Linux can't open include paths with \ separator, so fix them
+ std::string fixedname(filename);
+ std::replace(fixedname.begin(), fixedname.end(), '\\', '/');
+ fin.open(fixedname.c_str());
if (fin.is_open())
{
fileOpened = true;
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index 9ffc24700..72ecf02df 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -359,8 +359,9 @@ void Tokenizer::createTokens(std::istream &code)
{
if (lineNumbers.empty() || fileIndexes.empty())
{
- std::cerr << "####### Preprocessor bug! #######\n";
- std::exit(0);
+ cppcheckError(0);
+ deallocateTokens();
+ return;
}
lineno = lineNumbers.back();
@@ -5734,8 +5735,9 @@ bool Tokenizer::simplifyRedundantParanthesis()
ret = true;
}
- if ((Token::simpleMatch(tok->previous(), "delete (") && Token::Match(tok->link(), ") ;|,")) ||
- (Token::simpleMatch(tok->previous(), "; (") && Token::Match(tok->link(), ") ;")))
+ if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") &&
+ Token::Match(tok->previous(), "delete|; (") &&
+ Token::Match(tok->link(), ") ;|,"))
{
tok->link()->deleteThis();
tok->deleteThis();
diff --git a/test/testclass.cpp b/test/testclass.cpp
index d3c2cc2e5..c56401fa9 100644
--- a/test/testclass.cpp
+++ b/test/testclass.cpp
@@ -52,6 +52,7 @@ private:
TEST_CASE(uninitVar6);
TEST_CASE(uninitVar7);
TEST_CASE(uninitVar8);
+ TEST_CASE(uninitVar9); // ticket #1730
TEST_CASE(uninitVarEnum);
TEST_CASE(uninitVarStream);
TEST_CASE(uninitVarTypedef);
@@ -128,6 +129,8 @@ private:
TEST_CASE(const24); // ticket #1708
TEST_CASE(const25); // ticket #1724
TEST_CASE(const26); // ticket #1847
+ TEST_CASE(const27); // ticket #1882
+ TEST_CASE(const28); // ticket #1883
TEST_CASE(constoperator1); // operator< can often be const
TEST_CASE(constoperator2); // operator<<
TEST_CASE(constincdec); // increment/decrement => non-const
@@ -135,6 +138,7 @@ private:
TEST_CASE(constDelete); // delete member variable => not const
TEST_CASE(constLPVOID); // a function that returns LPVOID can't be const
TEST_CASE(constFunc); // a function that calls const functions can be const
+ TEST_CASE(constVirtualFunc);
}
// Check the operator Equal
@@ -1583,6 +1587,21 @@ private:
ASSERT_EQUALS("[test.cpp:8]: (style) Member variable 'Foo::a' is not assigned a value in 'Foo::operator='\n", errout.str());
}
+ void uninitVar9() // ticket #1730
+ {
+ checkUninitVar("class Prefs {\n"
+ "private:\n"
+ " int xasd;\n"
+ "public:\n"
+ " Prefs(wxSize size);\n"
+ "};\n"
+ "Prefs::Prefs(wxSize size)\n"
+ "{\n"
+ " SetMinSize( wxSize( 48,48 ) );\n"
+ "}\n");
+ ASSERT_EQUALS("[test.cpp:7]: (style) Member variable not initialized in the constructor 'Prefs::xasd'\n", errout.str());
+ }
+
void uninitVarArray1()
{
checkUninitVar("class John\n"
@@ -3594,6 +3613,45 @@ private:
ASSERT_EQUALS("", errout.str());
}
+ void const28() // ticket #1883
+ {
+ checkConst("class P {\n"
+ "public:\n"
+ " P() { x=0.0; y=0.0; }\n"
+ " double x,y;\n"
+ "};\n"
+ "class A : public P {\n"
+ "public:\n"
+ " A():P(){}\n"
+ " void SetPos(double xPos, double yPos) {\n"
+ " x=xPos;\n"
+ " y=yPos;\n"
+ " }\n"
+ "};\n"
+ );
+ ASSERT_EQUALS("", errout.str());
+ }
+
+ void const27() // ticket #1882
+ {
+ checkConst("class A {\n"
+ "public:\n"
+ " A(){m_d=1.0; m_iRealVal=2.0;}\n"
+ " double dGetValue();\n"
+ "private:\n"
+ " double m_d;\n"
+ " double m_iRealVal;\n"
+ "};\n"
+ "double A::dGetValue() {\n"
+ " double dRet = m_iRealVal;\n"
+ " if( m_d != 0 )\n"
+ " return dRet / m_d;\n"
+ " return dRet;\n"
+ "};\n"
+ );
+ ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:4]: (style) The function 'A::dGetValue' can be const\n", errout.str());
+ }
+
// increment/decrement => not const
void constincdec()
{
@@ -3660,6 +3718,114 @@ private:
"}");
TODO_ASSERT_EQUALS("[test.cpp:7]: (style) The function 'A::GetVecSize' can be const\n", errout.str());
}
+
+ void constVirtualFunc()
+ {
+ // base class has no virtual function
+ checkConst("class A { };\n"
+ "class B : public A {\n"
+ " int b;\n"
+ "public:\n"
+ " B() : b(0) { }\n"
+ " int func() { return b; }\n"
+ "};");
+ ASSERT_EQUALS("[test.cpp:6]: (style) The function 'B::func' can be const\n", errout.str());
+
+ // base class has no virtual function
+ checkConst("class A {\n"
+ "public:\n"
+ " int func();\n"
+ "};\n"
+ "class B : public A {\n"
+ " int b;\n"
+ "public:\n"
+ " B() : b(0) { }\n"
+ " int func() { return b; }\n"
+ "};\n");
+ ASSERT_EQUALS("[test.cpp:9]: (style) The function 'B::func' can be const\n", errout.str());
+
+ // base class has virtual function
+ checkConst("class A {\n"
+ "public:\n"
+ " virtual int func();\n"
+ "};\n"
+ "class B : public A {\n"
+ " int b;\n"
+ "public:\n"
+ " B() : b(0) { }\n"
+ " int func() { return b; }\n"
+ "};\n");
+ ASSERT_EQUALS("", errout.str());
+
+ // base class has no virtual function
+ checkConst("class A {\n"
+ " int a;\n"
+ "public:\n"
+ " A() : a(0) { }\n"
+ " int func() { return a; }\n"
+ "};\n"
+ "class B : public A {\n"
+ " int b;\n"
+ "public:\n"
+ " B() : b(0) { }\n"
+ " int func() { return b; }\n"
+ "};\n"
+ "class C : public B {\n"
+ " int c;\n"
+ "public:\n"
+ " C() : c(0) { }\n"
+ " int func() { return c; }\n"
+ "};\n");
+ ASSERT_EQUALS("[test.cpp:5]: (style) The function 'A::func' can be const\n"
+ "[test.cpp:11]: (style) The function 'B::func' can be const\n"
+ "[test.cpp:17]: (style) The function 'C::func' can be const\n", errout.str());
+
+ // base class has virtual function
+ checkConst("class A {\n"
+ " int a;\n"
+ "public:\n"
+ " A() : a(0) { }\n"
+ " virtual int func() { return a; }\n"
+ "};\n"
+ "class B : public A {\n"
+ " int b;\n"
+ "public:\n"
+ " B() : b(0) { }\n"
+ " int func() { return b; }\n"
+ "};\n"
+ "class C : public B {\n"
+ " int c;\n"
+ "public:\n"
+ " C() : c(0) { }\n"
+ " int func() { return c; }\n"
+ "};\n");
+ ASSERT_EQUALS("", errout.str());
+
+ // ticket #1311
+ checkConst("class X {\n"
+ " int x;\n"
+ "public:\n"
+ " X(int x) : x(x) { }\n"
+ " int getX() { return x; }\n"
+ "};\n"
+ "class Y : public X {\n"
+ " int y;\n"
+ "public:\n"
+ " Y(int x, int y) : X(x), y(y) { }\n"
+ " int getY() { return y; }\n"
+ "};\n"
+ "class Z : public Y {\n"
+ " int z;\n"
+ "public:\n"
+ " Z(int x, int y, int z) : Y(x, y), z(z) { }\n"
+ " int getZ() { return z; }\n"
+ "};\n"
+ " }\n"
+ "};");
+ ASSERT_EQUALS("[test.cpp:5]: (style) The function 'X::getX' can be const\n"
+ "[test.cpp:11]: (style) The function 'Y::getY' can be const\n"
+ "[test.cpp:17]: (style) The function 'Z::getZ' can be const\n", errout.str());
+ }
};
REGISTER_TEST(TestClass)
diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp
index 88d6a3613..ed51eb141 100644
--- a/test/testconstructors.cpp
+++ b/test/testconstructors.cpp
@@ -733,6 +733,63 @@ private:
"[test.cpp:21]: (style) Member variable not initialized in the constructor 'B::b'\n"
"[test.cpp:22]: (style) Member variable not initialized in the constructor 'C::c'\n"
"[test.cpp:23]: (style) Member variable not initialized in the constructor 'D::d'\n", errout.str());
+
+ check("class A {\n"
+ "public:\n"
+ " A();\n"
+ " struct B {\n"
+ " B();\n"
+ " struct C {\n"
+ " C();\n"
+ " struct D {\n"
+ " D(const D &);\n"
+ " int d;\n"
+ " };\n"
+ " int c;\n"
+ " };\n"
+ " int b;\n"
+ " };\n"
+ "private:\n"
+ " int a;\n"
+ " B b;\n"
+ "};\n"
+ "A::A(){}\n"
+ "A::B::B(){}\n"
+ "A::B::C::C(){}\n"
+ "A::B::C::D::D(const A::B::C::D & d){}\n");
+ ASSERT_EQUALS("[test.cpp:20]: (style) Member variable not initialized in the constructor 'A::a'\n"
+ "[test.cpp:21]: (style) Member variable not initialized in the constructor 'B::b'\n"
+ "[test.cpp:22]: (style) Member variable not initialized in the constructor 'C::c'\n"
+ "[test.cpp:23]: (style) Member variable not initialized in the constructor 'D::d'\n", errout.str());
+
+ check("class A {\n"
+ "public:\n"
+ " A();\n"
+ " struct B {\n"
+ " B();\n"
+ " struct C {\n"
+ " C();\n"
+ " struct D {\n"
+ " struct E { };\n"
+ " E d;\n"
+ " D(const E &);\n"
+ " };\n"
+ " int c;\n"
+ " };\n"
+ " int b;\n"
+ " };\n"
+ "private:\n"
+ " int a;\n"
+ " B b;\n"
+ "};\n"
+ "A::A(){}\n"
+ "A::B::B(){}\n"
+ "A::B::C::C(){}\n"
+ "A::B::C::D::D(const A::B::C::D::E & e){}\n");
+ ASSERT_EQUALS("[test.cpp:21]: (style) Member variable not initialized in the constructor 'A::a'\n"
+ "[test.cpp:22]: (style) Member variable not initialized in the constructor 'B::b'\n"
+ "[test.cpp:23]: (style) Member variable not initialized in the constructor 'C::c'\n"
+ "[test.cpp:24]: (style) Member variable not initialized in the constructor 'D::d'\n", errout.str());
}
void initvar_destructor()
diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp
index e65788036..07058e0ec 100644
--- a/test/testmemleak.cpp
+++ b/test/testmemleak.cpp
@@ -40,6 +40,7 @@ private:
TEST_CASE(test2);
TEST_CASE(test3);
TEST_CASE(test4);
+ TEST_CASE(test5);
}
void check(const char code[])
@@ -104,6 +105,21 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
}
+
+ void test5() //#ticket 1879
+ {
+ check("void test()\n"
+ "{\n"
+ " int *a = new int[10];\n"
+ " try\n"
+ " {\n"
+ " }\n"
+ " catch(...)\n"
+ " {\n"
+ " }\n"
+ "}\n");
+ ASSERT_EQUALS("[test.cpp:10]: (error) Memory leak: a\n",errout.str());
+ }
};
static TestLocalLeaks testLocalLeaks;
@@ -313,6 +329,7 @@ private:
TEST_CASE(realloc4);
TEST_CASE(realloc5);
TEST_CASE(realloc6);
+ TEST_CASE(realloc7);
TEST_CASE(assign);
@@ -1996,6 +2013,21 @@ private:
ASSERT_EQUALS(";;alloc;", getcode("char *buf; buf=realloc(0,100);", "buf"));
}
+ void realloc7()
+ {
+ check("bool foo(size_t nLen, char* pData)\n"
+ "{\n"
+ " pData = (char*) realloc(pData, sizeof(char) + (nLen + 1)*sizeof(char));\n"
+ " if ( pData == NULL )\n"
+ " {\n"
+ " return false;\n"
+ " }\n"
+ " free(pData);\n"
+ " return true;\n"
+ "}\n", false);
+ ASSERT_EQUALS("", errout.str());
+ }
+
void assign()
{
check("void foo()\n"
diff --git a/test/testother.cpp b/test/testother.cpp
index d5db3bbf7..b3bd301f5 100644
--- a/test/testother.cpp
+++ b/test/testother.cpp
@@ -1834,6 +1834,18 @@ private:
" } catch (...) {\n"
" }\n"
"}\n");
+
+ // #1855 - switch(foo(&x))
+ checkUninitVar("int a()\n"
+ "{\n"
+ " int x;\n"
+ " switch (foo(&x))\n"
+ " {\n"
+ " case 1:\n"
+ " return x;\n"
+ " }\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
}
// arrays..
@@ -1909,6 +1921,16 @@ private:
" strchr(s, ' ');\n"
"};\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s\n", errout.str());
+
+ checkUninitVar("void foo()\n"
+ "{\n"
+ " int y[2];\n"
+ " int s;\n"
+ " GetField( y + 0, \n"
+ " y + 1 );\n"
+ " s = y[0]*y[1];\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
}
// alloc..
diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp
index 330ba12ea..51f0d677f 100644
--- a/test/testtokenize.cpp
+++ b/test/testtokenize.cpp
@@ -165,13 +165,14 @@ private:
TEST_CASE(simplify_function_parameters);
- TEST_CASE(removeParantheses1); // Ticket #61
+ TEST_CASE(removeParantheses1); // Ticket #61
TEST_CASE(removeParantheses2);
TEST_CASE(removeParantheses3);
TEST_CASE(removeParantheses4); // Ticket #390
TEST_CASE(removeParantheses5); // Ticket #392
TEST_CASE(removeParantheses6);
TEST_CASE(removeParantheses7);
+ TEST_CASE(removeParantheses8); // Ticket #1865
TEST_CASE(tokenize_double);
TEST_CASE(tokenize_strings);
@@ -3014,6 +3015,20 @@ private:
ASSERT_EQUALS(" ; delete p ; ( p ) = 0 ;", ostr.str());
}
+ void removeParantheses8()
+ {
+ const char code[] = "struct foo {\n"
+ " void operator delete(void *obj, size_t sz);\n"
+ "}\n";
+ const std::string actual(tokenizeAndStringify(code));
+
+ const char expected[] = "struct foo {\n"
+ "void operator delete ( void * obj , size_t sz ) ;\n"
+ "}";
+
+ ASSERT_EQUALS(expected, actual);
+ }
+
void tokenize_double()
{
const char code[] = "void f()\n"
diff --git a/test/testunusedfunctions.cpp b/test/testunusedfunctions.cpp
index 0c709d6c4..2689b7783 100644
--- a/test/testunusedfunctions.cpp
+++ b/test/testunusedfunctions.cpp
@@ -45,6 +45,8 @@ private:
TEST_CASE(throwIsNotAFunction);
TEST_CASE(unusedError);
TEST_CASE(initializationIsNotAFunction);
+
+ TEST_CASE(multipleFiles); // same function name in multiple files
}
void check(const char code[])
@@ -181,6 +183,33 @@ private:
"};\n");
ASSERT_EQUALS("", errout.str());
}
+
+ void multipleFiles()
+ {
+ CheckUnusedFunctions c;
+
+ // Clear the error buffer..
+ errout.str("");
+
+ const char code[] = "static void f() { }";
+
+ for (int i = 1; i <= 2; ++i)
+ {
+ std::ostringstream fname;
+ fname << "test" << i << ".cpp";
+
+ Tokenizer tokenizer;
+ std::istringstream istr(code);
+ tokenizer.tokenize(istr, fname.str().c_str());
+
+ c.parseTokens(tokenizer);
+ }
+
+ // Check for unused functions..
+ c.check(this);
+
+ ASSERT_EQUALS("[test1.cpp:1]: (style) The function 'f' is never used\n",errout.str());
+ }
};
REGISTER_TEST(TestUnusedFunctions)