From ef743ac1935db8d15a27e9bdeadb748f3834e817 Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 23 Jun 2025 22:20:07 +0200 Subject: [PATCH 1/2] refs #13914 - apply enforced language for non-project inputs in GUI --- cli/cmdlineparser.cpp | 35 +-------------------------- frontend/frontend.cpp | 38 ++++++++++++++++++++++++++++++ frontend/frontend.h | 2 ++ gui/checkthread.cpp | 12 +++------- gui/checkthread.h | 7 +++--- gui/mainwindow.cpp | 35 +++++++++++++++++++-------- gui/mainwindow.h | 5 ++++ gui/threadhandler.cpp | 22 +++++++++-------- gui/threadhandler.h | 10 ++++---- gui/threadresult.cpp | 11 ++++----- gui/threadresult.h | 3 +-- test/testfrontend.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 156 insertions(+), 79 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index c83f55e9818..87ac81ec5d7 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -293,40 +293,7 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) files = std::move(filesResolved); } - if (mEnforcedLang != Standards::Language::None) - { - // apply enforced language - for (auto& f : files) - { - if (mSettings.library.markupFile(f.path())) - continue; - f.setLang(mEnforcedLang); - } - } - else - { - // identify remaining files - for (auto& f : files) - { - if (f.lang() != Standards::Language::None) - continue; - if (mSettings.library.markupFile(f.path())) - continue; - bool header = false; - f.setLang(Path::identify(f.path(), mSettings.cppHeaderProbe, &header)); - // unknown extensions default to C++ - if (!header && f.lang() == Standards::Language::None) - f.setLang(Standards::Language::CPP); - } - } - - // enforce the language since markup files are special and do not adhere to the enforced language - for (auto& f : files) - { - if (mSettings.library.markupFile(f.path())) { - f.setLang(Standards::Language::C); - } - } + frontend::applyLang(files, mSettings, mEnforcedLang); // sort the markup last std::copy_if(files.cbegin(), files.cend(), std::inserter(mFiles, mFiles.end()), [&](const FileWithDetails& entry) { diff --git a/frontend/frontend.cpp b/frontend/frontend.cpp index eaaf34f33fd..bd95488a9a5 100644 --- a/frontend/frontend.cpp +++ b/frontend/frontend.cpp @@ -63,4 +63,42 @@ namespace frontend { } } } + + void applyLang(std::list& files, const Settings& settings, Standards::Language enforcedLang) + { + if (enforcedLang != Standards::Language::None) + { + // apply enforced language + for (auto& f : files) + { + if (settings.library.markupFile(f.path())) + continue; + f.setLang(enforcedLang); + } + } + else + { + // identify remaining files + for (auto& f : files) + { + if (f.lang() != Standards::Language::None) + continue; + if (settings.library.markupFile(f.path())) + continue; + bool header = false; + f.setLang(Path::identify(f.path(), settings.cppHeaderProbe, &header)); + // unknown extensions default to C++ + if (!header && f.lang() == Standards::Language::None) + f.setLang(Standards::Language::CPP); + } + } + + // enforce the language since markup files are special and do not adhere to the enforced language + for (auto& f : files) + { + if (settings.library.markupFile(f.path())) { + f.setLang(Standards::Language::C); + } + } + } } diff --git a/frontend/frontend.h b/frontend/frontend.h index 1a8a92743b2..71af18b3b3f 100644 --- a/frontend/frontend.h +++ b/frontend/frontend.h @@ -25,6 +25,7 @@ struct FileSettings; class Settings; +class FileWithDetails; namespace frontend { @@ -32,6 +33,7 @@ namespace frontend Applies the enforced language as all as identifying remaining files - also taking markup files into consideration. */ void applyLang(std::list &fileSettings, const Settings &settings, Standards::Language enforcedLang); + void applyLang(std::list &files, const Settings &settings, Standards::Language enforcedLang); } #endif // FRONTEND_H diff --git a/gui/checkthread.cpp b/gui/checkthread.cpp index 773aab95a6d..872227aa9e3 100644 --- a/gui/checkthread.cpp +++ b/gui/checkthread.cpp @@ -25,7 +25,6 @@ #include "errorlogger.h" #include "errortypes.h" #include "filesettings.h" -#include "path.h" #include "settings.h" #include "standards.h" #include "threadresult.h" @@ -121,7 +120,7 @@ void CheckThread::setSettings(const Settings &settings, std::shared_ptr &files, const std::string& ctuInfo) { mFiles = files; mAnalyseWholeProgram = true; @@ -136,17 +135,12 @@ void CheckThread::run() CppCheck cppcheck(mSettings, *mSuppressions, mResult, true, executeCommand); - if (!mFiles.isEmpty() || mAnalyseWholeProgram) { + if (!mFiles.empty() || mAnalyseWholeProgram) { mAnalyseWholeProgram = false; std::string ctuInfo; ctuInfo.swap(mCtuInfo); qDebug() << "Whole program analysis"; - std::list files2; - std::transform(mFiles.cbegin(), mFiles.cend(), std::back_inserter(files2), [&](const QString& file) { - // TODO: apply enforcedLanguage - return FileWithDetails{file.toStdString(), Path::identify(file.toStdString(), mSettings.cppHeaderProbe), 0}; - }); - cppcheck.analyseWholeProgram(mSettings.buildDir, files2, {}, ctuInfo); + cppcheck.analyseWholeProgram(mSettings.buildDir, mFiles, {}, ctuInfo); mFiles.clear(); emit done(); return; diff --git a/gui/checkthread.h b/gui/checkthread.h index 827e75f1247..892bdf5258d 100644 --- a/gui/checkthread.h +++ b/gui/checkthread.h @@ -20,11 +20,13 @@ #ifndef CHECKTHREAD_H #define CHECKTHREAD_H +#include "filesettings.h" #include "settings.h" #include "suppressions.h" #include #include +#include #include #include #include @@ -36,7 +38,6 @@ #include class ThreadResult; -struct FileSettings; /// @addtogroup GUI /// @{ @@ -63,7 +64,7 @@ class CheckThread : public QThread { * @param files All files * @param ctuInfo Ctu info for addons */ - void analyseWholeProgram(const QStringList &files, const std::string& ctuInfo); + void analyseWholeProgram(const std::list &files, const std::string& ctuInfo); void setAddonsAndTools(const QStringList &addonsAndTools) { mAddonsAndTools = addonsAndTools; @@ -142,7 +143,7 @@ class CheckThread : public QThread { bool isSuppressed(const SuppressionList::ErrorMessage &errorMessage) const; - QStringList mFiles; + std::list mFiles; bool mAnalyseWholeProgram{}; std::string mCtuInfo; QStringList mAddonsAndTools; diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 4b7970d3b47..ce900e4230a 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -57,6 +57,8 @@ #include "frontend.h" #include +#include +#include #include #include #include @@ -661,9 +663,11 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar return; } - mUI->mResults->checkingStarted(fileNames.count()); + std::list fdetails = enrichFilesForAnalysis(fileNames, checkSettings); - mThread->setFiles(fileNames); + // TODO: lock UI here? + mUI->mResults->checkingStarted(fdetails.size()); + mThread->setFiles(std::move(fdetails)); if (mProjectFile && !checkConfiguration) mThread->setAddonsAndTools(mProjectFile->getAddonsAndTools()); mThread->setSuppressions(mProjectFile ? mProjectFile->getCheckingSuppressions() : QList()); @@ -701,9 +705,9 @@ void MainWindow::analyzeCode(const QString& code, const QString& filename) if (!getCppcheckSettings(checkSettings, supprs)) return; + // TODO: split ErrorLogger from ThreadResult // Initialize dummy ThreadResult as ErrorLogger ThreadResult result; - result.setFiles(QStringList(filename)); connect(&result, SIGNAL(progress(int,QString)), mUI->mResults, SLOT(progress(int,QString))); connect(&result, SIGNAL(error(ErrorItem)), @@ -720,7 +724,7 @@ void MainWindow::analyzeCode(const QString& code, const QString& filename) checkLockDownUI(); clearResults(); mUI->mResults->checkingStarted(1); - // TODO: apply enforcedLanguage + // TODO: apply enforcedLanguage? cppcheck.check(FileWithDetails(filename.toStdString(), Path::identify(filename.toStdString(), false), 0), code.toStdString()); analysisDone(); @@ -1380,10 +1384,12 @@ void MainWindow::reAnalyzeSelected(const QStringList& files) pathList.addPathList(files); if (mProjectFile) pathList.addExcludeList(mProjectFile->getExcludedPaths()); - QStringList fileNames = pathList.getFileList(); + + std::list fdetails = enrichFilesForAnalysis(pathList.getFileList(), checkSettings); + checkLockDownUI(); // lock UI while checking - mUI->mResults->checkingStarted(fileNames.size()); - mThread->setCheckFiles(fileNames); + mUI->mResults->checkingStarted(fdetails.size()); + mThread->setCheckFiles(std::move(fdetails)); // Saving last check start time, otherwise unchecked modified files will not be // considered in "Modified Files Check" performed after "Selected Files Check" @@ -1396,7 +1402,7 @@ void MainWindow::reAnalyzeSelected(const QStringList& files) void MainWindow::reAnalyze(bool all) { - const QStringList files = mThread->getReCheckFiles(all); + const std::list files = mThread->getReCheckFiles(all); if (files.empty()) return; @@ -1409,8 +1415,8 @@ void MainWindow::reAnalyze(bool all) mUI->mResults->clear(all); // Clear results for changed files - for (int i = 0; i < files.size(); ++i) - mUI->mResults->clear(files[i]); + for (const auto& f : files) + mUI->mResults->clear(QString::fromStdString(f.path())); checkLockDownUI(); // lock UI while checking mUI->mResults->checkingStarted(files.size()); @@ -2349,3 +2355,12 @@ void MainWindow::changeReportType() { } } +std::list MainWindow::enrichFilesForAnalysis(const QStringList& fileNames, const Settings& settings) const { + std::list fdetails; + std::transform(fileNames.cbegin(), fileNames.cend(), std::back_inserter(fdetails), [](const QString& f) { + return FileWithDetails{f.toStdString(), Standards::Language::None, static_cast(QFile(f).size())}; + }); + const Standards::Language enforcedLang = static_cast(mSettings->value(SETTINGS_ENFORCED_LANGUAGE, 0).toInt()); + frontend::applyLang(fdetails, settings, enforcedLang); + return fdetails; +} diff --git a/gui/mainwindow.h b/gui/mainwindow.h index ae58e5412ae..4999f101f80 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -23,6 +23,7 @@ #include "platforms.h" #include +#include #include #include @@ -45,6 +46,7 @@ class QNetworkAccessManager; class QNetworkReply; class Settings; struct Suppressions; +class FileWithDetails; namespace Ui { class MainWindow; } @@ -423,6 +425,9 @@ private slots: */ void removeProjectMRU(const QString &project); + /** @brief Generate list of detailed files from list of filenames. */ + std::list enrichFilesForAnalysis(const QStringList& fileNames, const Settings& settings) const; + /** @brief Program settings */ QSettings *mSettings; diff --git a/gui/threadhandler.cpp b/gui/threadhandler.cpp index 7363e167939..e7de012be1a 100644 --- a/gui/threadhandler.cpp +++ b/gui/threadhandler.cpp @@ -20,6 +20,7 @@ #include "checkthread.h" #include "common.h" +#include "filesettings.h" #include "resultsview.h" #include "settings.h" @@ -55,10 +56,10 @@ void ThreadHandler::clearFiles() mSuppressionsUI.clear(); } -void ThreadHandler::setFiles(const QStringList &files) +void ThreadHandler::setFiles(std::list files) { - mResults.setFiles(files); mLastFiles = files; + mResults.setFiles(std::move(files)); } void ThreadHandler::setProject(const ImportProject &prj) @@ -74,10 +75,10 @@ void ThreadHandler::setCheckFiles(bool all) } } -void ThreadHandler::setCheckFiles(const QStringList& files) +void ThreadHandler::setCheckFiles(std::list files) { if (mRunningThreadCount == 0) { - mResults.setFiles(files); + mResults.setFiles(std::move(files)); } } @@ -172,6 +173,7 @@ void ThreadHandler::threadDone() { mRunningThreadCount--; + // TODO: also run with projects? if (mRunningThreadCount == 0 && mAnalyseWholeProgram) { createThreads(1); mRunningThreadCount = 1; @@ -235,7 +237,7 @@ void ThreadHandler::saveSettings(QSettings &settings) const bool ThreadHandler::hasPreviousFiles() const { - return !mLastFiles.isEmpty(); + return !mLastFiles.empty(); } int ThreadHandler::getPreviousFilesCount() const @@ -248,7 +250,7 @@ int ThreadHandler::getPreviousScanDuration() const return mScanDuration; } -QStringList ThreadHandler::getReCheckFiles(bool all) const +std::list ThreadHandler::getReCheckFiles(bool all) const { if (mLastCheckTime.isNull() || all) return mLastFiles; @@ -256,10 +258,10 @@ QStringList ThreadHandler::getReCheckFiles(bool all) const 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]); + std::list files; + for (const auto& f : mLastFiles) { + if (needsReCheck(QString::fromStdString(f.path()), modified, unmodified)) + files.push_back(f); } return files; } diff --git a/gui/threadhandler.h b/gui/threadhandler.h index 5a687e74762..cc578bd5643 100644 --- a/gui/threadhandler.h +++ b/gui/threadhandler.h @@ -24,6 +24,7 @@ #include "suppressions.h" #include "threadresult.h" +#include #include #include #include @@ -40,6 +41,7 @@ class CheckThread; class QSettings; class ImportProject; class ErrorItem; +class FileWithDetails; /// @addtogroup GUI /// @{ @@ -97,7 +99,7 @@ class ThreadHandler : public QObject { * * @param files files to check */ - void setFiles(const QStringList &files); + void setFiles(std::list files); /** * @brief Set project to check @@ -126,7 +128,7 @@ class ThreadHandler : public QObject { * * @param files list of files to be checked */ - void setCheckFiles(const QStringList& files); + void setCheckFiles(std::list files); /** * @brief Is checking running? @@ -160,7 +162,7 @@ class ThreadHandler : public QObject { * @brief Get files that should be rechecked because they have been * changed. */ - QStringList getReCheckFiles(bool all) const; + std::list getReCheckFiles(bool all) const; /** * @brief Get start time of last check @@ -207,7 +209,7 @@ protected slots: * @brief List of files checked last time (used when rechecking) * */ - QStringList mLastFiles; + std::list mLastFiles; /** @brief date and time when current checking started */ QDateTime mCheckStartTime; diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp index a8d198228ea..39e6f48f6cd 100644 --- a/gui/threadresult.cpp +++ b/gui/threadresult.cpp @@ -25,6 +25,7 @@ #include "importproject.h" #include +#include #include @@ -80,18 +81,14 @@ void ThreadResult::getNextFileSettings(const FileSettings*& fs) ++mItNextFileSettings; } -void ThreadResult::setFiles(const QStringList &files) +void ThreadResult::setFiles(std::list files) { std::lock_guard locker(mutex); - std::list fdetails; - std::transform(files.cbegin(), files.cend(), std::back_inserter(fdetails), [](const QString& f) { - return FileWithDetails{f.toStdString(), Path::identify(f.toStdString(), false), static_cast(QFile(f).size())}; // TODO: provide Settings::cppHeaderProbe - }); - mFiles = std::move(fdetails); + mTotalFiles = files.size(); + mFiles = std::move(files); mItNextFile = mFiles.cbegin(); mProgress = 0; mFilesChecked = 0; - mTotalFiles = files.size(); // Determine the total size of all of the files to check, so that we can // show an accurate progress estimate diff --git a/gui/threadresult.h b/gui/threadresult.h index 33dc8290134..64c26d03d0c 100644 --- a/gui/threadresult.h +++ b/gui/threadresult.h @@ -31,7 +31,6 @@ #include #include #include -#include class ErrorItem; class ImportProject; @@ -59,7 +58,7 @@ class ThreadResult : public QObject, public ErrorLogger { * @brief Set list of files to check * @param files List of files to check */ - void setFiles(const QStringList &files); + void setFiles(std::list files); void setProject(const ImportProject &prj); diff --git a/test/testfrontend.cpp b/test/testfrontend.cpp index 941394863f3..ef6b774181a 100644 --- a/test/testfrontend.cpp +++ b/test/testfrontend.cpp @@ -33,6 +33,7 @@ class TestFrontend : public TestFixture { private: void run() override { TEST_CASE(applyLangFS); + TEST_CASE(applyLangFiles); } void applyLangFS() const { @@ -87,6 +88,60 @@ class TestFrontend : public TestFixture { ASSERT_EQUALS_ENUM((it++)->file.lang(), Standards::Language::C); // markup files are always C } } + + void applyLangFiles() const + { + const char xmldata[] = R"()"; + const Settings s = settingsBuilder().libraryxml(xmldata).build(); + + const std::list fs = { + {"nolang", Standards::Language::None, 0 }, + {"c", Standards::Language::C, 0 }, + {"cpp", Standards::Language::CPP, 0 }, + {"nolang.c", Standards::Language::None, 0 }, + {"nolang.cpp", Standards::Language::None, 0 }, + {"nolang.ml", Standards::Language::None, 0 } + }; + + // no language to enforce - identify only + { + std::list fs1 = fs; + frontend::applyLang(fs1, s, Standards::Language::None); + auto it = fs1.cbegin(); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); // unknown defaults to C++ + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); // markup files are always C + } + + // language to enforce (C) + { + std::list fs1 = fs; + frontend::applyLang(fs1, s, Standards::Language::C); + auto it = fs1.cbegin(); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); // markup files are always C + } + + // language to enforce (C++) + { + std::list fs1 = fs; + frontend::applyLang(fs1, s, Standards::Language::CPP); + auto it = fs1.cbegin(); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::CPP); + ASSERT_EQUALS_ENUM((it++)->lang(), Standards::Language::C); // markup files are always C + } + } }; REGISTER_TEST(TestFrontend) From a561640e52e3673393d83f10b1a87613eda0953d Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 25 Jun 2025 21:20:40 +0200 Subject: [PATCH 2/2] gui/threadhandler.cpp: fixed `useStlAlgorithm` selfcheck warning --- gui/threadhandler.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gui/threadhandler.cpp b/gui/threadhandler.cpp index e7de012be1a..f077d3c7b2c 100644 --- a/gui/threadhandler.cpp +++ b/gui/threadhandler.cpp @@ -259,10 +259,9 @@ std::list ThreadHandler::getReCheckFiles(bool all) const std::set unmodified; std::list files; - for (const auto& f : mLastFiles) { - if (needsReCheck(QString::fromStdString(f.path()), modified, unmodified)) - files.push_back(f); - } + std::copy_if(mLastFiles.cbegin(), mLastFiles.cend(), std::back_inserter(files), [&](const FileWithDetails &f) { + return needsReCheck(QString::fromStdString(f.path()), modified, unmodified); + }); return files; }