Skip to content

refs #13914 - apply enforced language for non-project inputs in GUI #7627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 1 addition & 34 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
38 changes: 38 additions & 0 deletions frontend/frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,42 @@ namespace frontend {
}
}
}

void applyLang(std::list<FileWithDetails>& 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);
}
}
}
}
2 changes: 2 additions & 0 deletions frontend/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@

struct FileSettings;
class Settings;
class FileWithDetails;

namespace frontend
{
/**
Applies the enforced language as all as identifying remaining files - also taking markup files into consideration.
*/
void applyLang(std::list<FileSettings> &fileSettings, const Settings &settings, Standards::Language enforcedLang);
void applyLang(std::list<FileWithDetails> &files, const Settings &settings, Standards::Language enforcedLang);
}

#endif // FRONTEND_H
12 changes: 3 additions & 9 deletions gui/checkthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -121,7 +120,7 @@ void CheckThread::setSettings(const Settings &settings, std::shared_ptr<Suppress
mSuppressions = std::move(supprs);
}

void CheckThread::analyseWholeProgram(const QStringList &files, const std::string& ctuInfo)
void CheckThread::analyseWholeProgram(const std::list<FileWithDetails> &files, const std::string& ctuInfo)
{
mFiles = files;
mAnalyseWholeProgram = true;
Expand All @@ -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<FileWithDetails> 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;
Expand Down
7 changes: 4 additions & 3 deletions gui/checkthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
#ifndef CHECKTHREAD_H
#define CHECKTHREAD_H

#include "filesettings.h"
#include "settings.h"
#include "suppressions.h"

#include <atomic>
#include <cstdint>
#include <list>
#include <memory>
#include <string>
#include <vector>
Expand All @@ -36,7 +38,6 @@
#include <QThread>

class ThreadResult;
struct FileSettings;

/// @addtogroup GUI
/// @{
Expand All @@ -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<FileWithDetails> &files, const std::string& ctuInfo);

void setAddonsAndTools(const QStringList &addonsAndTools) {
mAddonsAndTools = addonsAndTools;
Expand Down Expand Up @@ -142,7 +143,7 @@ class CheckThread : public QThread {

bool isSuppressed(const SuppressionList::ErrorMessage &errorMessage) const;

QStringList mFiles;
std::list<FileWithDetails> mFiles;
bool mAnalyseWholeProgram{};
std::string mCtuInfo;
QStringList mAddonsAndTools;
Expand Down
35 changes: 25 additions & 10 deletions gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
#include "frontend.h"

#include <algorithm>
#include <cstddef>
#include <fstream>
#include <iterator>
#include <list>
#include <memory>
Expand Down Expand Up @@ -661,9 +663,11 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar
return;
}

mUI->mResults->checkingStarted(fileNames.count());
std::list<FileWithDetails> fdetails = enrichFilesForAnalysis(fileNames, checkSettings);

mThread->setFiles(fileNames);
// TODO: lock UI here?
Copy link
Collaborator Author

@firewave firewave Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI is locked earlier in the other instance. Something to look into later (or to consider if ever fixing some issues with it).

mUI->mResults->checkingStarted(fdetails.size());
mThread->setFiles(std::move(fdetails));
if (mProjectFile && !checkConfiguration)
mThread->setAddonsAndTools(mProjectFile->getAddonsAndTools());
mThread->setSuppressions(mProjectFile ? mProjectFile->getCheckingSuppressions() : QList<SuppressionList::Suppression>());
Expand Down Expand Up @@ -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));
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not necessary as this is just a dummy. Also the language is identified below.

connect(&result, SIGNAL(progress(int,QString)),
mUI->mResults, SLOT(progress(int,QString)));
connect(&result, SIGNAL(error(ErrorItem)),
Expand All @@ -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?
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is invoked by the Scratchpad which has it's own field for specifying the language so I think it should not be using the enforced language.

But I wonder if it relies on other project settings? If it does it would be inconsistent and we should remove that field for specifying a file name. If not it would have limited usability because it might require e.g. the standard or libraries to be set. But I guess that should get its own ticket and is not in the scope of this PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cppcheck.check(FileWithDetails(filename.toStdString(), Path::identify(filename.toStdString(), false), 0), code.toStdString());
analysisDone();

Expand Down Expand Up @@ -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<FileWithDetails> 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"
Expand All @@ -1396,7 +1402,7 @@ void MainWindow::reAnalyzeSelected(const QStringList& files)

void MainWindow::reAnalyze(bool all)
{
const QStringList files = mThread->getReCheckFiles(all);
const std::list<FileWithDetails> files = mThread->getReCheckFiles(all);
if (files.empty())
return;

Expand All @@ -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());
Expand Down Expand Up @@ -2349,3 +2355,12 @@ void MainWindow::changeReportType() {
}
}

std::list<FileWithDetails> MainWindow::enrichFilesForAnalysis(const QStringList& fileNames, const Settings& settings) const {
std::list<FileWithDetails> fdetails;
std::transform(fileNames.cbegin(), fileNames.cend(), std::back_inserter(fdetails), [](const QString& f) {
return FileWithDetails{f.toStdString(), Standards::Language::None, static_cast<std::size_t>(QFile(f).size())};
});
const Standards::Language enforcedLang = static_cast<Standards::Language>(mSettings->value(SETTINGS_ENFORCED_LANGUAGE, 0).toInt());
frontend::applyLang(fdetails, settings, enforcedLang);
return fdetails;
}
5 changes: 5 additions & 0 deletions gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "platforms.h"

#include <cstdint>
#include <list>

#include <QFileDialog>
#include <QMainWindow>
Expand All @@ -45,6 +46,7 @@ class QNetworkAccessManager;
class QNetworkReply;
class Settings;
struct Suppressions;
class FileWithDetails;
namespace Ui {
class MainWindow;
}
Expand Down Expand Up @@ -423,6 +425,9 @@ private slots:
*/
void removeProjectMRU(const QString &project);

/** @brief Generate list of detailed files from list of filenames. */
std::list<FileWithDetails> enrichFilesForAnalysis(const QStringList& fileNames, const Settings& settings) const;

/** @brief Program settings */
QSettings *mSettings;

Expand Down
23 changes: 12 additions & 11 deletions gui/threadhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "checkthread.h"
#include "common.h"
#include "filesettings.h"
#include "resultsview.h"
#include "settings.h"

Expand Down Expand Up @@ -55,10 +56,10 @@ void ThreadHandler::clearFiles()
mSuppressionsUI.clear();
}

void ThreadHandler::setFiles(const QStringList &files)
void ThreadHandler::setFiles(std::list<FileWithDetails> files)
{
mResults.setFiles(files);
mLastFiles = files;
mResults.setFiles(std::move(files));
}

void ThreadHandler::setProject(const ImportProject &prj)
Expand All @@ -74,10 +75,10 @@ void ThreadHandler::setCheckFiles(bool all)
}
}

void ThreadHandler::setCheckFiles(const QStringList& files)
void ThreadHandler::setCheckFiles(std::list<FileWithDetails> files)
{
if (mRunningThreadCount == 0) {
mResults.setFiles(files);
mResults.setFiles(std::move(files));
}
}

Expand Down Expand Up @@ -172,6 +173,7 @@ void ThreadHandler::threadDone()
{
mRunningThreadCount--;

// TODO: also run with projects?
if (mRunningThreadCount == 0 && mAnalyseWholeProgram) {
createThreads(1);
mRunningThreadCount = 1;
Expand Down Expand Up @@ -235,7 +237,7 @@ void ThreadHandler::saveSettings(QSettings &settings) const

bool ThreadHandler::hasPreviousFiles() const
{
return !mLastFiles.isEmpty();
return !mLastFiles.empty();
}

int ThreadHandler::getPreviousFilesCount() const
Expand All @@ -248,19 +250,18 @@ int ThreadHandler::getPreviousScanDuration() const
return mScanDuration;
}

QStringList ThreadHandler::getReCheckFiles(bool all) const
std::list<FileWithDetails> ThreadHandler::getReCheckFiles(bool all) const
{
if (mLastCheckTime.isNull() || all)
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]);
}
std::list<FileWithDetails> files;
std::copy_if(mLastFiles.cbegin(), mLastFiles.cend(), std::back_inserter(files), [&](const FileWithDetails &f) {
return needsReCheck(QString::fromStdString(f.path()), modified, unmodified);
});
return files;
}

Expand Down
Loading
Loading