Skip to content

Commit 87a118c

Browse files
committed
GUI: Recheck changed files. Ticket: cppcheck-opensource#816
1 parent 2e13a51 commit 87a118c

10 files changed

Lines changed: 154 additions & 12 deletions

gui/erroritem.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ ErrorItem::ErrorItem()
2727
ErrorItem::ErrorItem(const ErrorItem &item)
2828
{
2929
file = item.file;
30+
file0 = item.file0;
3031
files = item.files;
3132
lines = item.lines;
3233
errorId = item.errorId;

gui/erroritem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class ErrorItem {
105105

106106
QString file;
107107
QStringList files;
108+
QString file0;
108109
QList<unsigned int> lines;
109110
QString errorId;
110111
Severity::SeverityType severity;

gui/mainwindow.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -582,12 +582,16 @@ void MainWindow::ProgramSettings()
582582

583583
void MainWindow::ReCheck()
584584
{
585-
ClearResults();
586-
CheckLockDownUI(); // lock UI while checking
585+
const QStringList files = mThread->GetReCheckFiles();
586+
if (files.empty())
587+
return;
587588

588-
const int filesCount = mThread->GetPreviousFilesCount();
589-
Q_ASSERT(filesCount > 0); // If no files should not be able to recheck
590-
mUI.mResults->CheckingStarted(filesCount);
589+
// Clear results for changed files
590+
for (int i = 0; i < files.size(); ++i)
591+
mUI.mResults->Clear(files[i]);
592+
593+
CheckLockDownUI(); // lock UI while checking
594+
mUI.mResults->CheckingStarted(files.size());
591595

592596
if (mProject)
593597
qDebug() << "Rechecking project file" << mProject->GetProjectFile()->GetFilename();

gui/resultstree.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item)
134134
line.severity = item.severity;
135135
//Create the base item for the error and ensure it has a proper
136136
//file item as a parent
137-
QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, hide),
137+
QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, item.file0, hide),
138138
line,
139139
hide,
140140
SeverityToIcon(line.severity));
@@ -152,6 +152,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item)
152152
data["line"] = item.lines[0];
153153
data["id"] = item.errorId;
154154
data["inconclusive"] = item.inconclusive;
155+
data["file0"] = item.file0;
155156
stditem->setData(QVariant(data));
156157

157158
//Add backtrace files as children
@@ -303,6 +304,25 @@ void ResultsTree::Clear()
303304
mModel.removeRows(0, mModel.rowCount());
304305
}
305306

307+
void ResultsTree::Clear(const QString &filename)
308+
{
309+
const QString stripped = StripPath(filename, false);
310+
311+
for (int i = 0; i < mModel.rowCount(); ++i) {
312+
const QStandardItem *item = mModel.item(i, 0);
313+
if (!item)
314+
continue;
315+
316+
QVariantMap data = item->data().toMap();
317+
if (stripped == data["file"].toString() ||
318+
filename == data["file0"].toString()) {
319+
mModel.removeRow(i);
320+
break;
321+
}
322+
}
323+
}
324+
325+
306326
void ResultsTree::LoadSettings()
307327
{
308328
for (int i = 0; i < mModel.columnCount(); i++) {
@@ -433,7 +453,7 @@ void ResultsTree::RefreshTree()
433453
}
434454
}
435455

436-
QStandardItem *ResultsTree::EnsureFileItem(const QString &fullpath, bool hide)
456+
QStandardItem *ResultsTree::EnsureFileItem(const QString &fullpath, const QString &file0, bool hide)
437457
{
438458
QString name = StripPath(fullpath, false);
439459
// Since item has path with native separators we must use path with
@@ -452,6 +472,7 @@ QStandardItem *ResultsTree::EnsureFileItem(const QString &fullpath, bool hide)
452472
//Add user data to that item
453473
QMap<QString, QVariant> data;
454474
data["file"] = fullpath;
475+
data["file0"] = file0;
455476
item->setData(QVariant(data));
456477
mModel.appendRow(item);
457478

@@ -828,6 +849,7 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item)
828849
item.message = data["message"].toString();
829850
item.errorId = data["id"].toString();
830851
item.inconclusive = data["inconclusive"].toBool();
852+
item.file0 = data["file0"].toString();
831853
QString file = StripPath(data["file"].toString(), true);
832854
unsigned int line = data["line"].toUInt();
833855

gui/resultstree.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ class ResultsTree : public QTreeView {
6666
*/
6767
void Clear();
6868

69+
/**
70+
* @brief Clear errors for a specific file from the tree
71+
*/
72+
void Clear(const QString &filename);
73+
6974
/**
7075
* @brief Function to show/hide certain type of errors
7176
* Refreshes the tree.
@@ -339,10 +344,11 @@ protected slots:
339344
* @brief Ensures there's a item in the model for the specified file
340345
*
341346
* @param fullpath Full path to the file item.
347+
* @param file0 Source file
342348
* @param hide is the error (we want this file item for) hidden?
343349
* @return QStandardItem to be used as a parent for all errors for specified file
344350
*/
345-
QStandardItem *EnsureFileItem(const QString &fullpath, bool hide);
351+
QStandardItem *EnsureFileItem(const QString &fullpath, const QString &file0, bool hide);
346352

347353
/**
348354
* @brief Show a file item

gui/resultsview.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@ void ResultsView::Clear()
8080
mUI.mProgress->setFormat("%p%");
8181
}
8282

83+
void ResultsView::Clear(const QString &filename)
84+
{
85+
mUI.mTree->Clear(filename);
86+
mUI.mDetails->setText("");
87+
mErrorsFound = false;
88+
mStatistics->Clear();
89+
90+
// Clear the progressbar
91+
mUI.mProgress->setMaximum(PROGRESS_MAX);
92+
mUI.mProgress->setValue(0);
93+
mUI.mProgress->setFormat("%p%");
94+
}
95+
8396
void ResultsView::Progress(int value, const QString& description)
8497
{
8598
mUI.mProgress->setValue(value);

gui/resultsview.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ class ResultsView : public QWidget {
6464
*/
6565
void Clear();
6666

67+
/**
68+
* @brief Clear results for a specific file
69+
*/
70+
void Clear(const QString &filename);
71+
6772
/**
6873
* @brief Save results to a file
6974
*

gui/threadhandler.cpp

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include <QObject>
20+
#include <QFileInfo>
2021
#include <QStringList>
2122
#include <QDebug>
2223
#include "settings.h"
@@ -51,7 +52,8 @@ void ThreadHandler::SetFiles(const QStringList &files)
5152
void ThreadHandler::Check(const Settings &settings, bool recheck)
5253
{
5354
if (recheck && mRunningThreadCount == 0) {
54-
mResults.SetFiles(mLastFiles);
55+
// only recheck changed files
56+
mResults.SetFiles(GetReCheckFiles());
5557
}
5658

5759
if (mResults.GetFileCount() == 0 || mRunningThreadCount > 0 || settings._jobs <= 0) {
@@ -72,6 +74,9 @@ void ThreadHandler::Check(const Settings &settings, bool recheck)
7274
mThreads[i]->Check(settings);
7375
}
7476

77+
// Date and time when checking starts..
78+
mCheckStartTime = QDateTime::currentDateTime();
79+
7580
mTime.start();
7681
}
7782

@@ -124,11 +129,18 @@ void ThreadHandler::ThreadDone()
124129
emit Done();
125130

126131
mScanDuration = mTime.elapsed();
132+
133+
// Set date/time used by the recheck
134+
if (!mCheckStartTime.isNull()) {
135+
mLastCheckTime = mCheckStartTime;
136+
mCheckStartTime = QDateTime();
137+
}
127138
}
128139
}
129140

130141
void ThreadHandler::Stop()
131142
{
143+
mCheckStartTime = QDateTime();
132144
for (int i = 0; i < mThreads.size(); i++) {
133145
mThreads[i]->stop();
134146
}
@@ -177,3 +189,59 @@ int ThreadHandler::GetPreviousScanDuration() const
177189
{
178190
return mScanDuration;
179191
}
192+
193+
QStringList ThreadHandler::GetReCheckFiles() const
194+
{
195+
if (mLastCheckTime.isNull())
196+
return mLastFiles;
197+
198+
std::set<QString> modified;
199+
std::set<QString> unmodified;
200+
201+
QStringList files;
202+
for (int i = 0; i < mLastFiles.size(); ++i) {
203+
if (NeedsReCheck(mLastFiles[i], modified, unmodified))
204+
files.push_back(mLastFiles[i]);
205+
}
206+
return files;
207+
}
208+
209+
bool ThreadHandler::NeedsReCheck(const QString &filename, std::set<QString> &modified, std::set<QString> &unmodified) const
210+
{
211+
if (modified.find(filename) != modified.end())
212+
return true;
213+
214+
if (unmodified.find(filename) != unmodified.end())
215+
return false;
216+
217+
if (QFileInfo(filename).lastModified() > mLastCheckTime) {
218+
return true;
219+
}
220+
221+
// Parse included files recursively
222+
QFile f(filename);
223+
if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
224+
return false;
225+
226+
// prevent recursion..
227+
unmodified.insert(filename);
228+
229+
QTextStream in(&f);
230+
while (!in.atEnd()) {
231+
QString line = in.readLine();
232+
if (line.startsWith("#include \"")) {
233+
line.remove(0,10);
234+
int i = line.indexOf("\"");
235+
if (i > 0) {
236+
line.remove(i,line.length());
237+
line = QFileInfo(filename).absolutePath() + "/" + line;
238+
if (NeedsReCheck(line, modified, unmodified)) {
239+
modified.insert(line);
240+
return true;
241+
}
242+
}
243+
}
244+
}
245+
246+
return false;
247+
}

gui/threadhandler.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

2323
#include <QObject>
2424
#include <QStringList>
25-
#include <QTime>
25+
#include <QDateTime>
26+
#include <set>
2627
#include "settings.h"
2728
#include "cppcheck.h"
2829
#include "threadresult.h"
@@ -117,6 +118,12 @@ class ThreadHandler : public QObject {
117118
*/
118119
int GetPreviousScanDuration() const;
119120

121+
/**
122+
* @brief Get files that should be rechecked because they have been
123+
* changed.
124+
*/
125+
QStringList GetReCheckFiles() const;
126+
120127
signals:
121128
/**
122129
* @brief Signal that all threads are done
@@ -147,6 +154,14 @@ protected slots:
147154
*/
148155
QStringList mLastFiles;
149156

157+
/** @brief date and time when current checking started */
158+
QDateTime mCheckStartTime;
159+
160+
/**
161+
* @brief when was the files checked the last time (used when rechecking)
162+
*/
163+
QDateTime mLastCheckTime;
164+
150165
/**
151166
* @brief Timer used for measuring scan duration
152167
*
@@ -183,6 +198,12 @@ protected slots:
183198
*/
184199
int mRunningThreadCount;
185200
private:
201+
202+
/**
203+
* @brief Check if a file needs to be rechecked. Recursively checks
204+
* included headers. Used by GetReCheckFiles()
205+
*/
206+
bool NeedsReCheck(const QString &filename, std::set<QString> &modified, std::set<QString> &unmodified) const;
186207
};
187208
/// @}
188209
#endif // THREADHANDLER_H

gui/threadresult.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,15 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg)
7272
}
7373

7474
ErrorItem item;
75-
item.file = QString(callStackToString(msg._callStack).c_str());
75+
item.file = QString::fromStdString(callStackToString(msg._callStack));
7676
item.files = files;
77-
item.errorId = QString(msg._id.c_str());
77+
item.errorId = QString::fromStdString(msg._id);
7878
item.lines = lines;
7979
item.summary = QString::fromStdString(msg.shortMessage());
8080
item.message = QString::fromStdString(msg.verboseMessage());
8181
item.severity = msg._severity;
8282
item.inconclusive = msg._inconclusive;
83+
item.file0 = QString::fromStdString(msg.file0);
8384

8485
if (msg._severity != Severity::debug)
8586
emit Error(item);

0 commit comments

Comments
 (0)