GUI: Recheck changed files. Ticket: #816

This commit is contained in:
Daniel Marjamäki 2012-02-14 21:16:11 +01:00
parent 2e13a51d08
commit 87a118cd16
10 changed files with 154 additions and 12 deletions

View File

@ -27,6 +27,7 @@ ErrorItem::ErrorItem()
ErrorItem::ErrorItem(const ErrorItem &item) ErrorItem::ErrorItem(const ErrorItem &item)
{ {
file = item.file; file = item.file;
file0 = item.file0;
files = item.files; files = item.files;
lines = item.lines; lines = item.lines;
errorId = item.errorId; errorId = item.errorId;

View File

@ -105,6 +105,7 @@ public:
QString file; QString file;
QStringList files; QStringList files;
QString file0;
QList<unsigned int> lines; QList<unsigned int> lines;
QString errorId; QString errorId;
Severity::SeverityType severity; Severity::SeverityType severity;

View File

@ -582,12 +582,16 @@ void MainWindow::ProgramSettings()
void MainWindow::ReCheck() void MainWindow::ReCheck()
{ {
ClearResults(); const QStringList files = mThread->GetReCheckFiles();
CheckLockDownUI(); // lock UI while checking if (files.empty())
return;
const int filesCount = mThread->GetPreviousFilesCount(); // Clear results for changed files
Q_ASSERT(filesCount > 0); // If no files should not be able to recheck for (int i = 0; i < files.size(); ++i)
mUI.mResults->CheckingStarted(filesCount); mUI.mResults->Clear(files[i]);
CheckLockDownUI(); // lock UI while checking
mUI.mResults->CheckingStarted(files.size());
if (mProject) if (mProject)
qDebug() << "Rechecking project file" << mProject->GetProjectFile()->GetFilename(); qDebug() << "Rechecking project file" << mProject->GetProjectFile()->GetFilename();

View File

@ -134,7 +134,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item)
line.severity = item.severity; line.severity = item.severity;
//Create the base item for the error and ensure it has a proper //Create the base item for the error and ensure it has a proper
//file item as a parent //file item as a parent
QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, hide), QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, item.file0, hide),
line, line,
hide, hide,
SeverityToIcon(line.severity)); SeverityToIcon(line.severity));
@ -152,6 +152,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item)
data["line"] = item.lines[0]; data["line"] = item.lines[0];
data["id"] = item.errorId; data["id"] = item.errorId;
data["inconclusive"] = item.inconclusive; data["inconclusive"] = item.inconclusive;
data["file0"] = item.file0;
stditem->setData(QVariant(data)); stditem->setData(QVariant(data));
//Add backtrace files as children //Add backtrace files as children
@ -303,6 +304,25 @@ void ResultsTree::Clear()
mModel.removeRows(0, mModel.rowCount()); 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() void ResultsTree::LoadSettings()
{ {
for (int i = 0; i < mModel.columnCount(); i++) { 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); QString name = StripPath(fullpath, false);
// Since item has path with native separators we must use path with // 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 //Add user data to that item
QMap<QString, QVariant> data; QMap<QString, QVariant> data;
data["file"] = fullpath; data["file"] = fullpath;
data["file0"] = file0;
item->setData(QVariant(data)); item->setData(QVariant(data));
mModel.appendRow(item); mModel.appendRow(item);
@ -828,6 +849,7 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item)
item.message = data["message"].toString(); item.message = data["message"].toString();
item.errorId = data["id"].toString(); item.errorId = data["id"].toString();
item.inconclusive = data["inconclusive"].toBool(); item.inconclusive = data["inconclusive"].toBool();
item.file0 = data["file0"].toString();
QString file = StripPath(data["file"].toString(), true); QString file = StripPath(data["file"].toString(), true);
unsigned int line = data["line"].toUInt(); unsigned int line = data["line"].toUInt();

View File

@ -66,6 +66,11 @@ public:
*/ */
void Clear(); 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 * @brief Function to show/hide certain type of errors
* Refreshes the tree. * Refreshes the tree.
@ -339,10 +344,11 @@ protected:
* @brief Ensures there's a item in the model for the specified file * @brief Ensures there's a item in the model for the specified file
* *
* @param fullpath Full path to the file item. * @param fullpath Full path to the file item.
* @param file0 Source file
* @param hide is the error (we want this file item for) hidden? * @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 * @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 * @brief Show a file item

View File

@ -80,6 +80,19 @@ void ResultsView::Clear()
mUI.mProgress->setFormat("%p%"); 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) void ResultsView::Progress(int value, const QString& description)
{ {
mUI.mProgress->setValue(value); mUI.mProgress->setValue(value);

View File

@ -64,6 +64,11 @@ public:
*/ */
void Clear(); void Clear();
/**
* @brief Clear results for a specific file
*/
void Clear(const QString &filename);
/** /**
* @brief Save results to a file * @brief Save results to a file
* *

View File

@ -17,6 +17,7 @@
*/ */
#include <QObject> #include <QObject>
#include <QFileInfo>
#include <QStringList> #include <QStringList>
#include <QDebug> #include <QDebug>
#include "settings.h" #include "settings.h"
@ -51,7 +52,8 @@ void ThreadHandler::SetFiles(const QStringList &files)
void ThreadHandler::Check(const Settings &settings, bool recheck) void ThreadHandler::Check(const Settings &settings, bool recheck)
{ {
if (recheck && mRunningThreadCount == 0) { if (recheck && mRunningThreadCount == 0) {
mResults.SetFiles(mLastFiles); // only recheck changed files
mResults.SetFiles(GetReCheckFiles());
} }
if (mResults.GetFileCount() == 0 || mRunningThreadCount > 0 || settings._jobs <= 0) { 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); mThreads[i]->Check(settings);
} }
// Date and time when checking starts..
mCheckStartTime = QDateTime::currentDateTime();
mTime.start(); mTime.start();
} }
@ -124,11 +129,18 @@ void ThreadHandler::ThreadDone()
emit Done(); emit Done();
mScanDuration = mTime.elapsed(); mScanDuration = mTime.elapsed();
// Set date/time used by the recheck
if (!mCheckStartTime.isNull()) {
mLastCheckTime = mCheckStartTime;
mCheckStartTime = QDateTime();
}
} }
} }
void ThreadHandler::Stop() void ThreadHandler::Stop()
{ {
mCheckStartTime = QDateTime();
for (int i = 0; i < mThreads.size(); i++) { for (int i = 0; i < mThreads.size(); i++) {
mThreads[i]->stop(); mThreads[i]->stop();
} }
@ -177,3 +189,59 @@ int ThreadHandler::GetPreviousScanDuration() const
{ {
return mScanDuration; return mScanDuration;
} }
QStringList ThreadHandler::GetReCheckFiles() const
{
if (mLastCheckTime.isNull())
return mLastFiles;
std::set<QString> modified;
std::set<QString> 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<QString> &modified, std::set<QString> &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;
}

View File

@ -22,7 +22,8 @@
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
#include <QTime> #include <QDateTime>
#include <set>
#include "settings.h" #include "settings.h"
#include "cppcheck.h" #include "cppcheck.h"
#include "threadresult.h" #include "threadresult.h"
@ -117,6 +118,12 @@ public:
*/ */
int GetPreviousScanDuration() const; int GetPreviousScanDuration() const;
/**
* @brief Get files that should be rechecked because they have been
* changed.
*/
QStringList GetReCheckFiles() const;
signals: signals:
/** /**
* @brief Signal that all threads are done * @brief Signal that all threads are done
@ -147,6 +154,14 @@ protected:
*/ */
QStringList mLastFiles; 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 * @brief Timer used for measuring scan duration
* *
@ -183,6 +198,12 @@ protected:
*/ */
int mRunningThreadCount; int mRunningThreadCount;
private: private:
/**
* @brief Check if a file needs to be rechecked. Recursively checks
* included headers. Used by GetReCheckFiles()
*/
bool NeedsReCheck(const QString &filename, std::set<QString> &modified, std::set<QString> &unmodified) const;
}; };
/// @} /// @}
#endif // THREADHANDLER_H #endif // THREADHANDLER_H

View File

@ -72,14 +72,15 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg)
} }
ErrorItem item; ErrorItem item;
item.file = QString(callStackToString(msg._callStack).c_str()); item.file = QString::fromStdString(callStackToString(msg._callStack));
item.files = files; item.files = files;
item.errorId = QString(msg._id.c_str()); item.errorId = QString::fromStdString(msg._id);
item.lines = lines; item.lines = lines;
item.summary = QString::fromStdString(msg.shortMessage()); item.summary = QString::fromStdString(msg.shortMessage());
item.message = QString::fromStdString(msg.verboseMessage()); item.message = QString::fromStdString(msg.verboseMessage());
item.severity = msg._severity; item.severity = msg._severity;
item.inconclusive = msg._inconclusive; item.inconclusive = msg._inconclusive;
item.file0 = QString::fromStdString(msg.file0);
if (msg._severity != Severity::debug) if (msg._severity != Severity::debug)
emit Error(item); emit Error(item);