Skip to content

Commit 20298d2

Browse files
committed
add fix
1 parent dbc1c3c commit 20298d2

11 files changed

Lines changed: 182 additions & 158 deletions

‎gui/checkthread.cpp‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,15 @@ CheckThread::CheckThread(ThreadResult &result, int threadIndex)
113113
void CheckThread::setSettings(const Settings &settings, std::shared_ptr<Suppressions> supprs)
114114
{
115115
mFiles.clear();
116+
mFileSettings.clear();
116117
mSettings = settings; // this is a copy
117118
mSuppressions = std::move(supprs);
118119
}
119120

120-
void CheckThread::analyseWholeProgram(const std::list<FileWithDetails> &files, const std::string& ctuInfo)
121+
void CheckThread::analyseWholeProgram(const std::list<FileWithDetails> &files, const std::list<FileSettings> &fileSettings, const std::string& ctuInfo)
121122
{
122123
mFiles = files;
124+
mFileSettings = fileSettings;
123125
mAnalyseWholeProgram = true;
124126
mCtuInfo = ctuInfo;
125127
start();
@@ -136,8 +138,9 @@ void CheckThread::run()
136138
std::string ctuInfo;
137139
ctuInfo.swap(mCtuInfo);
138140
qDebug() << "Whole program analysis";
139-
cppcheck.analyseWholeProgram(mSettings.buildDir, mFiles, {}, ctuInfo);
141+
cppcheck.analyseWholeProgram(mSettings.buildDir, mFiles, mFileSettings, ctuInfo);
140142
mFiles.clear();
143+
mFileSettings.clear();
141144
emit done();
142145
return;
143146
}

‎gui/checkthread.h‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ class CheckThread : public QThread {
6969

7070
/**
7171
* @brief Run whole program analysis
72-
* @param files All files
73-
* @param ctuInfo Ctu info for addons
72+
* @param files All files
73+
* @param fileSettings All files of the project
74+
* @param ctuInfo Ctu info for addons
7475
*/
75-
void analyseWholeProgram(const std::list<FileWithDetails> &files, const std::string& ctuInfo);
76+
void analyseWholeProgram(const std::list<FileWithDetails> &files, const std::list<FileSettings> &fileSettings, const std::string& ctuInfo);
7677

7778
void setAddonsAndTools(const QStringList &addonsAndTools) {
7879
mAddonsAndTools = addonsAndTools;
@@ -153,6 +154,7 @@ class CheckThread : public QThread {
153154
bool isSuppressed(const SuppressionList::ErrorMessage &errorMessage) const;
154155

155156
std::list<FileWithDetails> mFiles;
157+
std::list<FileSettings> mFileSettings;
156158
bool mAnalyseWholeProgram{};
157159
std::string mCtuInfo;
158160
QStringList mAddonsAndTools;

‎gui/mainwindow.cpp‎

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959

6060
#include <algorithm>
6161
#include <cstddef>
62+
#include <fstream>
6263
#include <iterator>
6364
#include <list>
6465
#include <memory>
@@ -96,6 +97,7 @@
9697
#include <QtNetwork/QNetworkRequest>
9798
#include <QPushButton>
9899
#include <QRegularExpression>
100+
#include <QSet>
99101
#include <QSettings>
100102
#include <QSize>
101103
#include <QTimer>
@@ -118,6 +120,18 @@ static QString fromNativePath(const QString& p) {
118120
#endif
119121
}
120122

123+
// The files selected in the results view are not necessarily spelled the same way as the
124+
// project or files.txt spells them, compare them as absolute paths
125+
static QString comparablePath(const QString& path) {
126+
return QDir::cleanPath(QFileInfo(path).absoluteFilePath());
127+
}
128+
129+
static QSet<QString> comparablePaths(const QStringList& paths) {
130+
QSet<QString> ret;
131+
std::transform(paths.cbegin(), paths.cend(), std::inserter(ret, ret.end()), comparablePath);
132+
return ret;
133+
}
134+
121135
template<typename T = std::vector<std::string>>
122136
static T toStdStringList(const QStringList& stringList) {
123137
T ret;
@@ -171,9 +185,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
171185
connect(mUI->mActionAnalyzeFiles, &QAction::triggered, this, &MainWindow::analyzeFiles);
172186
connect(mUI->mActionAnalyzeDirectory, &QAction::triggered, this, &MainWindow::analyzeDirectory);
173187
connect(mUI->mActionSettings, &QAction::triggered, this, &MainWindow::programSettings);
174-
connect(mUI->mActionClearResults, &QAction::triggered, this, [this]() {
175-
clearResults();
176-
});
188+
connect(mUI->mActionClearResults, &QAction::triggered, this, &MainWindow::clearResults);
177189
connect(mUI->mActionOpenXML, &QAction::triggered, this, &MainWindow::openResults);
178190

179191
connect(mUI->mActionShowStyle, &QAction::toggled, this, &MainWindow::showStyle);
@@ -570,21 +582,31 @@ void MainWindow::saveSettings() const
570582
mUI->mResults->saveSettings(mSettings);
571583
}
572584

573-
void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bool checkConfig, const QStringList& recheckFiles)
585+
void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bool checkConfig, const QStringList& selectedFiles, const Recheck recheck)
574586
{
575587
Settings checkSettings;
576588
auto supprs = std::make_shared<Suppressions>();
577589
if (!getCppcheckSettings(checkSettings, *supprs))
578590
return;
579591

580-
// filter requested files
581-
if (!recheckFiles.isEmpty()) {
592+
// Filter the selected files
593+
if (recheck == Recheck::Selected) {
594+
const QSet<QString> selected = comparablePaths(selectedFiles);
582595
p.fileSettings.remove_if([&](const FileSettings& fs) {
583-
return !recheckFiles.contains(QString::fromStdString(fs.filename()));
596+
return !selected.contains(comparablePath(QString::fromStdString(fs.filename())));
584597
});
598+
if (p.fileSettings.empty()) {
599+
QMessageBox msg(QMessageBox::Information,
600+
"Cppcheck",
601+
tr("None of the selected files is part of the project, nothing to analyze."),
602+
QMessageBox::Ok,
603+
this);
604+
msg.exec();
605+
return;
606+
}
585607
}
586608

587-
clearResults(recheckFiles);
609+
clearResultsForAnalysis(checkSettings.buildDir, selectedFiles, recheck);
588610

589611
mIsLogfileLoaded = false;
590612
if (mProjectFile) {
@@ -630,7 +652,7 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bo
630652
if (!checkSettings.buildDir.empty()) {
631653
checkSettings.loadSummaries();
632654
std::list<std::string> sourcefiles;
633-
AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, p.fileSettings, !recheckFiles.isEmpty());
655+
AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, p.fileSettings);
634656
}
635657

636658
//mThread->SetanalyzeProject(true);
@@ -649,7 +671,7 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bo
649671
mUI->mResults->setCheckSettings(checkSettings);
650672
}
651673

652-
void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, const bool checkConfig, const bool partialRecheck)
674+
void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, const bool checkConfig, const QStringList& selectedFiles, const Recheck recheck)
653675
{
654676
if (files.isEmpty())
655677
return;
@@ -659,7 +681,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, c
659681
if (!getCppcheckSettings(checkSettings, *supprs))
660682
return;
661683

662-
clearResults(partialRecheck ? files : QStringList());
684+
clearResultsForAnalysis(checkSettings.buildDir, selectedFiles, recheck);
663685

664686
mIsLogfileLoaded = false;
665687
FileList pathList;
@@ -708,7 +730,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, c
708730
if (!checkSettings.buildDir.empty()) {
709731
checkSettings.loadSummaries();
710732
const auto& sourcefiles = toStdStringList<std::list<std::string>>(fileNames);
711-
AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, {}, partialRecheck);
733+
AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, {});
712734
}
713735

714736
mThread->setCheckFiles(true);
@@ -1380,11 +1402,6 @@ void MainWindow::reAnalyzeSelected(const QStringList& files)
13801402
return;
13811403

13821404
if (mProjectFile) {
1383-
// Clear details, statistics and progress
1384-
mUI->mResults->clear(false);
1385-
for (int i = 0; i < files.size(); ++i)
1386-
mUI->mResults->clearRecheckFile(files[i]);
1387-
13881405
analyzeProject(mProjectFile, files);
13891406
return;
13901407
}
@@ -1394,10 +1411,7 @@ void MainWindow::reAnalyzeSelected(const QStringList& files)
13941411
if (!getCppcheckSettings(checkSettings, *supprs))
13951412
return;
13961413

1397-
// Clear details, statistics and progress
1398-
mUI->mResults->clear(false);
1399-
for (int i = 0; i < files.size(); ++i)
1400-
mUI->mResults->clearRecheckFile(files[i]);
1414+
clearResultsForAnalysis(checkSettings.buildDir, files, Recheck::Selected);
14011415

14021416
mCurrentDirectory = mUI->mResults->getCheckDirectory();
14031417
FileList pathList;
@@ -1449,16 +1463,10 @@ void MainWindow::reAnalyze(bool all)
14491463
mUI->mResults->setCheckSettings(checkSettings);
14501464
}
14511465

1452-
void MainWindow::clearResults(const QStringList& selectedFiles)
1466+
void MainWindow::clearResults()
14531467
{
1454-
if (!selectedFiles.isEmpty()) {
1455-
mUI->mResults->clear(false);
1456-
for (const QString& f : selectedFiles)
1457-
mUI->mResults->clearRecheckFile(f);
1458-
return;
1459-
}
14601468
if (mProjectFile && !mProjectFile->getBuildDir().isEmpty()) {
1461-
QDir dir(QFileInfo(mProjectFile->getFilename()).absolutePath() + '/' + mProjectFile->getBuildDir());
1469+
QDir dir(QDir(QFileInfo(mProjectFile->getFilename()).absolutePath()).filePath(mProjectFile->getBuildDir()));
14621470
for (const QString& f: dir.entryList(QDir::Files)) {
14631471
if (!f.endsWith("files.txt")) {
14641472
static const QRegularExpression rx("^.*.s[0-9]+$");
@@ -1472,6 +1480,42 @@ void MainWindow::clearResults(const QStringList& selectedFiles)
14721480
enableResultsButtons();
14731481
}
14741482

1483+
void MainWindow::clearResultsForAnalysis(const std::string& buildDir, const QStringList& selectedFiles, const Recheck recheck)
1484+
{
1485+
switch (recheck) {
1486+
case Recheck::None:
1487+
clearResults();
1488+
break;
1489+
case Recheck::Selected:
1490+
// Only the selected files are analyzed, the results of the other files are kept
1491+
mUI->mResults->clear(false);
1492+
for (const QString& f : selectedFiles)
1493+
mUI->mResults->clearRecheckFile(f);
1494+
enableResultsButtons();
1495+
break;
1496+
case Recheck::Cached: {
1497+
// Every file reports its results again, either analyzed or replayed from the analyzer
1498+
// information. Remove the analyzer information of the selected files so that they really
1499+
// are analyzed again, also by the clang tools that keep their results next to it.
1500+
const QSet<QString> selected = comparablePaths(selectedFiles);
1501+
QDir dir(QString::fromStdString(buildDir));
1502+
std::ifstream filesTxt(buildDir + "/files.txt");
1503+
std::string line;
1504+
while (std::getline(filesTxt, line)) {
1505+
AnalyzerInformation::Info info;
1506+
if (!info.parse(line) || !selected.contains(comparablePath(QString::fromStdString(info.sourceFile))))
1507+
continue;
1508+
const QString afile = QString::fromStdString(info.afile);
1509+
for (const QString& f : dir.entryList({afile, afile + ".*"}, QDir::Files))
1510+
dir.remove(f);
1511+
}
1512+
mUI->mResults->clear(true);
1513+
enableResultsButtons();
1514+
break;
1515+
}
1516+
}
1517+
}
1518+
14751519
void MainWindow::openResults()
14761520
{
14771521
if (mUI->mResults->hasResults()) {
@@ -1870,10 +1914,19 @@ bool MainWindow::loadLastResults()
18701914
return true;
18711915
}
18721916

1873-
void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringList& recheckFiles, const bool checkLib, const bool checkConfig)
1917+
void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringList& selectedFiles, const bool checkLib, const bool checkConfig)
18741918
{
18751919
Settings::terminate(false);
18761920

1921+
// A build directory means there is an analyzer information cache. Analyzing the whole
1922+
// project is then the better way to recheck a few files: the cache skips the files that
1923+
// did not change and replays their findings, and files.txt stays complete so whole
1924+
// program analysis (unusedFunction, the MISRA cross-TU rules, ...) still sees every file.
1925+
// Only without a cache is it worth narrowing the analysis down to the selected files.
1926+
Recheck recheck = Recheck::None;
1927+
if (!selectedFiles.isEmpty())
1928+
recheck = projectFile->getBuildDir().isEmpty() ? Recheck::Selected : Recheck::Cached;
1929+
18771930
QFileInfo inf(projectFile->getFilename());
18781931
const QString& rootpath = projectFile->getRootPath();
18791932

@@ -1975,11 +2028,11 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis
19752028
msg.exec();
19762029
return;
19772030
}
1978-
doAnalyzeProject(p, checkLib, checkConfig, recheckFiles); // TODO: avoid copy
2031+
doAnalyzeProject(p, checkLib, checkConfig, selectedFiles, recheck); // TODO: avoid copy
19792032
return;
19802033
}
19812034

1982-
QStringList paths = recheckFiles.isEmpty() ? projectFile->getCheckPaths() : recheckFiles;
2035+
QStringList paths = recheck == Recheck::Selected ? selectedFiles : projectFile->getCheckPaths();
19832036

19842037
// If paths not given then check the root path (which may be the project
19852038
// file's location, see above). This is to keep the compatibility with
@@ -1988,7 +2041,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis
19882041
if (paths.isEmpty()) {
19892042
paths << mCurrentDirectory;
19902043
}
1991-
doAnalyzeFiles(paths, checkLib, checkConfig, !recheckFiles.isEmpty());
2044+
doAnalyzeFiles(paths, checkLib, checkConfig, selectedFiles, recheck);
19922045
}
19932046

19942047
void MainWindow::newProjectFile()

‎gui/mainwindow.h‎

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <cstdint>
2626
#include <list>
27+
#include <string>
2728

2829
#include <QFileDialog>
2930
#include <QMainWindow>
@@ -107,11 +108,8 @@ public slots:
107108
/** @brief Slot to reanalyze modified files */
108109
void reAnalyzeModified();
109110

110-
/**
111-
* @brief Slot to clear all search results or selected
112-
* @param selectedFiles list to clear, leave empty for all
113-
*/
114-
void clearResults(const QStringList& selectedFiles = QStringList());
111+
/** @brief Slot to clear all search results */
112+
void clearResults();
115113

116114
/** @brief Slot to open XML report file */
117115
void openResults();
@@ -252,6 +250,19 @@ private slots:
252250
void changeReportType();
253251
private:
254252

253+
/** @brief How an analysis treats the files selected for a recheck */
254+
enum class Recheck : std::uint8_t {
255+
/** Not a recheck, everything is analyzed from scratch */
256+
None,
257+
/** Only the selected files are analyzed, the results of the other files are kept */
258+
Selected,
259+
/**
260+
* Everything is analyzed. The analyzer information in the build directory is kept,
261+
* except for the selected files, so the unchanged files are not analyzed again.
262+
*/
263+
Cached
264+
};
265+
255266
bool isCppcheckPremium() const;
256267

257268
/** Get filename for last results */
@@ -269,11 +280,11 @@ private slots:
269280
/**
270281
* @brief Analyze the project.
271282
* @param projectFile Pointer to the project to analyze.
272-
* @param recheckFiles files to recheck, empty => check all files
283+
* @param selectedFiles files to recheck, empty => check all files
273284
* @param checkLib Flag to indicate if the library should be checked.
274285
* @param checkConfig Flag to indicate if the configuration should be checked.
275286
*/
276-
void analyzeProject(const ProjectFile *projectFile, const QStringList& recheckFiles, bool checkLib = false, bool checkConfig = false);
287+
void analyzeProject(const ProjectFile *projectFile, const QStringList& selectedFiles, bool checkLib = false, bool checkConfig = false);
277288

278289
/**
279290
* @brief Set current language
@@ -311,18 +322,29 @@ private slots:
311322
* @param p imported project
312323
* @param checkLib Flag to indicate if library should be checked
313324
* @param checkConfig Flag to indicate if the configuration should be checked.
325+
* @param selectedFiles Files selected for a recheck
326+
* @param recheck How the selected files are rechecked
314327
*/
315-
void doAnalyzeProject(ImportProject p, bool checkLib = false, bool checkConfig = false, const QStringList &recheckFiles = QStringList());
328+
void doAnalyzeProject(ImportProject p, bool checkLib = false, bool checkConfig = false, const QStringList& selectedFiles = QStringList(), Recheck recheck = Recheck::None);
316329

317330
/**
318331
* @brief Analyze all files specified in parameter files
319332
*
320333
* @param files List of files and/or directories to analyze
321334
* @param checkLib Flag to indicate if library should be checked
322335
* @param checkConfig Flag to indicate if the configuration should be checked.
323-
* @param partialRecheck Flag to indicate a partial recheck.
336+
* @param selectedFiles Files selected for a recheck
337+
* @param recheck How the selected files are rechecked
338+
*/
339+
void doAnalyzeFiles(const QStringList &files, bool checkLib = false, bool checkConfig = false, const QStringList& selectedFiles = QStringList(), Recheck recheck = Recheck::None);
340+
341+
/**
342+
* @brief Clear the results that a new analysis replaces
343+
* @param buildDir Build directory of the analysis
344+
* @param selectedFiles Files selected for a recheck
345+
* @param recheck How the selected files are rechecked
324346
*/
325-
void doAnalyzeFiles(const QStringList &files, bool checkLib = false, bool checkConfig = false, bool partialRecheck = false);
347+
void clearResultsForAnalysis(const std::string& buildDir, const QStringList& selectedFiles, Recheck recheck);
326348

327349
/**
328350
* @brief Get our default cppcheck settings and read project file.

0 commit comments

Comments
 (0)