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 + + + Checking Log + + + + + Clear + + + + + Close + + + MainWindow - - - - + + + + Cppcheck - + Standard @@ -156,265 +174,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 - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + &New Project File... - + + &Log View + + + + + Log View + + + + &Contents - + Categories - + Open the help contents - + F1 - + &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) - + Open the report file - + Checking is running. Do you want to stop the checking and exit Cppcheck?. - + Text files (*.txt) - + CSV files (*.csv) - + Cppcheck - %1 - + Failed to change the language: %1 @@ -426,18 +454,18 @@ Do you want to stop the checking and exit Cppcheck?. - - + + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + Select Project Filename 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 + + + Checking Log + + + + + Clear + + + + + Close + + + MainWindow - - - - + + + + Cppcheck Cppcheck - + Standard Standard @@ -169,265 +187,275 @@ kate -l(line) (file) - + &Check &Check - + &Edit &Edit - + &License... &License... - + A&uthors... A&uthors... - + &About... &About... - + &Files... &Files... - + Ctrl+F Ctrl+F - + &Directory... &Directory... - + Ctrl+D Ctrl+D - + &Recheck files &Recheck files - + Ctrl+R Ctrl+R - + &Stop &Stop - + Esc Esc - + &Save results to file... &Save results to file... - + Ctrl+S Ctrl+S - + &Quit &Quit - + &Clear results &Clear results - + &Preferences &Preferences - + Show style errors Show style errors - + Show common errors Show common errors - + &Check all &Check all - + &Uncheck all &Uncheck all - + Collapse &all Collapse &all - + &Expand all &Expand all - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + &New Project File... - + + &Log View + + + + + Log View + + + + &Contents - + Categories - + Open the help contents - + F1 - + &Language &Language - + &Help &Help - + Select files to check Select files to check - + Select directory to check Select directory to check - + No suitable files found to check! No suitable files found to check! - + License License - + Authors Authors - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Save the report file Save the report file - - + + XML files (*.xml) XML files (*.xml) - + Open the report file - + Checking is running. Do you want to stop the checking and exit Cppcheck?. - + Text files (*.txt) Text files (*.txt) - + CSV files (*.csv) - + Cppcheck - %1 Cppcheck - %1 - + Failed to change the language: %1 @@ -441,18 +469,18 @@ Do you want to stop the checking and exit Cppcheck?. %1 - - + + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + Select Project Filename 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 + + + Checking Log + + + + + Clear + + + + + Close + + + MainWindow - - - - + + + + Cppcheck Cppcheck - + Standard Vakio @@ -171,265 +189,275 @@ kate -l(line) (file) - + &Check &Tarkista - + &Edit &Muokkaa - + &License... &Lisenssi... - + A&uthors... &Tekijät... - + &About... &Tietoa ohjelmasta Cppcheck... - + &Files... &Tiedostot... - + Ctrl+F Ctrl+F - + &Directory... &Hakemisto... - + Ctrl+D Ctrl+D - + &Recheck files Tarkista tiedostot &uudelleen - + Ctrl+R Ctrl+R - + &Stop &Pysäytä - + Esc Esc - + &Save results to file... &Tallenna tulokset tiedostoon... - + Ctrl+S Ctrl+S - + &Quit &Lopeta - + &Clear results &Tyhjennä tulokset - + &Preferences &Asetukset - + Show style errors Näytä tyylivirheet - + Show common errors Näytä yleiset virheet - + &Check all &Valitse kaikki - + &Uncheck all &Poista kaikista valinta - + Collapse &all &Pienennä kaikki - + &Expand all &Laajenna kaikki - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + &New Project File... - + + &Log View + + + + + Log View + + + + &Contents - + Categories - + Open the help contents - + F1 - + &Language &Kieli - + &Help &Ohje - + Select files to check Valitse tarkistettavat tiedostot - + Select directory to check Valitse tarkistettava hakemisto - + No suitable files found to check! Tarkistettavaksi sopivia tiedostoja ei löytynyt! - + License Lisenssi - + Authors Tekijät - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML-tiedostot (*.xml);;Tekstitiedostot (*.txt);;CSV-tiedostot (*.csv) - + Save the report file Tallenna raportti - - + + XML files (*.xml) XML-tiedostot (*xml) - + Open the report file - + Checking is running. Do you want to stop the checking and exit Cppcheck?. - + Text files (*.txt) Tekstitiedostot (*.txt) - + CSV files (*.csv) - + Cppcheck - %1 Cppcheck - %1 - + Failed to change the language: %1 @@ -445,18 +473,18 @@ Do you want to stop the checking and exit Cppcheck?. - - + + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + Select Project Filename 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 + + + Checking Log + + + + + Clear + + + + + Close + + + MainWindow - - - - + + + + Cppcheck Cppcheck - + Standard Standaard @@ -169,265 +187,275 @@ kate -l(line) (file) - + &Check &Controleer - + &Edit Be&werken - + &License... &Licentie... - + A&uthors... A&uteurs... - + &About... &Over... - + &Files... &Bestanden... - + Ctrl+F Ctrl+F - + &Directory... &Mappen... - + Ctrl+D Ctrl+D - + &Recheck files &Opnieuw controleren - + Ctrl+R Ctrl+R - + &Stop &Stop - + Esc Esc - + &Save results to file... &Resultaten opslaan... - + Ctrl+S Ctrl+S - + &Quit &Afsluiten - + &Clear results &Resultaten wissen - + &Preferences &Voorkeuren - + Show style errors Toon stijl fouten - + Show common errors Toon gewone fouten - + &Check all &Selecteer alles - + &Uncheck all Selecteer &niets - + Collapse &all Alles Inkl&appen - + &Expand all Alles &Uitklappen - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + &New Project File... - + + &Log View + + + + + Log View + + + + &Contents - + Categories - + Open the help contents - + F1 - + &Language &Taal - + &Help &Help - + Select files to check Selecteer bestanden om te controleren - + Select directory to check Selecteer een map om te controleren - + No suitable files found to check! Geen geschikte bestanden gevonden om te controleren! - + License Licentie - + Authors Auteurs - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML bestanden (*.xml);;Tekst bestanden (*.txt);;CSV bestanden (*.csv) - + Save the report file Rapport opslaan - - + + XML files (*.xml) XML bestanden (*.xml) - + Open the report file - + Checking is running. Do you want to stop the checking and exit Cppcheck?. - + Text files (*.txt) Tekst bestanden (*.txt) - + CSV files (*.csv) - + Cppcheck - %1 Cppcheck - %1 - + Failed to change the language: %1 @@ -441,18 +469,18 @@ Do you want to stop the checking and exit Cppcheck?. %1 - - + + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + Select Project Filename 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 + + + Checking Log + + + + + Clear + + + + + Close + + + MainWindow - - - - + + + + Cppcheck @@ -151,275 +169,285 @@ kate -l(line) (file) - + &Language - + &Help - + &Check - + &Edit - + Standard - + &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 - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + &New Project File... - + + &Log View + + + + + Log View + + + + &Contents - + Categories - + Open the help contents - + F1 - + No suitable files found to check! - + Select files to check - + Select directory to check - + Open the report file - + License - + Authors - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Save the report file - + Select Project Filename - - + + XML files (*.xml) - + Checking is running. Do you want to stop the checking and exit Cppcheck?. - + Text files (*.txt) - + CSV files (*.csv) - + Cppcheck - %1 - + Failed to change the language: %1 @@ -428,13 +456,13 @@ Do you want to stop the checking and exit Cppcheck?. - - + + Project files (*.cppcheck);;All files(*.*) - + Select Project 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 + + + Checking Log + + + + + Clear + + + + + Close + + + MainWindow - - - - + + + + Cppcheck Cppcheck - + Standard @@ -159,265 +177,275 @@ kate -l(line) (file) - + &Check Проверить - + &Edit Правка - + &License... Лицензия... - + A&uthors... Авторы... - + &About... О программе... - + &Files... Файлы... - + Ctrl+F Ctrl+F - + &Directory... Каталог... - + Ctrl+D Ctrl+D - + &Recheck files - + Ctrl+R Ctrl+R - + &Stop Остановить - + Esc Esc - + &Save results to file... Сохранить отчёт в файл... - + Ctrl+S Ctrl+S - + &Quit Выход - + &Clear results Очистить отчёт - + &Preferences Параметры - + Show style errors Показывать ошибки стиля - + Show common errors Показывать общие ошибки - + &Check all Отметить все - + &Uncheck all Сбросить все - + Collapse &all Свернуть все - + &Expand all Развернуть все - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + &New Project File... - + + &Log View + + + + + Log View + + + + &Contents - + Categories - + Open the help contents - + F1 - + &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) - + Open the report file - + Checking is running. Do you want to stop the checking and exit Cppcheck?. - + Text files (*.txt) Текстовые файлы (*.txt) - + CSV files (*.csv) - + Cppcheck - %1 Cppcheck - %1 - + Failed to change the language: %1 @@ -433,18 +461,18 @@ Do you want to stop the checking and exit Cppcheck?. - - + + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + Select Project Filename 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 + + + Checking Log + + + + + Clear + + + + + Close + + + MainWindow - - - - + + + + Cppcheck Cppcheck - + Standard Standard @@ -169,266 +187,276 @@ kate -l(line) (file) Verktygsfält - + &Check &Check - + &Edit &Redigera - + &License... &Licens... - + A&uthors... &Utvecklat av... - + &About... &Om... - + &Files... &Filer... - + Ctrl+F Ctrl+F - + &Directory... &Katalog... - + Ctrl+D Ctrl+D - + &Recheck files Starta &om check - + Ctrl+R Ctrl+R - + &Stop &Stoppa - + Esc Esc - + &Save results to file... &Spara resultat till fil... - + Ctrl+S Ctrl+S - + &Quit &Avsluta - + &Clear results &Töm resultat - + &Preferences &Inställningar - + Show style errors Visa stilvarningar - + Show common errors Visa vanliga fel - + &Check all &Kryssa alla - + &Uncheck all Kryssa &ur alla - + Collapse &all Ingen bra översättning! &Fäll ihop alla - + &Expand all &Expandera alla - + &Standard &Standard - + Standard items Standard poster - + Toolbar Verktygsfält - + &Categories &Kategorier - + Error categories Fel kategorier - + &Open XML... - + Open P&roject File... - + &New Project File... - + + &Log View + + + + + Log View + + + + &Contents &Innehåll - + Categories Kategorier - + Open the help contents Öppna hjälp - + F1 F1 - + &Language &Språk - + &Help &Hjälp - + Select files to check Välj filer att kontrollera - + Select directory to check Välj katalog som skall kontrolleras - + No suitable files found to check! Inga lämpliga filer hittades! - + License Licens - + Authors Utvecklare - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML filer (*.xml);;Text filer (*.txt);;CSV filer (*.csv) - + Save the report file Spara rapport - - + + XML files (*.xml) XML filer (*.xml) - + Open the report file - + Checking is running. Do you want to stop the checking and exit Cppcheck?. - + Text files (*.txt) Text filer (*.txt) - + CSV files (*.csv) CSV filer (*.csv) - + Cppcheck - %1 Cppcheck - %1 - + Failed to change the language: %1 @@ -444,18 +472,18 @@ Do you want to stop the checking and exit Cppcheck?. - - + + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + Select Project Filename 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 @@ + @@ -365,6 +366,14 @@ &New Project File... + + + &Log View + + + Log View + + 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)