From 87a118cd16ce59cc20af67d5c62cd45d217075a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 14 Feb 2012 21:16:11 +0100 Subject: [PATCH] GUI: Recheck changed files. Ticket: #816 --- gui/erroritem.cpp | 1 + gui/erroritem.h | 1 + gui/mainwindow.cpp | 14 +++++---- gui/resultstree.cpp | 26 ++++++++++++++-- gui/resultstree.h | 8 ++++- gui/resultsview.cpp | 13 ++++++++ gui/resultsview.h | 5 ++++ gui/threadhandler.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++- gui/threadhandler.h | 23 +++++++++++++- gui/threadresult.cpp | 5 ++-- 10 files changed, 154 insertions(+), 12 deletions(-) diff --git a/gui/erroritem.cpp b/gui/erroritem.cpp index 101c779e5..5e2d9e51d 100644 --- a/gui/erroritem.cpp +++ b/gui/erroritem.cpp @@ -27,6 +27,7 @@ ErrorItem::ErrorItem() ErrorItem::ErrorItem(const ErrorItem &item) { file = item.file; + file0 = item.file0; files = item.files; lines = item.lines; errorId = item.errorId; diff --git a/gui/erroritem.h b/gui/erroritem.h index da8e8e3ec..705f856ae 100644 --- a/gui/erroritem.h +++ b/gui/erroritem.h @@ -105,6 +105,7 @@ public: QString file; QStringList files; + QString file0; QList lines; QString errorId; Severity::SeverityType severity; diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index bd0a60424..1c9a061b7 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -582,12 +582,16 @@ void MainWindow::ProgramSettings() void MainWindow::ReCheck() { - ClearResults(); - CheckLockDownUI(); // lock UI while checking + const QStringList files = mThread->GetReCheckFiles(); + if (files.empty()) + return; - const int filesCount = mThread->GetPreviousFilesCount(); - Q_ASSERT(filesCount > 0); // If no files should not be able to recheck - mUI.mResults->CheckingStarted(filesCount); + // Clear results for changed files + for (int i = 0; i < files.size(); ++i) + mUI.mResults->Clear(files[i]); + + CheckLockDownUI(); // lock UI while checking + mUI.mResults->CheckingStarted(files.size()); if (mProject) qDebug() << "Rechecking project file" << mProject->GetProjectFile()->GetFilename(); diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index da09327e5..7b6a17688 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -134,7 +134,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) line.severity = item.severity; //Create the base item for the error and ensure it has a proper //file item as a parent - QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, hide), + QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, item.file0, hide), line, hide, SeverityToIcon(line.severity)); @@ -152,6 +152,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) data["line"] = item.lines[0]; data["id"] = item.errorId; data["inconclusive"] = item.inconclusive; + data["file0"] = item.file0; stditem->setData(QVariant(data)); //Add backtrace files as children @@ -303,6 +304,25 @@ void ResultsTree::Clear() mModel.removeRows(0, mModel.rowCount()); } +void ResultsTree::Clear(const QString &filename) +{ + const QString stripped = StripPath(filename, false); + + for (int i = 0; i < mModel.rowCount(); ++i) { + const QStandardItem *item = mModel.item(i, 0); + if (!item) + continue; + + QVariantMap data = item->data().toMap(); + if (stripped == data["file"].toString() || + filename == data["file0"].toString()) { + mModel.removeRow(i); + break; + } + } +} + + void ResultsTree::LoadSettings() { for (int i = 0; i < mModel.columnCount(); i++) { @@ -433,7 +453,7 @@ void ResultsTree::RefreshTree() } } -QStandardItem *ResultsTree::EnsureFileItem(const QString &fullpath, bool hide) +QStandardItem *ResultsTree::EnsureFileItem(const QString &fullpath, const QString &file0, bool hide) { QString name = StripPath(fullpath, false); // Since item has path with native separators we must use path with @@ -452,6 +472,7 @@ QStandardItem *ResultsTree::EnsureFileItem(const QString &fullpath, bool hide) //Add user data to that item QMap data; data["file"] = fullpath; + data["file0"] = file0; item->setData(QVariant(data)); mModel.appendRow(item); @@ -828,6 +849,7 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item) item.message = data["message"].toString(); item.errorId = data["id"].toString(); item.inconclusive = data["inconclusive"].toBool(); + item.file0 = data["file0"].toString(); QString file = StripPath(data["file"].toString(), true); unsigned int line = data["line"].toUInt(); diff --git a/gui/resultstree.h b/gui/resultstree.h index d0b6419b4..d6b35be71 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -66,6 +66,11 @@ public: */ void Clear(); + /** + * @brief Clear errors for a specific file from the tree + */ + void Clear(const QString &filename); + /** * @brief Function to show/hide certain type of errors * Refreshes the tree. @@ -339,10 +344,11 @@ protected: * @brief Ensures there's a item in the model for the specified file * * @param fullpath Full path to the file item. + * @param file0 Source file * @param hide is the error (we want this file item for) hidden? * @return QStandardItem to be used as a parent for all errors for specified file */ - QStandardItem *EnsureFileItem(const QString &fullpath, bool hide); + QStandardItem *EnsureFileItem(const QString &fullpath, const QString &file0, bool hide); /** * @brief Show a file item diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 4f03023f9..dbf9e2a98 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -80,6 +80,19 @@ void ResultsView::Clear() mUI.mProgress->setFormat("%p%"); } +void ResultsView::Clear(const QString &filename) +{ + mUI.mTree->Clear(filename); + mUI.mDetails->setText(""); + mErrorsFound = false; + mStatistics->Clear(); + + // Clear the progressbar + mUI.mProgress->setMaximum(PROGRESS_MAX); + mUI.mProgress->setValue(0); + mUI.mProgress->setFormat("%p%"); +} + void ResultsView::Progress(int value, const QString& description) { mUI.mProgress->setValue(value); diff --git a/gui/resultsview.h b/gui/resultsview.h index 7bdfce0a8..29aa1c03f 100644 --- a/gui/resultsview.h +++ b/gui/resultsview.h @@ -64,6 +64,11 @@ public: */ void Clear(); + /** + * @brief Clear results for a specific file + */ + void Clear(const QString &filename); + /** * @brief Save results to a file * diff --git a/gui/threadhandler.cpp b/gui/threadhandler.cpp index e02464d56..3067b25c1 100644 --- a/gui/threadhandler.cpp +++ b/gui/threadhandler.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include #include "settings.h" @@ -51,7 +52,8 @@ void ThreadHandler::SetFiles(const QStringList &files) void ThreadHandler::Check(const Settings &settings, bool recheck) { if (recheck && mRunningThreadCount == 0) { - mResults.SetFiles(mLastFiles); + // only recheck changed files + mResults.SetFiles(GetReCheckFiles()); } if (mResults.GetFileCount() == 0 || mRunningThreadCount > 0 || settings._jobs <= 0) { @@ -72,6 +74,9 @@ void ThreadHandler::Check(const Settings &settings, bool recheck) mThreads[i]->Check(settings); } + // Date and time when checking starts.. + mCheckStartTime = QDateTime::currentDateTime(); + mTime.start(); } @@ -124,11 +129,18 @@ void ThreadHandler::ThreadDone() emit Done(); mScanDuration = mTime.elapsed(); + + // Set date/time used by the recheck + if (!mCheckStartTime.isNull()) { + mLastCheckTime = mCheckStartTime; + mCheckStartTime = QDateTime(); + } } } void ThreadHandler::Stop() { + mCheckStartTime = QDateTime(); for (int i = 0; i < mThreads.size(); i++) { mThreads[i]->stop(); } @@ -177,3 +189,59 @@ int ThreadHandler::GetPreviousScanDuration() const { return mScanDuration; } + +QStringList ThreadHandler::GetReCheckFiles() const +{ + if (mLastCheckTime.isNull()) + return mLastFiles; + + std::set modified; + std::set unmodified; + + QStringList files; + for (int i = 0; i < mLastFiles.size(); ++i) { + if (NeedsReCheck(mLastFiles[i], modified, unmodified)) + files.push_back(mLastFiles[i]); + } + return files; +} + +bool ThreadHandler::NeedsReCheck(const QString &filename, std::set &modified, std::set &unmodified) const +{ + if (modified.find(filename) != modified.end()) + return true; + + if (unmodified.find(filename) != unmodified.end()) + return false; + + if (QFileInfo(filename).lastModified() > mLastCheckTime) { + return true; + } + + // Parse included files recursively + QFile f(filename); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + // prevent recursion.. + unmodified.insert(filename); + + QTextStream in(&f); + while (!in.atEnd()) { + QString line = in.readLine(); + if (line.startsWith("#include \"")) { + line.remove(0,10); + int i = line.indexOf("\""); + if (i > 0) { + line.remove(i,line.length()); + line = QFileInfo(filename).absolutePath() + "/" + line; + if (NeedsReCheck(line, modified, unmodified)) { + modified.insert(line); + return true; + } + } + } + } + + return false; +} diff --git a/gui/threadhandler.h b/gui/threadhandler.h index e4e9a1b9f..f11c31cb3 100644 --- a/gui/threadhandler.h +++ b/gui/threadhandler.h @@ -22,7 +22,8 @@ #include #include -#include +#include +#include #include "settings.h" #include "cppcheck.h" #include "threadresult.h" @@ -117,6 +118,12 @@ public: */ int GetPreviousScanDuration() const; + /** + * @brief Get files that should be rechecked because they have been + * changed. + */ + QStringList GetReCheckFiles() const; + signals: /** * @brief Signal that all threads are done @@ -147,6 +154,14 @@ protected: */ QStringList mLastFiles; + /** @brief date and time when current checking started */ + QDateTime mCheckStartTime; + + /** + * @brief when was the files checked the last time (used when rechecking) + */ + QDateTime mLastCheckTime; + /** * @brief Timer used for measuring scan duration * @@ -183,6 +198,12 @@ protected: */ int mRunningThreadCount; private: + + /** + * @brief Check if a file needs to be rechecked. Recursively checks + * included headers. Used by GetReCheckFiles() + */ + bool NeedsReCheck(const QString &filename, std::set &modified, std::set &unmodified) const; }; /// @} #endif // THREADHANDLER_H diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp index ba9946877..670fddf3b 100644 --- a/gui/threadresult.cpp +++ b/gui/threadresult.cpp @@ -72,14 +72,15 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg) } ErrorItem item; - item.file = QString(callStackToString(msg._callStack).c_str()); + item.file = QString::fromStdString(callStackToString(msg._callStack)); item.files = files; - item.errorId = QString(msg._id.c_str()); + item.errorId = QString::fromStdString(msg._id); item.lines = lines; item.summary = QString::fromStdString(msg.shortMessage()); item.message = QString::fromStdString(msg.verboseMessage()); item.severity = msg._severity; item.inconclusive = msg._inconclusive; + item.file0 = QString::fromStdString(msg.file0); if (msg._severity != Severity::debug) emit Error(item);