From 8a0d38d4dcc431a508e000ba1fd1a7ed0d808c39 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:01:50 +0100 Subject: [PATCH 01/16] Add tooling configuration --- .clang-tidy | 10 +++++ .github/workflows/code_quality.yml | 36 +++++++++++++++- CLAUDE.md | 67 ++++++++++++++++++++++++++++++ CMakeLists.txt | 2 + scripts/run_clang_format.sh | 29 +++++++++++++ scripts/run_clang_tidy.sh | 14 +++++++ scripts/run_clazy.sh | 15 +++++++ scripts/run_precommit.sh | 29 +++++++++++++ 8 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 .clang-tidy create mode 100644 CLAUDE.md create mode 100755 scripts/run_clang_format.sh create mode 100755 scripts/run_clang_tidy.sh create mode 100755 scripts/run_clazy.sh create mode 100755 scripts/run_precommit.sh diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..d08b109f --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,10 @@ +--- +Checks: > + bugprone-*, + clang-analyzer-*, + -clang-analyzer-cplusplus.NewDelete, + -clang-analyzer-cplusplus.NewDeleteLeaks, + -bugprone-reserved-identifier +WarningsAsErrors: "*" +HeaderFilterRegex: "src/.*" +ExcludeHeaderFilterRegex: ".*qcustomplot.h" diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index 069801c7..9b576874 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -21,7 +21,7 @@ jobs: run: bash /start.sh & - name: configure safe directory for git - run: git config --global --add safe.directory ${GITHUB_WORKSPACE} + run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" - name: Prepare environment for Ninja build with coverage run: | @@ -73,3 +73,37 @@ jobs: args: > --define "sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" if: ${{ !!env.SONAR_TOKEN && !!env.GITHUB_TOKEN }} + + clazy: + runs-on: ubuntu-latest + container: docker://jgeudens/qt-linux:6.8.3_build_1 + steps: + - uses: actions/checkout@v6.0.0 + + - name: Configure safe directory for git + run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" + + - name: Install clazy + run: | + apt-get update + apt-get install -y clazy + + - name: Run clazy + run: bash scripts/run_clazy.sh + + clang-tidy: + runs-on: ubuntu-latest + container: docker://jgeudens/qt-linux:6.8.3_build_1 + steps: + - uses: actions/checkout@v6.0.0 + + - name: Configure safe directory for git + run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" + + - name: Install clang-tidy + run: | + apt-get update + apt-get install -y clang-tidy + + - name: Run clang-tidy + run: bash scripts/run_clang_tidy.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..7e00f2da --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,67 @@ +# ModbusScope — Claude Code Guide + +## Build + +```bash +mkdir -p build && cd build +cmake -GNinja .. +ninja +``` + +Run tests: + +```bash +ctest --output-on-failure +``` + +Run pre-commit checks: + +```bash +./scripts/pre-commit.sh +``` + +**Requirements:** Qt 6, C++20, Ninja. Compiler flags: `-Wall -Wextra -Werror`. + +## Project Structure + +``` +src/ +├── communication/ Modbus protocol layer (ModbusPoll, ModbusMaster, ModbusConnection) +├── models/ Data models (SettingsModel, GraphDataModel, DiagnosticModel, Device, Connection) +├── datahandling/ Expression parsing, graph data processing +├── importexport/ CSV export, MBS project files, MBC device config import +├── dialogs/ UI dialogs and MainWindow +├── customwidgets/ Qt custom widgets +├── graphview/ Graph rendering (qcustomplot) +└── util/ Logging (ScopeLogging), formatting helpers +tests/ Google Test + Qt Test; test files named tst_*.cpp +libraries/ Vendored: qcustomplot, muparser +``` + +## Architecture + +- **SettingsModel** is the central config store — connections, devices, poll time +- **ModbusPoll** orchestrates polling: iterates connections, delegates to **ModbusMaster** per connection +- **ModbusMaster** manages one connection's read cycle via **ModbusConnection** (Qt Modbus) +- **GraphDataHandler** processes raw Modbus results and applies user expressions +- Models emit Qt signals; UI layers observe them — no direct model→UI calls + +## Code Style + +Enforced by `.clang-format` (Mozilla-based, C++20): + +- 4 spaces, no tabs; 120-char line limit +- Braces on new line for classes/functions +- Pointer left-aligned: `Type* ptr` +- Private members: `_camelCase`; pointer members: `_pName` +- Classes: `PascalCase`; methods: `camelCase` +- Use Qt doxygen style for comments + +## Key Conventions + +- Prefer readability and maintainability over using the latest C++ features (avoid syntax sugar that may be less familiar to new contributors). +- Tests use `QCOMPARE` / `QTEST_GUILESS_MAIN` (Qt Test) +- Make sure to document public APIs with brief Doxygen comments +- Update json-rpc schema spec when updating json-rpc related code +- Only use early return for error handling, avoid deep nesting +- When fixing a bug, add a test that reproduces the issue before implementing the fix. \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5187cbbe..baa78bed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,8 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + set(CMAKE_AUTORCC ON) option(USE_GCOV "Enable gcov support" OFF) diff --git a/scripts/run_clang_format.sh b/scripts/run_clang_format.sh new file mode 100755 index 00000000..3485b8f0 --- /dev/null +++ b/scripts/run_clang_format.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -euo pipefail + +CHECK_MODE=false +if [ "${1:-}" = "--check" ]; then + CHECK_MODE=true +fi + +CHANGED_FILES=$( + { git diff --name-only --diff-filter=d HEAD; git ls-files --others --exclude-standard; } \ + | grep -E '\.(cpp|h)$' \ + | sort -u \ + || true +) + +if [ -z "$CHANGED_FILES" ]; then + echo "No changed C++ files." + exit 0 +fi + +echo "=== Files ===" +echo "$CHANGED_FILES" +echo "=== Running clang-format ===" + +if [ "$CHECK_MODE" = true ]; then + echo "$CHANGED_FILES" | xargs clang-format --dry-run --Werror +else + echo "$CHANGED_FILES" | xargs clang-format -i +fi diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh new file mode 100755 index 00000000..21a893f2 --- /dev/null +++ b/scripts/run_clang_tidy.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -euo pipefail + +BUILD_DIR="${1:-build}" +QT_PREFIX="${2:-/opt/Qt/6.8.3/gcc_64}" + +echo "=== Configuring (compile_commands.json) ===" +cmake -GNinja \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_PREFIX_PATH="${QT_PREFIX}" \ + -B "${BUILD_DIR}" + +echo "=== Running clang-tidy ===" +run-clang-tidy -quiet -p "${BUILD_DIR}" -j "$(nproc)" "$(pwd)/src/.*\.cpp\$" 2>/dev/null diff --git a/scripts/run_clazy.sh b/scripts/run_clazy.sh new file mode 100755 index 00000000..74b2933a --- /dev/null +++ b/scripts/run_clazy.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -euo pipefail + +BUILD_DIR="${1:-build}" +QT_PREFIX="${2:-/opt/Qt/6.8.3/gcc_64}" + +echo "=== Configuring (compile_commands.json) ===" +cmake -GNinja \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_PREFIX_PATH="${QT_PREFIX}" \ + -B "${BUILD_DIR}" + +echo "=== Running clazy ===" +find "$(pwd)/src" -name "*.cpp" -print0 | \ + xargs -0 -P "$(nproc)" -I{} clazy-standalone --only-qt -p "${BUILD_DIR}" {} diff --git a/scripts/run_precommit.sh b/scripts/run_precommit.sh new file mode 100755 index 00000000..c0b432b4 --- /dev/null +++ b/scripts/run_precommit.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -uo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "${SCRIPT_DIR}/.." +PASS=0 +FAIL=0 + +run_check() +{ + local name="$1" + shift + echo "=== $name ===" + if "$@"; then + echo "--- $name: PASS" + ((PASS++)) + else + echo "--- $name: FAIL" + ((FAIL++)) + fi + echo "" +} + +run_check "clang-format" bash "${SCRIPT_DIR}/run_clang_format.sh" --check +run_check "clang-tidy" bash "${SCRIPT_DIR}/run_clang_tidy.sh" +run_check "clazy" bash "${SCRIPT_DIR}/run_clazy.sh" + +echo "=== Results: ${PASS} passed, ${FAIL} failed ===" +[ "${FAIL}" -eq 0 ] From 5d39a2cf12fc6e7f86164861e4b7971e1a548b49 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:02:34 +0100 Subject: [PATCH 02/16] Merge initial changes --- src/communication/modbusconnection.cpp | 39 ++++---------------------- src/communication/modbuspoll.cpp | 5 ++-- src/communication/modbusregister.cpp | 21 +++++++------- src/communication/readregisters.cpp | 2 +- src/util/modbusdatatype.cpp | 10 +++---- 5 files changed, 25 insertions(+), 52 deletions(-) diff --git a/src/communication/modbusconnection.cpp b/src/communication/modbusconnection.cpp index 673e85f4..b4b72949 100644 --- a/src/communication/modbusconnection.cpp +++ b/src/communication/modbusconnection.cpp @@ -123,18 +123,8 @@ void ModbusConnection::sendReadRequest(ModbusDataUnit const& regAddress, quint16 */ bool ModbusConnection::isConnected(void) { - if (_connectionList.isEmpty()) - { - return false; - } - else if (_connectionList.last()->pModbusClient->state() != QModbusDevice::ConnectedState) - { - return false; - } - else - { - return true; - } + return !_connectionList.isEmpty() + && _connectionList.last()->pModbusClient->state() == QModbusDevice::ConnectedState; } /*! @@ -147,9 +137,9 @@ void ModbusConnection::handleConnectionStateChanged(QModbusDevice::State state) QModbusClient* pClient = qobject_cast(QObject::sender()); const qint32 senderIdx = findConnectionData(nullptr, pClient); - if (state == QModbusDevice::ConnectingState) + if (state == QModbusDevice::ConnectingState || state == QModbusDevice::ClosingState) { - // Wait for connection or error + // Nothing to do, wait for next state } else if (state == QModbusDevice::ConnectedState) { @@ -200,14 +190,6 @@ void ModbusConnection::handleConnectionStateChanged(QModbusDevice::State state) _connectionList[senderIdx]->deleteLater(); } } - else if (state == QModbusDevice::ClosingState) - { - // Wait for final state - } - else - { - // Do nothing - } } /*! @@ -327,9 +309,7 @@ RegisterType ModbusConnection::registerType(ObjectType type) case ObjectType::INPUT_REGISTER: return RegisterType::InputRegisters; case ObjectType::HOLDING_REGISTER: - return RegisterType::HoldingRegisters; case ObjectType::UNKNOWN: - return RegisterType::HoldingRegisters; default: return RegisterType::HoldingRegisters; } @@ -382,18 +362,11 @@ qint32 ModbusConnection::findConnectionData(QTimer* pTimer, QModbusClient* pClie { for (qint32 idx = 0; idx < _connectionList.size(); idx++) { - if ((pTimer != nullptr) && (pTimer == &_connectionList[idx]->connectionTimeoutTimer)) - { - return idx; - } - else if ((pClient != nullptr) && (pClient == _connectionList[idx]->pModbusClient.get())) + if (((pTimer != nullptr) && (pTimer == &_connectionList[idx]->connectionTimeoutTimer)) + || ((pClient != nullptr) && (pClient == _connectionList[idx]->pModbusClient.get()))) { return idx; } - else - { - // Check next - } } return -1; diff --git a/src/communication/modbuspoll.cpp b/src/communication/modbuspoll.cpp index 3c4dc8d5..a079c366 100755 --- a/src/communication/modbuspoll.cpp +++ b/src/communication/modbuspoll.cpp @@ -11,8 +11,7 @@ using connectionId_t = ConnectionTypes::connectionId_t; -ModbusPoll::ModbusPoll(SettingsModel * pSettingsModel, QObject *parent) : - QObject(parent), _bPollActive(false) +ModbusPoll::ModbusPoll(SettingsModel* pSettingsModel, QObject* parent) : QObject(parent), _bPollActive(false) { _pPollTimer = new QTimer(); @@ -181,7 +180,7 @@ bool ModbusPoll::isActive() void ModbusPoll::triggerRegisterRead() { - if(_bPollActive) + if (_bPollActive) { _lastPollStart = QDateTime::currentMSecsSinceEpoch(); diff --git a/src/communication/modbusregister.cpp b/src/communication/modbusregister.cpp index 8a4dd4d6..444cf781 100644 --- a/src/communication/modbusregister.cpp +++ b/src/communication/modbusregister.cpp @@ -1,5 +1,7 @@ #include "modbusregister.h" +#include + ModbusRegister::ModbusRegister() : ModbusRegister(ModbusAddress(0), Device::cFirstDeviceId, ModbusDataType::Type::UNSIGNED_16) { @@ -153,19 +155,18 @@ uint32_t ModbusRegister::convertEndianness(bool bLittleEndian, quint16 value, qu double ModbusRegister::convertUint32ToFloat(quint32 value) const { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" - const double doubleValue = *(reinterpret_cast(&value)); -#pragma GCC diagnostic pop + const double doubleValue = std::bit_cast(value); switch(std::fpclassify(doubleValue)) { - case FP_INFINITE: return 0.0f; - case FP_NAN: return 0.0f; - case FP_NORMAL: return doubleValue; - case FP_SUBNORMAL: return doubleValue; - case FP_ZERO: return 0.0f; - default: return doubleValue; + case FP_INFINITE: + case FP_NAN: + case FP_ZERO: + return 0.0f; + case FP_NORMAL: + case FP_SUBNORMAL: + default: + return doubleValue; } } diff --git a/src/communication/readregisters.cpp b/src/communication/readregisters.cpp index daba88ee..3d02ea4d 100644 --- a/src/communication/readregisters.cpp +++ b/src/communication/readregisters.cpp @@ -139,7 +139,7 @@ void ReadRegisters::addError() if (hasNext()) { auto nextRequestData = next(); - for (quint32 i = 0; i < nextRequestData.count(); i++) + for (int i = 0; i < nextRequestData.count(); i++) { const auto registerAddr = nextRequestData.address().next(i); const auto result = Result(0, State::INVALID); diff --git a/src/util/modbusdatatype.cpp b/src/util/modbusdatatype.cpp index f49da89a..b57f63a3 100644 --- a/src/util/modbusdatatype.cpp +++ b/src/util/modbusdatatype.cpp @@ -3,9 +3,9 @@ const ModbusDataType::TypeSettings ModbusDataType::cDataTypes[] = { - [static_cast(ModbusDataType::Type::UNSIGNED_16)] = {.b32Bit = false, .bUnsigned = true, .bFloat = false}, - [static_cast(ModbusDataType::Type::SIGNED_16)] = {.b32Bit = false, .bUnsigned = false, .bFloat = false}, - [static_cast(ModbusDataType::Type::UNSIGNED_32)] = {.b32Bit = true, .bUnsigned = true, .bFloat = false}, - [static_cast(ModbusDataType::Type::SIGNED_32)] = {.b32Bit = true, .bUnsigned = false, .bFloat = false}, - [static_cast(ModbusDataType::Type::FLOAT_32)] = {.b32Bit = true, .bUnsigned = false, .bFloat = true}, + /* UNSIGNED_16 */ {false, true, false}, + /* SIGNED_16 */ {false, false, false}, + /* UNSIGNED_32 */ {true, true, false}, + /* SIGNED_32 */ {true, false, false}, + /* FLOAT_32 */ {true, false, true }, }; From 9ab2b99aaca3c6872f73524a6bcec909f820bc9c Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:19:32 +0100 Subject: [PATCH 03/16] Exclude qcustomplot --- scripts/run_clazy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_clazy.sh b/scripts/run_clazy.sh index 74b2933a..13197aae 100755 --- a/scripts/run_clazy.sh +++ b/scripts/run_clazy.sh @@ -12,4 +12,4 @@ cmake -GNinja \ echo "=== Running clazy ===" find "$(pwd)/src" -name "*.cpp" -print0 | \ - xargs -0 -P "$(nproc)" -I{} clazy-standalone --only-qt -p "${BUILD_DIR}" {} + xargs -0 -P "$(nproc)" -I{} clazy-standalone --only-qt --header-filter="src/.*" -p "${BUILD_DIR}" {} From caf7e01e2aee662fbcc3ff887cfcd5578be4e5a2 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:19:35 +0100 Subject: [PATCH 04/16] fix: add missing emit keyword on signal call Co-Authored-By: Claude Sonnet 4.6 --- src/dialogs/settingsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialogs/settingsdialog.cpp b/src/dialogs/settingsdialog.cpp index 6e1220cb..1af4d390 100644 --- a/src/dialogs/settingsdialog.cpp +++ b/src/dialogs/settingsdialog.cpp @@ -71,7 +71,7 @@ void SettingsDialog::settingsStackSwitch(int newRow) // Validate device settings when switching to tab if (newRow == PAGE_DEVICE) { - _pDevSettings->settingsTabsSwitched(); + emit _pDevSettings->settingsTabsSwitched(); } _pUi->settingsStack->setCurrentIndex(newRow); From 3f454514f15a67207880efa6f2e793071c187378 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:20:06 +0100 Subject: [PATCH 05/16] fix: fully qualify GuiState in slot declaration Fixes clazy-fully-qualified-moc-types: MOC requires enum types in slot/signal declarations to be fully qualified. Co-Authored-By: Claude Sonnet 4.6 --- src/models/guimodel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/guimodel.h b/src/models/guimodel.h index 7252e724..964e7ba8 100644 --- a/src/models/guimodel.h +++ b/src/models/guimodel.h @@ -92,7 +92,7 @@ public slots: void sety2AxisMin(double newMin); void setyAxisMax(double newMax); void sety2AxisMax(double newMax); - void setGuiState(GuiState state); + void setGuiState(GuiModel::GuiState state); void clearMarkersState(void); void setStartMarkerPos(double pos); void setEndMarkerPos(double pos); From 887e50b77247f4e5f662396dc5a45eb0eefa6396 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:20:58 +0100 Subject: [PATCH 06/16] fix: wrap range-loop containers in std::as_const Prevents implicit detachment of Qt containers when iterating with range-based for loops. Co-Authored-By: Claude Sonnet 4.6 --- src/communication/modbuspoll.cpp | 2 +- src/customwidgets/deviceform.cpp | 4 ++-- src/dialogs/devicesettings.cpp | 2 +- src/importexport/projectfileexporter.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/communication/modbuspoll.cpp b/src/communication/modbuspoll.cpp index a079c366..4e99bd66 100755 --- a/src/communication/modbuspoll.cpp +++ b/src/communication/modbuspoll.cpp @@ -87,7 +87,7 @@ void ModbusPoll::startCommunication(QList& registerList) } qCInfo(scopeCommConnection) << qPrintable(str); - for (deviceId_t devId : _pSettingsModel->deviceListForConnection(i)) + for (deviceId_t devId : std::as_const(_pSettingsModel->deviceListForConnection(i))) { Device* dev = _pSettingsModel->deviceSettings(devId); QString devStr = QString("[Device] %1: slave ID %2, max consecutive %3, 32-bit little endian %4") diff --git a/src/customwidgets/deviceform.cpp b/src/customwidgets/deviceform.cpp index f5efd6fe..491965fa 100644 --- a/src/customwidgets/deviceform.cpp +++ b/src/customwidgets/deviceform.cpp @@ -72,7 +72,7 @@ void DeviceForm::updateConnectionList() _pUi->comboConnection->blockSignals(true); _pUi->comboConnection->clear(); - for (auto connId : _pSettingsModel->connectionList()) + for (auto connId : std::as_const(_pSettingsModel->connectionList())) { _pUi->comboConnection->addItem(QString("Connection %1").arg(connId + 1), static_cast(connId)); } @@ -99,7 +99,7 @@ void DeviceForm::checkConnectionState() Device* device = _pSettingsModel->deviceSettings(_deviceId); ConnectionTypes::connectionId_t connId = device->connectionId(); bool bConnExistsAndEnabled = false; - for (auto availableConnId : _pSettingsModel->connectionList()) + for (auto availableConnId : std::as_const(_pSettingsModel->connectionList())) { if (availableConnId == connId && _pSettingsModel->connectionState(connId)) { diff --git a/src/dialogs/devicesettings.cpp b/src/dialogs/devicesettings.cpp index ef3c47ba..1883c0b8 100644 --- a/src/dialogs/devicesettings.cpp +++ b/src/dialogs/devicesettings.cpp @@ -18,7 +18,7 @@ DeviceSettings::DeviceSettings(SettingsModel* pSettingsModel, QWidget* parent) QList pages; QStringList names; - for (deviceId_t const& devId : _pSettingsModel->deviceList()) + for (deviceId_t const& devId : std::as_const(_pSettingsModel->deviceList())) { names.append(constructTabName(devId)); pages.append(createForm(devId)); diff --git a/src/importexport/projectfileexporter.cpp b/src/importexport/projectfileexporter.cpp index 435f88b5..d581b91d 100644 --- a/src/importexport/projectfileexporter.cpp +++ b/src/importexport/projectfileexporter.cpp @@ -104,7 +104,7 @@ void ProjectFileExporter::createDeviceTags(QDomElement* pParentElement) { QList deviceList = _pSettingsModel->deviceList(); - for (const deviceId_t& deviceId : deviceList) + for (const deviceId_t& deviceId : std::as_const(deviceList)) { Device* device = _pSettingsModel->deviceSettings(deviceId); QDomElement deviceElement = _domDocument.createElement(ProjectFileDefinitions::cDeviceTag); From 47447b7d520fc59bcc49ba0b600f131039f7fa42 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:21:48 +0100 Subject: [PATCH 07/16] fix: use constLast/at() to avoid detaching temporaries Replace last() with constLast() and operator[]() with at() on temporary QList values to avoid detachment. Co-Authored-By: Claude Sonnet 4.6 --- src/dialogs/importmbcdialog.cpp | 2 +- src/dialogs/mainwindow.cpp | 2 +- src/graphview/graphscaling.cpp | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/dialogs/importmbcdialog.cpp b/src/dialogs/importmbcdialog.cpp index 63767f37..e779148b 100644 --- a/src/dialogs/importmbcdialog.cpp +++ b/src/dialogs/importmbcdialog.cpp @@ -223,7 +223,7 @@ void ImportMbcDialog::dragEnterEvent(QDragEnterEvent* e) void ImportMbcDialog::dropEvent(QDropEvent* e) { - const QString filename(e->mimeData()->urls().last().toLocalFile()); + const QString filename(e->mimeData()->urls().constLast().toLocalFile()); _pUi->lineMbcfile->setText(filename); _pGuiModel->setLastMbcImportedFile(filename); diff --git a/src/dialogs/mainwindow.cpp b/src/dialogs/mainwindow.cpp index 6baa5f54..5e1e31ee 100755 --- a/src/dialogs/mainwindow.cpp +++ b/src/dialogs/mainwindow.cpp @@ -808,7 +808,7 @@ void MainWindow::dropEvent(QDropEvent *e) { if (!_pModbusPoll->isActive()) { - const QString filename(e->mimeData()->urls().last().toLocalFile()); + const QString filename(e->mimeData()->urls().constLast().toLocalFile()); handleFileOpen(filename); } } diff --git a/src/graphview/graphscaling.cpp b/src/graphview/graphscaling.cpp index debf8655..d0ce2846 100644 --- a/src/graphview/graphscaling.cpp +++ b/src/graphview/graphscaling.cpp @@ -22,19 +22,19 @@ GraphScale::GraphScale(GuiModel* pGuiModel, ScopePlot* pPlot, QObject *parent) : _pPlot->setNoAntialiasingOnDrag(true); // Replace y-axis with custom value axis - _pPlot->axisRect()->removeAxis(_pPlot->axisRect()->axes(QCPAxis::atLeft)[0]); + _pPlot->axisRect()->removeAxis(_pPlot->axisRect()->axes(QCPAxis::atLeft).at(0)); _pPlot->axisRect()->addAxis(QCPAxis::atLeft, new ValueAxis(_pPlot->axisRect(), QCPAxis::atLeft)); // Replace y2-axis with custom value axis - _pPlot->axisRect()->removeAxis(_pPlot->axisRect()->axes(QCPAxis::atRight)[0]); + _pPlot->axisRect()->removeAxis(_pPlot->axisRect()->axes(QCPAxis::atRight).at(0)); _pPlot->axisRect()->addAxis(QCPAxis::atRight, new ValueAxis(_pPlot->axisRect(), QCPAxis::atRight)); connect(_pPlot->xAxis, QOverload::of(&QCPAxis::rangeChanged), this, &GraphScale::timeAxisRangeChanged); // Fix axis settings - QCPAxis * pXAxis = _pPlot->axisRect()->axes(QCPAxis::atBottom)[0]; - QCPAxis * pYAxis = _pPlot->axisRect()->axes(QCPAxis::atLeft)[0]; - QCPAxis * pY2Axis = _pPlot->axisRect()->axes(QCPAxis::atRight)[0]; + QCPAxis * pXAxis = _pPlot->axisRect()->axes(QCPAxis::atBottom).at(0); + QCPAxis * pYAxis = _pPlot->axisRect()->axes(QCPAxis::atLeft).at(0); + QCPAxis * pY2Axis = _pPlot->axisRect()->axes(QCPAxis::atRight).at(0); pYAxis->grid()->setVisible(true); pY2Axis->grid()->setVisible(true); From 07a6496882c3f5ef1fde990e8c1aff0e92099507 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:31:17 +0100 Subject: [PATCH 08/16] Fix compilation --- src/communication/modbuspoll.cpp | 3 ++- src/customwidgets/deviceform.cpp | 6 ++++-- src/dialogs/devicesettings.cpp | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/communication/modbuspoll.cpp b/src/communication/modbuspoll.cpp index 4e99bd66..ba897b35 100755 --- a/src/communication/modbuspoll.cpp +++ b/src/communication/modbuspoll.cpp @@ -87,7 +87,8 @@ void ModbusPoll::startCommunication(QList& registerList) } qCInfo(scopeCommConnection) << qPrintable(str); - for (deviceId_t devId : std::as_const(_pSettingsModel->deviceListForConnection(i))) + const auto devicesForConn = _pSettingsModel->deviceListForConnection(i); + for (deviceId_t devId : devicesForConn) { Device* dev = _pSettingsModel->deviceSettings(devId); QString devStr = QString("[Device] %1: slave ID %2, max consecutive %3, 32-bit little endian %4") diff --git a/src/customwidgets/deviceform.cpp b/src/customwidgets/deviceform.cpp index 491965fa..e23d189c 100644 --- a/src/customwidgets/deviceform.cpp +++ b/src/customwidgets/deviceform.cpp @@ -72,7 +72,8 @@ void DeviceForm::updateConnectionList() _pUi->comboConnection->blockSignals(true); _pUi->comboConnection->clear(); - for (auto connId : std::as_const(_pSettingsModel->connectionList())) + const auto connList = _pSettingsModel->connectionList(); + for (auto connId : connList) { _pUi->comboConnection->addItem(QString("Connection %1").arg(connId + 1), static_cast(connId)); } @@ -99,7 +100,8 @@ void DeviceForm::checkConnectionState() Device* device = _pSettingsModel->deviceSettings(_deviceId); ConnectionTypes::connectionId_t connId = device->connectionId(); bool bConnExistsAndEnabled = false; - for (auto availableConnId : std::as_const(_pSettingsModel->connectionList())) + const auto availableConnList = _pSettingsModel->connectionList(); + for (auto availableConnId : availableConnList) { if (availableConnId == connId && _pSettingsModel->connectionState(connId)) { diff --git a/src/dialogs/devicesettings.cpp b/src/dialogs/devicesettings.cpp index 1883c0b8..2c49205a 100644 --- a/src/dialogs/devicesettings.cpp +++ b/src/dialogs/devicesettings.cpp @@ -18,7 +18,8 @@ DeviceSettings::DeviceSettings(SettingsModel* pSettingsModel, QWidget* parent) QList pages; QStringList names; - for (deviceId_t const& devId : std::as_const(_pSettingsModel->deviceList())) + const auto devList = _pSettingsModel->deviceList(); + for (deviceId_t const& devId : devList) { names.append(constructTabName(devId)); pages.append(createForm(devId)); From 8cee9f78ea63329638be4fe501b21f27ad5bc090 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 21:49:25 +0100 Subject: [PATCH 09/16] Remove sonarqube --- .github/workflows/code_quality.yml | 31 ------------------------------ 1 file changed, 31 deletions(-) diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index 9b576874..804c07fc 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -43,37 +43,6 @@ jobs: PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} if: ${{ !!env.PROJECT_TOKEN }} - sonarqube: - runs-on: ubuntu-latest - container: docker://jgeudens/qt-linux:6.8.3_build_1 - env: - BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v6.0.0 - with: - # Disabling shallow clone is recommended for improving relevancy of reporting - fetch-depth: 0 - - - name: Install Build Wrapper - uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v7.0 - - - name: Run build-wrapper - run: | - # here goes your compilation wrapped with build-wrapper; See https://docs.sonarcloud.io/advanced-setup/languages/c-c-objective-c/#analysis-steps-using-build-wrapper for more information - cmake . -GNinja - build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} ninja - if: ${{ !!env.SONAR_TOKEN && !!env.GITHUB_TOKEN }} - - - name: SonarQube Scan - uses: SonarSource/sonarqube-scan-action@v7.0 - with: - # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options - args: > - --define "sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" - if: ${{ !!env.SONAR_TOKEN && !!env.GITHUB_TOKEN }} - clazy: runs-on: ubuntu-latest container: docker://jgeudens/qt-linux:6.8.3_build_1 From e0af7f2d5ba64c167da2e45ac9b211399f83b802 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Wed, 18 Mar 2026 22:25:25 +0100 Subject: [PATCH 10/16] Update scripts --- .clang-tidy | 7 +++++-- scripts/run_clang_tidy.sh | 3 +++ scripts/run_precommit.sh | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index d08b109f..e3d9d99b 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,7 +4,10 @@ Checks: > clang-analyzer-*, -clang-analyzer-cplusplus.NewDelete, -clang-analyzer-cplusplus.NewDeleteLeaks, - -bugprone-reserved-identifier + -bugprone-reserved-identifier, + -bugprone-easily-swappable-parameters, + -bugprone-narrowing-conversions + WarningsAsErrors: "*" HeaderFilterRegex: "src/.*" -ExcludeHeaderFilterRegex: ".*qcustomplot.h" +ExcludeHeaderFilterRegex: ".*(qcustomplot|ui_[a-z]+).h" diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 21a893f2..99b94d21 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -10,5 +10,8 @@ cmake -GNinja \ -DCMAKE_PREFIX_PATH="${QT_PREFIX}" \ -B "${BUILD_DIR}" +echo "=== Generating autogen headers ===" +ninja -C "${BUILD_DIR}" src/ScopeSource_autogen + echo "=== Running clang-tidy ===" run-clang-tidy -quiet -p "${BUILD_DIR}" -j "$(nproc)" "$(pwd)/src/.*\.cpp\$" 2>/dev/null diff --git a/scripts/run_precommit.sh b/scripts/run_precommit.sh index c0b432b4..1e618345 100755 --- a/scripts/run_precommit.sh +++ b/scripts/run_precommit.sh @@ -21,7 +21,7 @@ run_check() echo "" } -run_check "clang-format" bash "${SCRIPT_DIR}/run_clang_format.sh" --check +run_check "clang-format" bash "${SCRIPT_DIR}/run_clang_format.sh" run_check "clang-tidy" bash "${SCRIPT_DIR}/run_clang_tidy.sh" run_check "clazy" bash "${SCRIPT_DIR}/run_clazy.sh" From c2a525f1ba51630fa13d91a0a099f3ac2b52ed7b Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Thu, 19 Mar 2026 17:17:30 +0100 Subject: [PATCH 11/16] fix: resolve bugprone-too-small-loop-variable clang-tidy violations Loop counters used types narrower than qsizetype (the return type of QList::size()), causing potential truncation on large lists. Co-Authored-By: Claude Sonnet 4.6 --- src/communication/modbuspoll.cpp | 2 +- src/communication/registervaluehandler.cpp | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/communication/modbuspoll.cpp b/src/communication/modbuspoll.cpp index ba897b35..c7c34298 100755 --- a/src/communication/modbuspoll.cpp +++ b/src/communication/modbuspoll.cpp @@ -37,7 +37,7 @@ ModbusPoll::ModbusPoll(SettingsModel* pSettingsModel, QObject* parent) : QObject ModbusPoll::~ModbusPoll() { - for (quint8 i = 0u; i < _modbusMasters.size(); i++) + for (qsizetype i = 0; i < _modbusMasters.size(); i++) { _modbusMasters[i]->pModbusMaster->disconnect(); diff --git a/src/communication/registervaluehandler.cpp b/src/communication/registervaluehandler.cpp index 8b545244..a364bbb3 100644 --- a/src/communication/registervaluehandler.cpp +++ b/src/communication/registervaluehandler.cpp @@ -7,8 +7,7 @@ using State = ResultState::State; using connectionId_t = ConnectionTypes::connectionId_t; -RegisterValueHandler::RegisterValueHandler(SettingsModel *pSettingsModel) : - _pSettingsModel(pSettingsModel) +RegisterValueHandler::RegisterValueHandler(SettingsModel* pSettingsModel) : _pSettingsModel(pSettingsModel) { } @@ -16,7 +15,7 @@ void RegisterValueHandler::startRead() { _resultList.clear(); - for(quint16 listIdx = 0; listIdx < _registerList.size(); listIdx++) + for (qsizetype listIdx = 0; listIdx < _registerList.size(); listIdx++) { _resultList.append(ResultDouble(0, State::INVALID)); } @@ -31,7 +30,7 @@ void RegisterValueHandler::processPartialResult(ModbusResultMap partialResultMap { auto deviceList = _pSettingsModel->deviceListForConnection(connectionId); - for(qint32 listIdx = 0; listIdx < _registerList.size(); listIdx++) + for (qint32 listIdx = 0; listIdx < _registerList.size(); listIdx++) { const ModbusRegister mbReg = _registerList[listIdx]; From a9bcf8b46732f129cfd214e7993110f584ff0e2f Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Thu, 19 Mar 2026 17:20:48 +0100 Subject: [PATCH 12/16] fix: resolve bugprone-branch-clone clang-tidy violations Merged consecutive branches with identical bodies into single conditions: - communicationstats: combine size()==0 and size()<=1 checks - mbcregisterfilter: simplify tab filter to single boolean expression - settingsauto: merge two group-separator space-replacement branches - datafileexporter: merge skip-line conditions for notes and empty comments - graphview: invert handled-move check to remove two empty branches - fileselectionhelper: merge FILE_TYPE_NONE and default break cases Co-Authored-By: Claude Sonnet 4.6 --- src/communication/communicationstats.cpp | 18 ++-- src/graphview/graphview.cpp | 105 +++++++++++------------ src/importexport/datafileexporter.cpp | 68 +++++++-------- src/importexport/settingsauto.cpp | 36 +++----- src/models/mbcregisterfilter.cpp | 26 ++---- src/util/fileselectionhelper.cpp | 5 +- 6 files changed, 104 insertions(+), 154 deletions(-) mode change 100755 => 100644 src/graphview/graphview.cpp mode change 100755 => 100644 src/importexport/datafileexporter.cpp diff --git a/src/communication/communicationstats.cpp b/src/communication/communicationstats.cpp index 0ebbf495..1fa72bd5 100644 --- a/src/communication/communicationstats.cpp +++ b/src/communication/communicationstats.cpp @@ -5,10 +5,11 @@ const uint32_t CommunicationStats::_cUpdateTime = 500; -CommunicationStats::CommunicationStats(GraphDataModel* pGraphDataModel, quint32 sampleCalculationSize, QObject *parent) - : QObject{parent}, _pGraphDataModel (pGraphDataModel), _sampleCalculationSize(sampleCalculationSize) +CommunicationStats::CommunicationStats(GraphDataModel* pGraphDataModel, quint32 sampleCalculationSize, QObject* parent) + : QObject{ parent }, _pGraphDataModel(pGraphDataModel), _sampleCalculationSize(sampleCalculationSize) { - connect(this, &CommunicationStats::triggerRunTimeUpdate, _pGraphDataModel, &GraphDataModel::communicationTimeStatsChanged); + connect(this, &CommunicationStats::triggerRunTimeUpdate, _pGraphDataModel, + &GraphDataModel::communicationTimeStatsChanged); } void CommunicationStats::updateTimingInfo() @@ -16,11 +17,7 @@ void CommunicationStats::updateTimingInfo() QList diffList; quint32 timeMedian; - if (_pGraphDataModel->size() == 0u) - { - timeMedian = 0u; - } - else if (_pGraphDataModel->dataMap(0)->size() <= 1) + if (_pGraphDataModel->size() == 0u || _pGraphDataModel->dataMap(0)->size() <= 1) { timeMedian = 0u; } @@ -71,7 +68,8 @@ void CommunicationStats::stop() void CommunicationStats::incrementCommunicationStats(quint32 successes, quint32 errors) { - _pGraphDataModel->setCommunicationStats(_pGraphDataModel->communicationSuccessCount() + successes, _pGraphDataModel->communicationErrorCount() + errors); + _pGraphDataModel->setCommunicationStats(_pGraphDataModel->communicationSuccessCount() + successes, + _pGraphDataModel->communicationErrorCount() + errors); } void CommunicationStats::updateRuntime() @@ -88,7 +86,7 @@ void CommunicationStats::updateCommunicationStats(ResultDoubleList resultList) { quint32 error = 0; quint32 success = 0; - for(const auto &result: resultList) + for (const auto& result : resultList) { result.isValid() ? success++ : error++; } diff --git a/src/graphview/graphview.cpp b/src/graphview/graphview.cpp old mode 100755 new mode 100644 index c8258124..bb03d7af --- a/src/graphview/graphview.cpp +++ b/src/graphview/graphview.cpp @@ -20,8 +20,13 @@ #include #include -GraphView::GraphView(GuiModel * pGuiModel, SettingsModel *pSettingsModel, GraphDataModel * pGraphDataModel, NoteModel *pNoteModel, ScopePlot * pPlot, QObject *parent) : - QObject(parent) +GraphView::GraphView(GuiModel* pGuiModel, + SettingsModel* pSettingsModel, + GraphDataModel* pGraphDataModel, + NoteModel* pNoteModel, + ScopePlot* pPlot, + QObject* parent) + : QObject(parent) { _pGuiModel = pGuiModel; _pGraphDataModel = pGraphDataModel; @@ -30,21 +35,21 @@ GraphView::GraphView(GuiModel * pGuiModel, SettingsModel *pSettingsModel, GraphD _pPlot = pPlot; /* - * Greatly improves performance - * - * phFastPolylines Graph/Curve lines are drawn with a faster method. This reduces the quality especially - * of the line segment joins. (Only relevant for solid line pens.) - * phCacheLabels axis (tick) labels will be cached as pixmaps, increasing replot performance. - * */ + * Greatly improves performance + * + * phFastPolylines Graph/Curve lines are drawn with a faster method. This reduces the quality especially + * of the line segment joins. (Only relevant for solid line pens.) + * phCacheLabels axis (tick) labels will be cached as pixmaps, increasing replot performance. + * */ _pPlot->setPlottingHints(QCP::phCacheLabels | QCP::phFastPolylines); _pPlot->setInteraction(QCP::iSelectPlottables, true); /* - * Use other modifier key than Ctrl for multi select. - * ModbusScope uses Ctrl for adding/moving marker. - * Note: Multi select is disabled, but modifier needs to be changed from default. - * */ + * Use other modifier key than Ctrl for multi select. + * ModbusScope uses Ctrl for adding/moving marker. + * Note: Multi select is disabled, but modifier needs to be changed from default. + * */ _pPlot->setMultiSelectModifier(Qt::ShiftModifier); // Samples are enabled @@ -88,7 +93,7 @@ qint32 GraphView::graphDataSize() return _pPlot->graph(0)->data()->size(); } -bool GraphView::valuesUnderCursor(QList &valueList) +bool GraphView::valuesUnderCursor(QList& valueList) { bool bRet = true; @@ -104,14 +109,11 @@ bool GraphView::valuesUnderCursor(QList &valueList) // Check all graphs for (qint32 activeGraphIndex = 0; activeGraphIndex < _pPlot->graphCount(); activeGraphIndex++) { - if ( - _pPlot->underMouse() - && bValid - && keyRange.contains(xPos) - ) + if (_pPlot->underMouse() && bValid && keyRange.contains(xPos)) { const qint32 graphIdx = _pGraphDataModel->convertToGraphIndex(activeGraphIndex); - QCPGraphDataContainer::const_iterator graphDataIt = _pGraphDataModel->dataMap(graphIdx).data()->findBegin(tooltipPos, false); + QCPGraphDataContainer::const_iterator graphDataIt = + _pGraphDataModel->dataMap(graphIdx).data()->findBegin(tooltipPos, false); valueList.append(graphDataIt->value); } else @@ -128,7 +130,6 @@ bool GraphView::valuesUnderCursor(QList &valueList) } return bRet; - } QPointF GraphView::pixelToPointF(const QPoint& pixel) const @@ -197,7 +198,7 @@ void GraphView::clearGraph(const quint32 graphIdx) QCPGraphDataContainer::iterator it = _pGraphDataModel->dataMap(graphIdx)->begin(); /* Clear all values, keep keys */ - while(it != _pGraphDataModel->dataMap(graphIdx)->end()) + while (it != _pGraphDataModel->dataMap(graphIdx)->end()) { it->value = 0u; it++; @@ -225,7 +226,7 @@ void GraphView::updateGraphs() qint32 maxSampleCount = 0; quint32 maxSampleIdx = 0; - foreach(quint16 graphIdx, activeGraphList) + foreach (quint16 graphIdx, activeGraphList) { const qint32 sampleCount = _pGraphDataModel->dataMap(graphIdx)->size(); if (sampleCount > maxSampleCount) @@ -236,9 +237,9 @@ void GraphView::updateGraphs() } // Graph that have less points will be zeroed with that amount of points - foreach(quint16 graphIdx, activeGraphList) + foreach (quint16 graphIdx, activeGraphList) { - QCPGraph * pGraph = _pPlot->addGraph(); + QCPGraph* pGraph = _pPlot->addGraph(); setGraphAxis(pGraph, _pGraphDataModel->valueAxis(graphIdx)); setGraphColor(pGraph, _pGraphDataModel->color(graphIdx)); pGraph->setSelectable(QCP::stWhole); @@ -256,7 +257,7 @@ void GraphView::updateGraphs() // Add zero value for every key (x-coordinate) QCPGraphDataContainer::const_iterator refIt = pReferenceMap->constBegin(); - while(refIt != pReferenceMap->constEnd()) + while (refIt != pReferenceMap->constEnd()) { pMap->add(QCPGraphData(refIt->key, 0)); refIt++; @@ -290,7 +291,7 @@ void GraphView::changeGraphColor(const quint32 graphIdx) } void GraphView::changeGraphAxis(const quint32 graphIdx) -{ +{ if (_pGraphDataModel->isActive(graphIdx)) { const quint32 activeIdx = _pGraphDataModel->convertToActiveGraphIndex(graphIdx); @@ -362,9 +363,9 @@ void GraphView::addData(QList timeData, QList > data) { _pGuiModel->setHighlightSamples(false); - for (qint32 i = 0; i < _pPlot->graphCount(); i++) + for (qint32 i = 0; i < _pPlot->graphCount(); i++) { - _pPlot->graph(i)->pen().setWidth(1); + _pPlot->graph(i)->pen().setWidth(1); } _pPlot->setNotAntialiasedElements(QCP::aeAll); @@ -414,7 +415,7 @@ void GraphView::plotResults(ResultDoubleList resultList) QList dataList; uint32_t i = 0; - for (const auto &result: resultList) + for (const auto& result : resultList) { if (result.isValid()) { @@ -432,7 +433,7 @@ void GraphView::plotResults(ResultDoubleList resultList) emit dataAddedToPlot(timeData, dataList); - rescalePlot(); + rescalePlot(); } void GraphView::clearResults() @@ -454,7 +455,7 @@ void GraphView::showMarkers() _pGuiModel->setEndMarkerPos(getClosestPoint(endPos)); } -void GraphView::mousePress(QMouseEvent *event) +void GraphView::mousePress(QMouseEvent* event) { if (_pGraphViewZoom->handleMousePress(event)) { @@ -503,12 +504,12 @@ void GraphView::mousePress(QMouseEvent *event) } } -void GraphView::mouseRelease(QMouseEvent *event) +void GraphView::mouseRelease(QMouseEvent* event) { Q_UNUSED(event); - (void)_pGraphViewZoom->handleMouseRelease(); - (void)_pNoteHandling->handleMouseRelease(); + (void) _pGraphViewZoom->handleMouseRelease(); + (void) _pNoteHandling->handleMouseRelease(); /* Always re-enable range drag */ _pGraphScale->enableRangeZoom(); @@ -526,22 +527,14 @@ void GraphView::mouseWheel() } } -void GraphView::mouseMove(QMouseEvent *event) +void GraphView::mouseMove(QMouseEvent* event) { // Check for graph drag - if(event->buttons() & Qt::LeftButton) + if (event->buttons() & Qt::LeftButton) { if (!(event->modifiers() & Qt::ControlModifier)) { - if (_pGraphViewZoom->handleMouseMove(event)) - { - /* Already handled by graph zoom */ - } - else if (_pNoteHandling->handleMouseMove(event)) - { - /* Already handled by graph zoom */ - } - else + if (!_pGraphViewZoom->handleMouseMove(event) && !_pNoteHandling->handleMouseMove(event)) { _pGraphScale->handleDrag(); } @@ -562,7 +555,7 @@ void GraphView::handleSelectionChanged(bool selected) { if (selected) { - QCPGraph * pGraph = qobject_cast(QObject::sender()); + QCPGraph* pGraph = qobject_cast(QObject::sender()); const qint32 activeIdx = getActiveGraphIndex(pGraph); const qint32 graphIdx = _pGraphDataModel->convertToGraphIndex(activeIdx); _pGraphDataModel->setSelectedGraph(graphIdx); @@ -594,7 +587,7 @@ void GraphView::handleSelectionChanged(bool selected) void GraphView::paintTimeStampToolTip(QPoint pos) { - if (_pGuiModel->cursorValues() && (_pPlot->graphCount() > 0)) + if (_pGuiModel->cursorValues() && (_pPlot->graphCount() > 0)) { const double xPos = _pPlot->xAxis->pixelToCoord(pos.x()); double tooltipPos = getClosestPoint(xPos); @@ -605,7 +598,7 @@ void GraphView::paintTimeStampToolTip(QPoint pos) if (bValid && keyRange.contains(xPos)) { QString toolText = FormatRelativeTime::formatTime(tooltipPos); - QPoint location= _pPlot->mapToGlobal(pos); + QPoint location = _pPlot->mapToGlobal(pos); if (location != _tooltipLocation) { @@ -617,7 +610,7 @@ void GraphView::paintTimeStampToolTip(QPoint pos) else { QToolTip::hideText(); - _tooltipLocation = QPoint(-1 ,-1); + _tooltipLocation = QPoint(-1, -1); } } else @@ -625,7 +618,7 @@ void GraphView::paintTimeStampToolTip(QPoint pos) if (QToolTip::isVisible()) { QToolTip::hideText(); - _tooltipLocation = QPoint(-1 ,-1); + _tooltipLocation = QPoint(-1, -1); } } } @@ -646,7 +639,8 @@ void GraphView::handleSamplePoints() const int pointCount = upperBoundIt - lowerBoundIt; /* Get size in pixels */ - const double sizePx = _pPlot->xAxis->coordToPixel(upperBoundIt->key) - _pPlot->xAxis->coordToPixel(lowerBoundIt->key); + const double sizePx = + _pPlot->xAxis->coordToPixel(upperBoundIt->key) - _pPlot->xAxis->coordToPixel(lowerBoundIt->key); /* Calculate number of pixels per point */ double nrOfPixelsPerPoint; @@ -664,7 +658,6 @@ void GraphView::handleSamplePoints() { bHighlight = true; } - } } @@ -687,7 +680,7 @@ void GraphView::highlightSamples(bool bState) } } -void GraphView::setGraphColor(QCPGraph* _pGraph, const QColor &color) +void GraphView::setGraphColor(QCPGraph* _pGraph, const QColor& color) { QPen pen; pen.setColor(color); @@ -697,7 +690,7 @@ void GraphView::setGraphColor(QCPGraph* _pGraph, const QColor &color) _pGraph->selectionDecorator()->setPen(pen); } -void GraphView::setGraphAxis(QCPGraph* _pGraph, const GraphData::valueAxis_t &axis) +void GraphView::setGraphAxis(QCPGraph* _pGraph, const GraphData::valueAxis_t& axis) { if (axis == GraphData::VALUE_AXIS_SECONDARY) { @@ -717,7 +710,7 @@ double GraphView::getClosestPoint(double coordinate) QCPGraphDataContainer::const_iterator leftIt = _pPlot->graph(0)->data()->findBegin(coordinate); auto rightIt = leftIt + 1; - if (rightIt != _pPlot->graph(0)->data()->constEnd()) + if (rightIt != _pPlot->graph(0)->data()->constEnd()) { const double diffReference = rightIt->key - leftIt->key; @@ -763,7 +756,7 @@ void GraphView::updateSecondaryAxisVisibility() rescalePlot(); } -qint32 GraphView::getActiveGraphIndex(QCPGraph const * const pGraph) +qint32 GraphView::getActiveGraphIndex(QCPGraph const* const pGraph) { qint32 idx = -1; for (int i = 0; i < _pPlot->graphCount(); ++i) diff --git a/src/importexport/datafileexporter.cpp b/src/importexport/datafileexporter.cpp old mode 100755 new mode 100644 index f8f02e24..cc36556c --- a/src/importexport/datafileexporter.cpp +++ b/src/importexport/datafileexporter.cpp @@ -10,8 +10,11 @@ using connectionId_t = ConnectionTypes::connectionId_t; -DataFileExporter::DataFileExporter(SettingsModel * pSettingsModel, GraphDataModel * pGraphDataModel, NoteModel *pNoteModel, QObject *parent) : - QObject(parent) +DataFileExporter::DataFileExporter(SettingsModel* pSettingsModel, + GraphDataModel* pGraphDataModel, + NoteModel* pNoteModel, + QObject* parent) + : QObject(parent) { _pSettingsModel = pSettingsModel; _pGraphDataModel = pGraphDataModel; @@ -22,7 +25,6 @@ DataFileExporter::DataFileExporter(SettingsModel * pSettingsModel, GraphDataMode DataFileExporter::~DataFileExporter() { - } void DataFileExporter::enableExporterDuringLog() @@ -41,7 +43,7 @@ void DataFileExporter::disableExporterDuringLog() flushExportBuffer(); } -void DataFileExporter::exportDataLine(double timeData, QList dataValues) +void DataFileExporter::exportDataLine(double timeData, QList dataValues) { /* QList correspond with activeGraphList */ @@ -91,7 +93,7 @@ void DataFileExporter::exportDataFile(QString dataFile) _pGraphDataModel->activeGraphIndexList(&activeGraphIndexes); QList dataListIterators; - for(qint32 idx = 0; idx < activeGraphIndexes.size(); idx++) + for (qint32 idx = 0; idx < activeGraphIndexes.size(); idx++) { // Save iterators to data lists dataListIterators.append(_pGraphDataModel->dataMap(activeGraphIndexes[idx])->constBegin()); @@ -99,11 +101,11 @@ void DataFileExporter::exportDataFile(QString dataFile) // Add data lines const qint32 dataCount = _pGraphDataModel->dataMap(activeGraphIndexes[0])->size(); - for(qint32 i = 0; i < dataCount; i++) + for (qint32 i = 0; i < dataCount; i++) { QList dataRowValues; double key = dataListIterators[0]->key; - for(qint32 d = 0; d < dataListIterators.size(); d++) + for (qint32 d = 0; d < dataListIterators.size(); d++) { dataRowValues.append(dataListIterators[d]->value); @@ -112,8 +114,7 @@ void DataFileExporter::exportDataFile(QString dataFile) logData.append(formatData(key, dataRowValues)); - - if ( i % _cLogChunkLineCount == 0) + if (i % _cLogChunkLineCount == 0) { bRet = writeToFile(dataFile, logData); @@ -156,7 +157,7 @@ bool DataFileExporter::updateNoteLines(QString dataFile) QString line; bool bPreviousLineWasEmptyComment = false; - while(!srcStream.atEnd()) + while (!srcStream.atEnd()) { line = srcStream.readLine().trimmed(); @@ -164,13 +165,9 @@ bool DataFileExporter::updateNoteLines(QString dataFile) { bool bEmptyCommentLine = line.length() == 2; - if (line.left(6).toLower() == "//note") - { - // Skip line - } - else if (bPreviousLineWasEmptyComment && bEmptyCommentLine) + if (line.left(6).toLower() == "//note" || (bPreviousLineWasEmptyComment && bEmptyCommentLine)) { - // We want to avoid 2 subsequent comment lines, so skip + // Skip note lines and avoid 2 subsequent empty comment lines } else { @@ -192,7 +189,7 @@ bool DataFileExporter::updateNoteLines(QString dataFile) createNoteRows(noteRows); if (!noteRows.isEmpty()) { - for(const QString ¬eRow: std::as_const(noteRows)) + for (const QString& noteRow : std::as_const(noteRows)) { tmpStream << noteRow << "\n"; } @@ -204,7 +201,7 @@ bool DataFileExporter::updateNoteLines(QString dataFile) tmpStream << line << "\n"; // Copy rest of the file - while(!srcStream.atEnd()) + while (!srcStream.atEnd()) { tmpStream << srcStream.readLine() << "\n"; } @@ -213,7 +210,6 @@ bool DataFileExporter::updateNoteLines(QString dataFile) { bSuccess = false; } - } else { @@ -314,7 +310,8 @@ TODO: dev } } - header.append(comment + "Poll interval" + Util::separatorCharacter() + QString::number(_pSettingsModel->pollTime())); + header.append(comment + "Poll interval" + Util::separatorCharacter() + + QString::number(_pSettingsModel->pollTime())); quint32 success = _pGraphDataModel->communicationSuccessCount(); quint32 error = _pGraphDataModel->communicationErrorCount(); @@ -403,7 +400,7 @@ QString DataFileExporter::createPropertyRow(registerProperty prop) { QString line; - switch(prop) + switch (prop) { case E_LABEL: line.append("Time (ms)"); @@ -428,12 +425,12 @@ QString DataFileExporter::createPropertyRow(registerProperty prop) break; } - for(qint32 i = 0; i < _pGraphDataModel->activeCount(); i++) + for (qint32 i = 0; i < _pGraphDataModel->activeCount(); i++) { const qint32 graphIdx = _pGraphDataModel->convertToGraphIndex(i); QString propertyString; - switch(prop) + switch (prop) { case E_LABEL: case E_PROPERTY: @@ -449,15 +446,14 @@ QString DataFileExporter::createPropertyRow(registerProperty prop) break; case E_VALUE_AXIS: - { - qint32 axis = _pGraphDataModel->valueAxis(graphIdx) == GraphData::VALUE_AXIS_PRIMARY ? 0 : 1; - propertyString = QString("%1").arg(axis); - } - break; + { + qint32 axis = _pGraphDataModel->valueAxis(graphIdx) == GraphData::VALUE_AXIS_PRIMARY ? 0 : 1; + propertyString = QString("%1").arg(axis); + } + break; default: break; - } // Get headers @@ -485,7 +481,7 @@ QString DataFileExporter::formatData(double timeData, QList dataValues) } // Add formatted data (maximum 3 decimals, no trailing zeros) - for(qint32 d = 0; d < dataValues.size(); d++) + for (qint32 d = 0; d < dataValues.size(); d++) { line.append(Util::separatorCharacter() + Util::formatDoubleForExport(dataValues[d])); } @@ -501,7 +497,7 @@ bool DataFileExporter::writeToFile(QString filePath, QStringList logData) { QTextStream stream(&file); - foreach(QString line, logData) + foreach (QString line, logData) { stream << line << "\n"; } @@ -510,10 +506,7 @@ bool DataFileExporter::writeToFile(QString filePath, QStringList logData) } else { - if ( - (_pSettingsModel->writeDuringLogFile() == filePath) - && (_pSettingsModel->writeDuringLog()) - ) + if ((_pSettingsModel->writeDuringLogFile() == filePath) && (_pSettingsModel->writeDuringLog())) { // Disable logging to file on write error _pSettingsModel->setWriteDuringLog(false); @@ -528,8 +521,5 @@ bool DataFileExporter::writeToFile(QString filePath, QStringList logData) void DataFileExporter::clearFile(QString filePath) { QFile file(filePath); - (void)file.open(QIODevice::WriteOnly | QIODevice::Text); // Remove all data from file + (void) file.open(QIODevice::WriteOnly | QIODevice::Text); // Remove all data from file } - - - diff --git a/src/importexport/settingsauto.cpp b/src/importexport/settingsauto.cpp index 4cf32e8b..01691bbf 100644 --- a/src/importexport/settingsauto.cpp +++ b/src/importexport/settingsauto.cpp @@ -17,7 +17,7 @@ SettingsAuto::SettingsAuto() _absoluteDateRegex.optimize(); } -bool SettingsAuto::updateSettings(QTextStream* pDataFileStream, settingsData_t *pSettingsData, qint32 sampleLength) +bool SettingsAuto::updateSettings(QTextStream* pDataFileStream, settingsData_t* pSettingsData, qint32 sampleLength) { bool bRet = true; @@ -152,10 +152,7 @@ bool SettingsAuto::determineComment(QString line) else { // Check second character - if ( - (!line.at(1).isLetterOrNumber()) - && (!line.at(1).isSpace()) - ) + if ((!line.at(1).isLetterOrNumber()) && (!line.at(1).isSpace())) { _commentSequence = line.left(2); bRet = true; @@ -185,10 +182,7 @@ bool SettingsAuto::testLocale(QStringList previewData, QLocale locale, QString f aSeparatorCount[0] = previewData[_labelRow].count(fieldSeparator); aSeparatorCount[1] = previewData[_dataRow].count(fieldSeparator); - if ( - (aSeparatorCount[0] == aSeparatorCount[1]) - && (aSeparatorCount[0] > 0) - ) + if ((aSeparatorCount[0] == aSeparatorCount[1]) && (aSeparatorCount[0] > 0)) { qint32 parseIdx; for (parseIdx = _dataRow; parseIdx < previewData.size(); parseIdx++) @@ -226,10 +220,7 @@ bool SettingsAuto::testLocale(QStringList previewData, QLocale locale, QString f // If first time field is between 0 and 1, then presume in seconds /* Check second data row to avoid 0 */ QString firstTimeField = previewData[_dataRow + 1].split(fieldSeparator)[0]; - if ( - (locale.toDouble(firstTimeField) > 0) - && (locale.toDouble(firstTimeField) < 1) - ) + if ((locale.toDouble(firstTimeField) > 0) && (locale.toDouble(firstTimeField) < 1)) { _bTimeInMilliSeconds = false; } @@ -242,14 +233,11 @@ bool SettingsAuto::testLocale(QStringList previewData, QLocale locale, QString f _decimalSeparator = QString(locale.decimalPoint()); // In US locale field separator is the same as group (thousands) point - if (fieldSeparator == QString(locale.groupSeparator())) - { - _groupSeparator = ' '; - } - else if ( - (QString(locale.groupSeparator()) == QString(QChar(0xA0))) // no-break space - || (QString(locale.groupSeparator()) == QString(QChar(0x202F))) //narrow no-break space - ) + // Also replace non-breaking spaces with regular space + if (fieldSeparator == QString(locale.groupSeparator()) || + QString(locale.groupSeparator()) == QString(QChar(0xA0)) // no-break space + || QString(locale.groupSeparator()) == QString(QChar(0x202F)) // narrow no-break space + ) { _groupSeparator = ' '; } @@ -261,7 +249,7 @@ bool SettingsAuto::testLocale(QStringList previewData, QLocale locale, QString f return true; } -quint32 SettingsAuto::nextDataLine(quint32 startIdx, QStringList previewData, bool *bOk) +quint32 SettingsAuto::nextDataLine(quint32 startIdx, QStringList previewData, bool* bOk) { qint32 lineIdx; for (lineIdx = startIdx; lineIdx < previewData.size(); lineIdx++) @@ -285,7 +273,6 @@ quint32 SettingsAuto::nextDataLine(quint32 startIdx, QStringList previewData, bo return lineIdx; } - void SettingsAuto::loadDataFileSample(QTextStream* pDataStream, QStringList& dataFileSample, qint32 sampleLength) { QString lineData; @@ -313,7 +300,6 @@ void SettingsAuto::loadDataFileSample(QTextStream* pDataStream, QStringList& dat { dataFileSample.append(lineData); } - } else { @@ -321,7 +307,7 @@ void SettingsAuto::loadDataFileSample(QTextStream* pDataStream, QStringList& dat break; } - } while(bRet && (dataFileSample.size() < sampleLength)); + } while (bRet && (dataFileSample.size() < sampleLength)); /* Set cursor back to beginning */ pDataStream->seek(0); diff --git a/src/models/mbcregisterfilter.cpp b/src/models/mbcregisterfilter.cpp index 98f8c548..957ece74 100644 --- a/src/models/mbcregisterfilter.cpp +++ b/src/models/mbcregisterfilter.cpp @@ -10,7 +10,7 @@ MbcRegisterFilter::MbcRegisterFilter(QObject* parent) : QSortFilterProxyModel(pa _textFilter.clear(); } -bool MbcRegisterFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +bool MbcRegisterFilter::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { if (source_row < sourceModel()->rowCount()) { @@ -42,7 +42,7 @@ void MbcRegisterFilter::setTextFilter(QString filterText) invalidateFilter(); } -bool MbcRegisterFilter::performTabFilter(int source_row, const QModelIndex &source_parent) const +bool MbcRegisterFilter::performTabFilter(int source_row, const QModelIndex& source_parent) const { QModelIndex tabIdx = sourceModel()->index(source_row, MbcRegisterModel::cColumnTab, source_parent); QString tabName = tabIdx.data().toString(); @@ -50,23 +50,12 @@ bool MbcRegisterFilter::performTabFilter(int source_row, const QModelIndex &sour bool bAllowed = true; /* Filter on tab */ - if (_tab == cTabNoFilter) - { - bAllowed = true; - } - else if (tabName == _tab) - { - bAllowed = true; - } - else - { - bAllowed = false; - } + bAllowed = (_tab == cTabNoFilter || tabName == _tab); return bAllowed; } -bool MbcRegisterFilter::performTextFilter(int source_row, const QModelIndex &source_parent) const +bool MbcRegisterFilter::performTextFilter(int source_row, const QModelIndex& source_parent) const { bool bAllowed = true; @@ -77,11 +66,8 @@ bool MbcRegisterFilter::performTextFilter(int source_row, const QModelIndex &sou QString strAddress = addressIdx.data().toString(); /* Filter on text */ - if ( - (!_textFilter.isEmpty()) - && (!description.contains(_textFilter, Qt::CaseInsensitive)) - && (!strAddress.contains(_textFilter, Qt::CaseInsensitive)) - ) + if ((!_textFilter.isEmpty()) && (!description.contains(_textFilter, Qt::CaseInsensitive)) && + (!strAddress.contains(_textFilter, Qt::CaseInsensitive))) { bAllowed = false; } diff --git a/src/util/fileselectionhelper.cpp b/src/util/fileselectionhelper.cpp index 767a0e73..0a7f5d0a 100644 --- a/src/util/fileselectionhelper.cpp +++ b/src/util/fileselectionhelper.cpp @@ -7,9 +7,8 @@ GuiModel* FileSelectionHelper::_pGuiModel; -FileSelectionHelper::FileSelectionHelper(QObject *parent) : QObject(parent) +FileSelectionHelper::FileSelectionHelper(QObject* parent) : QObject(parent) { - } void FileSelectionHelper::configureFileDialog(QFileDialog* pDialog, DialogType dialogType, FileType fileType) @@ -102,8 +101,6 @@ void FileSelectionHelper::configureFileType(QFileDialog* pDialog, FileType fileT break; case FILE_TYPE_NONE: - break; - default: break; } From bfea8cec15712a6a737ffea5c36c7d53cbfaa087 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Thu, 19 Mar 2026 17:23:23 +0100 Subject: [PATCH 13/16] fix: resolve clang-analyzer-optin.performance.Padding violation Reorder fields in _ConnectionSettings struct to minimize padding. Group large/aligned types (QString, quint32, quint16) before bool flags, reducing padding from 42 bytes to 2 bytes optimal. Co-Authored-By: Claude Sonnet 4.6 --- src/importexport/projectfiledata.h | 215 ++++++++++++++--------------- 1 file changed, 103 insertions(+), 112 deletions(-) diff --git a/src/importexport/projectfiledata.h b/src/importexport/projectfiledata.h index ea22a44f..03f2cd74 100644 --- a/src/importexport/projectfiledata.h +++ b/src/importexport/projectfiledata.h @@ -6,144 +6,135 @@ #include #include -namespace ProjectFileData +namespace ProjectFileData { +typedef struct _RegisterSettings { - typedef struct _RegisterSettings - { - QString text = QString(""); - bool bActive = false; - ConnectionTypes::connectionId_t connectionId = 0; + QString text = QString(""); + bool bActive = false; + ConnectionTypes::connectionId_t connectionId = 0; - QString expression = QString("0"); + QString expression = QString("0"); - bool bColor = false; - QColor color; + bool bColor = false; + QColor color; - quint32 valueAxis = 0; + quint32 valueAxis = 0; - } RegisterSettings; +} RegisterSettings; - typedef struct - { - QList registerList; - } ScopeSettings; - - typedef struct _XAxisSettings - { - bool bSliding = false; - quint32 slidingInterval = 60; - - } XAxisSettings; - - typedef struct _YAxisSettings - { - bool bWindowScale = false; - - bool bMinMax = false; - double scaleMin = 0; - double scaleMax = 10; - } YAxisSettings; - - typedef struct _ScaleSettings - { - XAxisSettings xAxis; - YAxisSettings yAxis; - YAxisSettings y2Axis; - } ScaleSettings; - - typedef struct - { - ScaleSettings scaleSettings; - - } ViewSettings; - - typedef struct _LogSettings - { - bool bPollTime = false; - quint32 pollTime; - - bool bAbsoluteTimes = false; - - bool bLogToFile = true; - bool bLogToFileFile = false; - QString logFile; - - } LogSettings; - - typedef struct _ConnectionSettings - { - bool bConnectionId = false; - ConnectionTypes::connectionId_t connectionId = 0; - - bool bConnectionState = true; +typedef struct +{ + QList registerList; +} ScopeSettings; - bool bConnectionType = false; - QString connectionType; +typedef struct _XAxisSettings +{ + bool bSliding = false; + quint32 slidingInterval = 60; - bool bIp = false; - QString ip; +} XAxisSettings; - bool bPort = false; - quint16 port; +typedef struct _YAxisSettings +{ + bool bWindowScale = false; - bool bPortName = false; - QString portName; + bool bMinMax = false; + double scaleMin = 0; + double scaleMax = 10; +} YAxisSettings; - bool bBaudrate = false; - quint32 baudrate; +typedef struct _ScaleSettings +{ + XAxisSettings xAxis; + YAxisSettings yAxis; + YAxisSettings y2Axis; +} ScaleSettings; - bool bParity = false; - quint32 parity = 0; +typedef struct +{ + ScaleSettings scaleSettings; - bool bStopbits = false; - quint32 stopbits; +} ViewSettings; - bool bDatabits = false; - quint32 databits; +typedef struct _LogSettings +{ + bool bPollTime = false; + quint32 pollTime; - bool bTimeout = false; - quint32 timeout; + bool bAbsoluteTimes = false; - bool bPersistentConnection = true; + bool bLogToFile = true; + bool bLogToFileFile = false; + QString logFile; - } ConnectionSettings; +} LogSettings; - typedef struct _DeviceSettings - { - bool bDeviceId = false; - deviceId_t deviceId = Device::cFirstDeviceId; +typedef struct _ConnectionSettings +{ + /* Large/aligned types first to minimize padding */ + QString connectionType; + QString ip; + QString portName; + + ConnectionTypes::connectionId_t connectionId = 0; + quint32 baudrate; + quint32 parity = 0; + quint32 stopbits; + quint32 databits; + quint32 timeout; + + quint16 port; + + bool bConnectionId = false; + bool bConnectionState = true; + bool bConnectionType = false; + bool bIp = false; + bool bPort = false; + bool bPortName = false; + bool bBaudrate = false; + bool bParity = false; + bool bStopbits = false; + bool bDatabits = false; + bool bTimeout = false; + bool bPersistentConnection = true; + +} ConnectionSettings; + +typedef struct _DeviceSettings +{ + bool bDeviceId = false; + deviceId_t deviceId = Device::cFirstDeviceId; - bool bName = false; - QString name = QString(""); + bool bName = false; + QString name = QString(""); - bool bConnectionId = false; - ConnectionTypes::connectionId_t connectionId = 0; + bool bConnectionId = false; + ConnectionTypes::connectionId_t connectionId = 0; - bool bSlaveId = false; - quint8 slaveId; + bool bSlaveId = false; + quint8 slaveId; - bool bConsecutiveMax = false; - quint8 consecutiveMax; + bool bConsecutiveMax = false; + quint8 consecutiveMax; - bool bInt32LittleEndian = true; + bool bInt32LittleEndian = true; - } DeviceSettings; +} DeviceSettings; - typedef struct _GeneralSettings - { - QList connectionSettings; - QList deviceSettings; - LogSettings logSettings; +typedef struct _GeneralSettings +{ + QList connectionSettings; + QList deviceSettings; + LogSettings logSettings; - } GeneralSettings; +} GeneralSettings; - typedef struct - { - GeneralSettings general; - ScopeSettings scope; - ViewSettings view; - } ProjectSettings; -} +typedef struct +{ + GeneralSettings general; + ScopeSettings scope; + ViewSettings view; +} ProjectSettings; +} // namespace ProjectFileData #endif // PROJECTFILEDATA - From 3089d5318427779ce3636ab02a9546a87968e968 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Thu, 19 Mar 2026 19:28:45 +0100 Subject: [PATCH 14/16] Quality fixes --- src/graphview/graphview.cpp | 4 +++- src/importexport/datafileexporter.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/graphview/graphview.cpp b/src/graphview/graphview.cpp index bb03d7af..3529300e 100644 --- a/src/graphview/graphview.cpp +++ b/src/graphview/graphview.cpp @@ -365,7 +365,9 @@ void GraphView::addData(QList timeData, QList > data) for (qint32 i = 0; i < _pPlot->graphCount(); i++) { - _pPlot->graph(i)->pen().setWidth(1); + QPen pen = _pPlot->graph(i)->pen(); + pen.setWidth(1); + _pPlot->graph(i)->setPen(pen); } _pPlot->setNotAntialiasedElements(QCP::aeAll); diff --git a/src/importexport/datafileexporter.cpp b/src/importexport/datafileexporter.cpp index cc36556c..88d456fb 100644 --- a/src/importexport/datafileexporter.cpp +++ b/src/importexport/datafileexporter.cpp @@ -420,7 +420,7 @@ QString DataFileExporter::createPropertyRow(registerProperty prop) case E_VALUE_AXIS: line.append("Axis"); - + break; default: break; } From 2774b1650d6cffc557de11eb6ae8892cebca1b64 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Thu, 19 Mar 2026 19:36:05 +0100 Subject: [PATCH 15/16] Disable coverage --- .github/workflows/code_quality.yml | 54 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index 804c07fc..75d96197 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -10,38 +10,38 @@ on: - master jobs: - coverage: - runs-on: ubuntu-latest - container: docker://jgeudens/qt-linux:6.8.3_build_1 - steps: - - name: Checkout - uses: actions/checkout@v6.0.0 + # coverage: + # runs-on: ubuntu-latest + # container: docker://jgeudens/qt-linux:6.8.3_build_1 + # steps: + # - name: Checkout + # uses: actions/checkout@v6.0.0 - - name: Start display server - run: bash /start.sh & + # - name: Start display server + # run: bash /start.sh & - - name: configure safe directory for git - run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" + # - name: configure safe directory for git + # run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" - - name: Prepare environment for Ninja build with coverage - run: | - cmake . -GNinja -DUSE_GCOV=ON - ninja + # - name: Prepare environment for Ninja build with coverage + # run: | + # cmake . -GNinja -DUSE_GCOV=ON + # ninja - - name: Generate gcovr coverage report - run: | - ctest - gcovr --gcov-ignore-parse-errors --cobertura cobertura.xml + # - name: Generate gcovr coverage report + # run: | + # ctest + # gcovr --gcov-ignore-parse-errors --cobertura cobertura.xml - - name: Run codacy-coverage-reporter - uses: codacy/codacy-coverage-reporter-action@v1 - with: - api-token: ${{ secrets.CODACY_PROJECT_TOKEN }} - language: 'CPP' - coverage-reports: cobertura.xml - env: - PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} - if: ${{ !!env.PROJECT_TOKEN }} + # - name: Run codacy-coverage-reporter + # uses: codacy/codacy-coverage-reporter-action@v1 + # with: + # api-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + # language: 'CPP' + # coverage-reports: cobertura.xml + # env: + # PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} + # if: ${{ !!env.PROJECT_TOKEN }} clazy: runs-on: ubuntu-latest From a9599153cb1d9fb59013e18eed6b16a8878f5be6 Mon Sep 17 00:00:00 2001 From: Jens Geudens Date: Thu, 19 Mar 2026 19:45:43 +0100 Subject: [PATCH 16/16] Make sure all autogen headers are created --- scripts/run_clazy.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/run_clazy.sh b/scripts/run_clazy.sh index 13197aae..84e80642 100755 --- a/scripts/run_clazy.sh +++ b/scripts/run_clazy.sh @@ -10,6 +10,9 @@ cmake -GNinja \ -DCMAKE_PREFIX_PATH="${QT_PREFIX}" \ -B "${BUILD_DIR}" +echo "=== Generating autogen headers ===" +ninja -C "${BUILD_DIR}" src/ScopeSource_autogen + echo "=== Running clazy ===" find "$(pwd)/src" -name "*.cpp" -print0 | \ xargs -0 -P "$(nproc)" -I{} clazy-standalone --only-qt --header-filter="src/.*" -p "${BUILD_DIR}" {}