diff --git a/.clang-tidy b/.clang-tidy index 8c30f2c602b..b83436861bd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -42,7 +42,9 @@ Checks: > -modernize-avoid-c-arrays, -modernize-deprecated-ios-base-aliases, -misc-include-cleaner, + -misc-multiple-inheritance, -misc-unused-using-decls, + -modernize-avoid-c-style-cast, -modernize-loop-convert, -modernize-macro-to-enum, -modernize-raw-string-literal, @@ -68,6 +70,7 @@ Checks: > -readability-identifier-length, -readability-identifier-naming, -readability-implicit-bool-conversion, + -readability-inconsistent-ifelse-braces, -readability-isolate-declaration, -readability-magic-numbers, -readability-redundant-parentheses, @@ -87,3 +90,5 @@ CheckOptions: value: false - key: misc-override-with-different-visibility.DisallowedVisibilityChange value: widening + - key: misc-use-internal-linkage.AnalyzeTypes + value: false diff --git a/.github/workflows/CI-cygwin.yml b/.github/workflows/CI-cygwin.yml index 445c0953eb5..bf67967c5f8 100644 --- a/.github/workflows/CI-cygwin.yml +++ b/.github/workflows/CI-cygwin.yml @@ -42,8 +42,9 @@ jobs: persist-credentials: false - name: Set up Cygwin - uses: cygwin/cygwin-install-action@master + uses: cygwin/cygwin-install-action@v6 with: + site: https://mirrors.cicku.me/cygwin/ platform: ${{ matrix.platform }} packages: ${{ matrix.packages }} diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml index 4df9b4e9340..a38feb452f0 100644 --- a/.github/workflows/CI-unixish-docker.yml +++ b/.github/workflows/CI-unixish-docker.yml @@ -20,11 +20,16 @@ jobs: strategy: matrix: - image: ["ubuntu:24.04"] include: - - build_gui: false - image: "ubuntu:24.04" - build_gui: true + with_gui: true + full_build: true + - image: "ubuntu:25.10" + with_gui: true + full_build: true + - image: "alpine:3.23" + with_gui: false # it appears FindQt6.cmake is not provided by any package + full_build: false # FIXME: test-signalhandler.cpp fails to build since feenableexcept() is missing fail-fast: false # Prefer quick result runs-on: ubuntu-22.04 @@ -49,10 +54,15 @@ jobs: apt-get install -y cmake g++ make libxml2-utils libpcre3-dev - name: Install missing software (gui) on latest ubuntu - if: matrix.build_gui + if: contains(matrix.image, 'ubuntu') run: | apt-get install -y qt6-base-dev qt6-charts-dev qt6-tools-dev + - name: Install missing software on Alpine + if: contains(matrix.image, 'alpine') + run: | + apk add cmake make g++ pcre-dev + # needs to be called after the package installation since # - it doesn't call "apt-get update" - name: ccache @@ -60,18 +70,13 @@ jobs: with: key: ${{ github.workflow }}-${{ matrix.image }} - - name: CMake build - if: ${{ !matrix.build_gui }} + - name: Run CMake run: | - mkdir cmake.output - cd cmake.output - cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache .. - cmake --build . -- -j$(nproc) + cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=${{ matrix.with_gui }} -DWITH_QCHART=On -DBUILD_TRIAGE=${{ matrix.with_gui }} -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - - name: CMake build (with GUI) - if: matrix.build_gui + - name: CMake build + if: matrix.full_build run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache cmake --build cmake.output -- -j$(nproc) - name: Run CMake test @@ -82,7 +87,7 @@ jobs: strategy: matrix: - image: ["ubuntu:24.04"] + image: ["ubuntu:24.04", "ubuntu:25.10", "alpine:3.23"] fail-fast: false # Prefer quick result runs-on: ubuntu-22.04 @@ -101,6 +106,11 @@ jobs: apt-get update apt-get install -y g++ make python3 libxml2-utils libpcre3-dev + - name: Install missing software on Alpine + if: contains(matrix.image, 'alpine') + run: | + apk add make g++ pcre-dev bash python3 libxml2-utils + # needs to be called after the package installation since # - it doesn't call "apt-get update" - name: ccache @@ -108,14 +118,16 @@ jobs: with: key: ${{ github.workflow }}-${{ matrix.image }} + # /usr/lib/ccache/bin - Alpine Linux + - name: Build cppcheck run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + export PATH="/usr/lib/ccache/bin:/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" make -j$(nproc) HAVE_RULES=yes CXXOPTS="-Werror" - name: Build test run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + export PATH="/usr/lib/ccache/bin:/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" make -j$(nproc) HAVE_RULES=yes CXXOPTS="-Werror" testrunner - name: Run test diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 14682a41a56..3251a6b5adb 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -58,13 +58,13 @@ jobs: - name: CMake build on ubuntu (with GUI / system tinyxml2) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output.tinyxml2 -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output.tinyxml2 -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache cmake --build cmake.output.tinyxml2 -- -j$(nproc) - name: CMake build on macos (with GUI / system tinyxml2) if: contains(matrix.os, 'macos') run: | - cmake -S . -B cmake.output.tinyxml2 -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 + cmake -S . -B cmake.output.tinyxml2 -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 cmake --build cmake.output.tinyxml2 -- -j$(nproc) - name: Run CMake test (system tinyxml2) @@ -127,12 +127,12 @@ jobs: - name: Run CMake on ubuntu (with GUI) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install + cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install - name: Run CMake on macos (with GUI) if: contains(matrix.os, 'macos') run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 + cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 - name: Run CMake build run: | @@ -154,13 +154,13 @@ jobs: - name: Run CMake on ubuntu (no CLI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli -G "Unix Makefiles" -DBUILD_CLI=Off + cmake -S . -B cmake.output_nocli -Werror=dev -DBUILD_TESTING=Off -DBUILD_CLI=Off - name: Run CMake on ubuntu (no CLI / with tests) if: matrix.os == 'ubuntu-22.04' run: | # the test and CLI code are too intertwined so for now we need to reject that - if cmake -S . -B cmake.output_nocli_tests -G "Unix Makefiles" -DBUILD_TESTS=On -DBUILD_CLI=Off; then + if cmake -S . -B cmake.output_nocli_tests -Werror=dev -DBUILD_TESTING=On -DBUILD_CLI=Off; then exit 1 else exit 0 @@ -169,18 +169,18 @@ jobs: - name: Run CMake on ubuntu (no CLI / with GUI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli_gui -G "Unix Makefiles" -DBUILD_CLI=Off -DBUILD_GUI=On + cmake -S . -B cmake.output_nocli_gui -Werror=dev -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=On - name: Run CMake on ubuntu (no GUI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nogui -G "Unix Makefiles" -DBUILD_GUI=Off + cmake -S . -B cmake.output_nogui -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off - name: Run CMake on ubuntu (no GUI / with triage) if: matrix.os == 'ubuntu-22.04' run: | # cannot build triage without GUI - if cmake -S . -B cmake.output_nogui_triage -G "Unix Makefiles" -DBUILD_GUI=Off -DBUILD_TRIAGE=On; then + if cmake -S . -B cmake.output_nogui_triage -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off -DBUILD_TRIAGE=On; then exit 1 else exit 0 @@ -189,7 +189,7 @@ jobs: - name: Run CMake on ubuntu (no CLI / no GUI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli_nogui -G "Unix Makefiles" -DBUILD_GUI=Off + cmake -S . -B cmake.output_nocli_nogui -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off build_cmake_cxxstd: @@ -243,12 +243,12 @@ jobs: - name: Run CMake on ubuntu (with GUI) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output -Werror=dev -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - name: Run CMake on macos (with GUI) if: contains(matrix.os, 'macos') run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 + cmake -S . -B cmake.output -Werror=dev -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 - name: Run CMake build run: | @@ -373,7 +373,7 @@ jobs: run: | # make sure we fail when Boost is requested and not available. # will fail because no package configuration is available. - if cmake -S . -B cmake.output.boost-force-noavail -G "Unix Makefiles" -DUSE_BOOST=On; then + if cmake -S . -B cmake.output.boost-force-noavail -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=On; then exit 1 else exit 0 @@ -386,12 +386,12 @@ jobs: - name: Run CMake on macOS (force Boost) run: | - cmake -S . -B cmake.output.boost-force -G "Unix Makefiles" -DUSE_BOOST=On + cmake -S . -B cmake.output.boost-force -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=On - name: Run CMake on macOS (no Boost) run: | # make sure Boost is not used when disabled even though it is available - cmake -S . -B cmake.output.boost-no -G "Unix Makefiles" -DUSE_BOOST=Off + cmake -S . -B cmake.output.boost-no -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=Off if grep -q '\-DHAVE_BOOST' ./cmake.output.boost-no/compile_commands.json; then exit 1 else @@ -400,13 +400,49 @@ jobs: - name: Run CMake on macOS (with Boost) run: | - cmake -S . -B cmake.output.boost -G "Unix Makefiles" -DBUILD_TESTS=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output.boost -Werror=dev -DBUILD_TESTING=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache grep -q '\-DHAVE_BOOST' ./cmake.output.boost/compile_commands.json - name: Build with CMake on macOS (with Boost) run: | cmake --build cmake.output.boost -- -j$(nproc) + build_cmake_minimum: # TODO: move to docker workflow? + + runs-on: ubuntu-22.04 # use the oldest available runner + + env: + CMAKE_VERSION: 3.22 + CMAKE_VERSION_FULL: 3.22.6 + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install missing software + run: | + sudo apt-get update + sudo apt-get install libxml2-utils + # qt6-tools-dev-tools for lprodump + # qt6-l10n-tools for lupdate + sudo apt-get install qt6-base-dev libqt6charts6-dev qt6-tools-dev qt6-tools-dev-tools qt6-l10n-tools libglx-dev libgl1-mesa-dev + + - name: Install CMake + run: | + wget https://cmake.org/files/v${{ env.CMAKE_VERSION }}/cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64.tar.gz + tar xf cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64.tar.gz + + - name: Run CMake (without GUI) + run: | + export PATH=cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64/bin:$PATH + cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On + + - name: Run CMake (with GUI) + run: | + export PATH=cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64/bin:$PATH + cmake -S . -B cmake.output.gui -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On + build: strategy: @@ -560,7 +596,7 @@ jobs: - name: Test Signalhandler run: | - cmake -S . -B build.cmake.signal -G "Unix Makefiles" -DBUILD_TESTS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On + cmake -S . -B build.cmake.signal -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On cmake --build build.cmake.signal --target test-signalhandler -- -j$(nproc) # TODO: how to run this without copying the file? cp build.cmake.signal/bin/test-s* . @@ -571,7 +607,7 @@ jobs: - name: Test Stacktrace if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B build.cmake.stack -G "Unix Makefiles" -DBUILD_TESTS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On + cmake -S . -B build.cmake.stack -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On cmake --build build.cmake.stack --target test-stacktrace -- -j$(nproc) # TODO: how to run this without copying the file? cp build.cmake.stack/bin/test-s* . @@ -643,6 +679,19 @@ jobs: test -z "$(nm processexecutor.o)" # TODO: test NO_* defines + - name: Test execinfo.h detection + run: | + make clean + make cli/stacktrace.o | grep HAVE_EXECINFO_H=1 + test -n "$(nm cli/stacktrace.o)" + + - name: Test testrunner inclusion/exclusion + run: | + ! ./testrunner -d TestUtils | grep -v TestUtils > /dev/null + ! ./testrunner -d TestUtils::trim | grep -v TestUtils::trim > /dev/null + ! ./testrunner -d -x TestUtils | grep TestUtils > /dev/null + ! ./testrunner -d -x TestUtils:trim | grep TestUtils:trim > /dev/null + - name: Show all ignored files if: false # TODO: currently lists all the contents of ignored folders - we only need what actually matched run: | @@ -685,7 +734,7 @@ jobs: - name: CMake run: | - cmake -S . -B cmake.output -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On + cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On - name: Generate dependencies run: | @@ -695,31 +744,4 @@ jobs: - name: Self check run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude,information --exception-handling --debug-warnings --check-level=exhaustive" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - gui_options="-DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt" - ec=0 - - # TODO: add --check-config - - # early exit - if [ $ec -eq 1 ]; then - exit $ec - fi - - # self check externals - ./cppcheck $selfcheck_options externals || ec=1 - # self check lib/cli - mkdir b1 - ./cppcheck $selfcheck_options $cppcheck_options --cppcheck-build-dir=b1 --addon=naming.json frontend || ec=1 - ./cppcheck $selfcheck_options $cppcheck_options --cppcheck-build-dir=b1 --addon=naming.json -Ifrontend cli || ec=1 - ./cppcheck $selfcheck_options $cppcheck_options --cppcheck-build-dir=b1 --addon=naming.json --enable=internal lib || ec=1 - # check gui with qt settings - mkdir b2 - ./cppcheck $selfcheck_options $cppcheck_options $gui_options --cppcheck-build-dir=b2 --addon=naming.json -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui || ec=1 - # self check test and tools - ./cppcheck $selfcheck_options $cppcheck_options -Ifrontend -Icli test/*.cpp || ec=1 - ./cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - # triage - ./cppcheck $selfcheck_options $cppcheck_options $gui_options -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage || ec=1 - exit $ec + ./selfcheck.sh diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index 2b08f18bbf5..71d72025cf9 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -53,7 +53,7 @@ jobs: run: | rem TODO: enable rules? rem specify Release build so matchcompiler is used - cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build -Werror=dev -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - name: Build GUI release run: | @@ -92,12 +92,54 @@ jobs: - name: Run CMake run: | - cmake -S . -B build.cxxstd -G "Visual Studio 17 2022" -A x64 -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build.cxxstd -Werror=dev -A x64 -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - name: Build run: | cmake --build build.cxxstd --config Debug || exit /b !errorlevel! + build_cmake_minimum: + + runs-on: windows-2022 # use the oldest available runner + + env: + CMAKE_VERSION: 3.22 + CMAKE_VERSION_FULL: 3.22.6 + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install CMake + run: | + curl -fsSL https://cmake.org/files/v${{ env.CMAKE_VERSION }}/cmake-${{ env.CMAKE_VERSION_FULL }}-windows-x86_64.zip -o cmake.zip || exit /b !errorlevel! + 7z x cmake.zip || exit /b !errorlevel! + + - name: Set up Visual Studio environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: 6.10.0 + modules: 'qtcharts' + setup-python: 'false' + cache: true + aqtversion: '==3.1.*' # TODO: remove when aqtinstall 3.2.2 is available + + - name: Run CMake (without GUI) + run: | + :: TODO: enable DHAVE_RULES? + cmake-${{ env.CMAKE_VERSION_FULL }}-windows-x86_64\bin\cmake.exe -S . -B cmake.output -A x64 -DHAVE_RULES=Off -DBUILD_TESTING=On + + - name: Run CMake (with GUI) + run: | + :: TODO: enable DHAVE_RULES? + cmake-${{ env.CMAKE_VERSION_FULL }}-windows-x86_64\bin\cmake.exe -S . -B cmake.output.gui -A x64 -DHAVE_RULES=Off -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On + build: strategy: matrix: @@ -177,7 +219,7 @@ jobs: - name: Run Debug test if: matrix.config == 'debug' - run: .\bin\debug\testrunner.exe || exit /b !errorlevel! + run: .\bin\debug\testrunner.exe -t || exit /b !errorlevel! - name: Build CLI release configuration using MSBuild if: matrix.config == 'release' @@ -230,7 +272,7 @@ jobs: - name: Test SEH wrapper if: matrix.config == 'release' run: | - cmake -S . -B build.cmake.seh -DBUILD_TESTS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build.cmake.seh -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! cmake --build build.cmake.seh --target test-sehwrapper || exit /b !errorlevel! :: TODO: how to run this without copying the file? copy build.cmake.seh\bin\Debug\test-sehwrapper.exe . || exit /b !errorlevel! diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml deleted file mode 100644 index 642dbfd151c..00000000000 --- a/.github/workflows/asan.yml +++ /dev/null @@ -1,158 +0,0 @@ -# Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions -# Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: address sanitizer - -on: - push: - branches: - - 'main' - - 'releases/**' - - '2.*' - tags: - - '2.*' - pull_request: - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-22.04 - - env: - QT_VERSION: 6.10.0 - ASAN_OPTIONS: detect_stack_use_after_return=1 - LSAN_OPTIONS: suppressions=lsan-suppr.txt:print_suppressions=0 - # TODO: figure out why there are cache misses with PCH enabled - CCACHE_SLOPPINESS: pch_defines,time_macros - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.14' - check-latest: true - - - name: Install missing software on ubuntu - run: | - sudo apt-get update - sudo apt-get install -y cmake make libpcre3-dev libboost-container-dev libxml2-utils - sudo apt-get install -y libcups2-dev # required for Qt6PrintSupport in CMake since Qt 6.7.3 - - - name: Install clang - run: | - sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14 - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 22 - - - name: Install Qt ${{ env.QT_VERSION }} - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - modules: 'qtcharts' - setup-python: 'false' - cache: true - - - name: Install missing Python packages - run: | - python3 -m pip install pip --upgrade - python3 -m pip install pytest - python3 -m pip install pytest-timeout - python3 -m pip install pytest-xdist - python3 -m pip install psutil - - - name: CMake - run: | - cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DANALYZE_ADDRESS=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - env: - CC: clang-22 - CXX: clang++-22 - - - name: Build cppcheck - run: | - cmake --build cmake.output --target cppcheck -- -j $(nproc) - - - name: Build test - run: | - cmake --build cmake.output --target testrunner -- -j $(nproc) - - - name: Build GUI tests - run: | - cmake --build cmake.output --target gui-tests -- -j $(nproc) - - - name: Run tests - run: ./cmake.output/bin/testrunner - - - name: Run cfg tests - run: | - cmake --build cmake.output --target checkcfg -- -j $(nproc) - - - name: Run CTest - run: | - cp lsan-suppr.txt cmake.output/bin - ctest --test-dir cmake.output --output-on-failure -j$(nproc) - - - name: Run test/cli - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - - - name: Run test/cli (-j2) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_J: 2 - - - name: Run test/cli (--clang) - if: false - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_CLANG: clang - - - name: Run test/cli (--cppcheck-build-dir) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_BUILDDIR: injected - - - name: Generate dependencies - if: false - run: | - # make sure auto-generated GUI files exist - make -C cmake.output autogen - make -C cmake.output gui-build-deps triage-build-ui-deps - - # TODO: this is currently way too slow (~60 minutes) to enable it - # TODO: only fail the step on sanitizer issues - since we use processes it will only fail the underlying process which will result in an cppcheckError - - name: Self check - if: false - run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude,information --exception-handling --debug-warnings --check-level=exhaustive" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - gui_options="-DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt" - gui_options="$gui_options --suppress=autoNoType:*/moc_*.cpp --suppress=symbolDatabaseWarning:*/moc_*.cpp" - ec=0 - ./cmake.output/bin/cppcheck $selfcheck_options externals || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json frontend || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json -Ifrontend cli || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json --enable=internal lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options $gui_options --addon=naming.json --suppress=constVariablePointer:*/moc_*.cpp -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli -Ifrontend test/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options $gui_options -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage || ec=1 - exit $ec diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 7b462c688f0..c54d47da4f1 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -10,7 +10,7 @@ permissions: jobs: Fuzzing: runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - name: Build Fuzzers id: build diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 5d7445f34b5..c4f8cc0cf6b 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -61,7 +61,7 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off -DWARNINGS_ARE_ERRORS=On + cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_COMPILE_WARNING_AS_ERROR=On env: CC: clang-22 CXX: clang++-22 diff --git a/.github/workflows/corpus.yml b/.github/workflows/corpus.yml new file mode 100644 index 00000000000..0c1aeda94de --- /dev/null +++ b/.github/workflows/corpus.yml @@ -0,0 +1,58 @@ +# Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions +# Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners +name: corpus + +on: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: + +permissions: + contents: read + +jobs: + corpus: + runs-on: ubuntu-22.04 + if: ${{ github.repository_owner == 'cppcheck-opensource' }} + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.workflow }}-${{ runner.os }} + + - name: Install missing software on ubuntu + run: | + sudo apt-get update + sudo apt-get install -y fdupes + + - name: build testrunner + run: | + store_dir=$(pwd)/store + mkdir $store_dir + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + make -j$(nproc) CXXOPTS="-Werror" CPPOPTS="-DSTORE_INPUT_DIR=\"\\\"$store_dir\\\"\"" testrunner + + - name: run testrunner + run: | + ./testrunner -q + + - name: de-duplicate files + run: | + set -x + ls -l ./store | wc -l + echo "removing duplicates" + fdupes -qdN ./store > /dev/null + ls -l ./store | wc -l + # print largest size + ls -l ./store | cut -d' ' -f5 | sort -u -n -r | head -n1 + + - uses: actions/upload-artifact@v4 + if: success() + with: + name: corpus + path: ./store diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 3c07b61d7c7..006160c7779 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -12,7 +12,7 @@ permissions: jobs: scan: runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/cppcheck-premium.yml b/.github/workflows/cppcheck-premium.yml index 5cb63ca4d5e..ed0f2a1bcd5 100644 --- a/.github/workflows/cppcheck-premium.yml +++ b/.github/workflows/cppcheck-premium.yml @@ -33,7 +33,7 @@ jobs: run: | premium_version=${{ inputs.premium_version }} if [ -z $premium_version ]; then - premium_version=25.8.3 + premium_version=26.3.0 #wget https://files.cppchecksolutions.com/devdrop/cppcheckpremium-$premium_version-amd64.tar.gz -O cppcheckpremium.tar.gz wget https://files.cppchecksolutions.com/$premium_version/ubuntu-24.04/cppcheckpremium-$premium_version-amd64.tar.gz -O cppcheckpremium.tar.gz else diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 772a0da320c..05d5643bdf7 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -15,25 +15,22 @@ jobs: strategy: matrix: - # "opensuse/tumbleweed:latest" / "fedora:latest" / "debian:unstable" / "archlinux:latest" + # "opensuse/tumbleweed:latest" / "fedora:rawhide" / "debian:unstable" / "archlinux:latest" include: - os: ubuntu-22.04 - image: "fedora:latest" + image: "fedora:rawhide" stdlib: libstdc++ - clang_inc: '-isystem/usr/lib/clang/20/include' - # TODO: disable because it currently fails with "error: tried including but didn't find libc++'s header." - #- os: ubuntu-22.04 - # image: "fedora:latest" - # stdlib: libc++ - # clang_inc: '-isystem/usr/lib/clang/20/include' - - os: macos-13 + - os: ubuntu-22.04 + image: "fedora:rawhide" + stdlib: libc++ + - os: macos-26 image: "" stdlib: libc++ # no libstdc++ on macOS mapping_file_opt: '-Xiwyu --mapping_file=$(realpath ./macos.imp)' fail-fast: false runs-on: ${{ matrix.os }} - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} container: image: ${{ matrix.image }} @@ -100,18 +97,21 @@ jobs: if: contains(matrix.os, 'macos') run: | brew install include-what-you-use pcre coreutils - ln -s iwyu_tool.py /usr/local/bin/iwyu_tool + # on Apple Silicon files are symlinked under /opt/homebrew/bin + ln -s /opt/homebrew/bin/iwyu_tool.py /usr/local/bin/iwyu_tool # Fails on OpenSUSE: # Warning: Failed to restore: Tar failed with error: Unable to locate executable file: tar. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable. # Also the shell is broken afterwards: # OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH: unknown + # + # On macos-26 we need to perform the Python setup because the default installation is managed externally managed - name: Install Qt ${{ env.QT_VERSION }} uses: jurplel/install-qt-action@v4 with: version: ${{ env.QT_VERSION }} modules: 'qtcharts' - setup-python: 'false' + setup-python: ${{ contains(matrix.os, 'macos') }} install-deps: false cache: true @@ -125,7 +125,7 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.stdlib == 'libc++' }} + cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.stdlib == 'libc++' }} env: CC: clang CXX: clang++ @@ -147,8 +147,7 @@ jobs: - name: iwyu_tool run: | - # TODO: remove -stdlib= - it should have been taken from the compilation database - iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments -stdlib=${{ matrix.stdlib }} ${{ matrix.mapping_file_opt }} ${{ matrix.clang_inc }} > iwyu.log + iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments ${{ matrix.mapping_file_opt }} ${{ matrix.clang_inc }} > iwyu.log # TODO: run with all configurations - name: test/cfg @@ -193,7 +192,7 @@ jobs: fail-fast: false runs-on: ubuntu-22.04 - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} env: QT_VERSION: 6.10.0 @@ -233,7 +232,7 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.use_libcxx }} + cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.use_libcxx }} env: CC: clang-22 CXX: clang++-22 diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 2836000acc5..bacf32c8eaf 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -22,9 +22,10 @@ jobs: build: runs-on: windows-2025 - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} env: + PYTHON_VERSION: 3.14 # see https://www.pcre.org/original/changelog.txt PCRE_VERSION: 8.45 QT_VERSION: 6.10.0 @@ -35,6 +36,12 @@ jobs: with: persist-credentials: false + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + check-latest: true + - name: Set up Visual Studio environment uses: ilammy/msvc-dev-cmd@v1 @@ -48,7 +55,7 @@ jobs: 7z x pcre-%PCRE_VERSION%.zip || exit /b !errorlevel! cd pcre-%PCRE_VERSION% || exit /b !errorlevel! git apply --ignore-space-change ..\externals\pcre.patch || exit /b !errorlevel! - cmake . -G "Visual Studio 17 2022" -A x64 -DPCRE_BUILD_PCRECPP=OFF -DPCRE_BUILD_PCREGREP=OFF -DPCRE_BUILD_TESTS=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake . -A x64 -DPCRE_BUILD_PCRECPP=OFF -DPCRE_BUILD_PCREGREP=OFF -DPCRE_BUILD_TESTS=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! msbuild -m PCRE.sln -p:Configuration=Release -p:Platform=x64 || exit /b !errorlevel! copy pcre.h ..\externals || exit /b !errorlevel! copy Release\pcre.lib ..\externals\pcre64.lib || exit /b !errorlevel! @@ -65,21 +72,20 @@ jobs: # available modules: https://github.com/miurahr/aqtinstall/blob/master/docs/getting_started.rst#installing-modules # available tools: https://github.com/miurahr/aqtinstall/blob/master/docs/getting_started.rst#installing-tools - - name: Install Qt ${{ env.QT_VERSION }} + - name: Install Qt uses: jurplel/install-qt-action@v4 with: version: ${{ env.QT_VERSION }} modules: 'qtcharts' setup-python: 'false' tools: 'tools_opensslv3_x64' - aqtversion: '==3.1.*' # TODO: remove when aqtinstall 3.2.2 is available # TODO: build with multiple threads - name: Build x64 release GUI run: | :: TODO: enable rules? :: specify Release build so matchcompiler is used - cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_ONLINE_HELP=On -DUSE_BOOST=ON -DBOOST_INCLUDEDIR=%GITHUB_WORKSPACE%\boost -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build -Werror=dev -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_ONLINE_HELP=On -DUSE_BOOST=ON -DBOOST_INCLUDEDIR=%GITHUB_WORKSPACE%\boost -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! cmake --build build --target cppcheck-gui --config Release || exit /b !errorlevel! # TODO: package PDBs diff --git a/.github/workflows/ubsan.yml b/.github/workflows/sanitizers.yml similarity index 63% rename from .github/workflows/ubsan.yml rename to .github/workflows/sanitizers.yml index ecfe0f05379..d7ff31939d0 100644 --- a/.github/workflows/ubsan.yml +++ b/.github/workflows/sanitizers.yml @@ -1,6 +1,6 @@ # Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions # Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: undefined behaviour sanitizers +name: sanitizers on: push: @@ -18,10 +18,33 @@ permissions: jobs: build: + strategy: + matrix: + include: + - sanitizer: 'asan' + cmake_opts: '-DANALYZE_ADDRESS=On' + run_ctest: true + inject_executor: 'process' + run_selfcheck: false # TODO: this is currently way too slow (~60 minutes) to enable it + - sanitizer: 'tsan' + cmake_opts: '-DANALYZE_THREAD=On' + run_ctest: false # TODO: test-filelist fails with data race in pthread_cond_destroy + inject_executor: 'thread' + run_selfcheck: false # TODO: disabled for now as it takes around 40 minutes to finish + selfcheck_opts: '--executor=thread --error-exitcode=0' # set --error-exitcode=0 so we only fail on sanitizer issues - since it uses threads for execution it will exit the whole process on the first issue + - sanitizer: 'ubsan' + cmake_opts: '-DANALYZE_UNDEFINED=On' + run_ctest: true + inject_executor: 'process' + run_selfcheck: true + fail-fast: false + runs-on: ubuntu-22.04 env: QT_VERSION: 6.10.0 + ASAN_OPTIONS: detect_stack_use_after_return=1 + TSAN_OPTIONS: halt_on_error=1 UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1:report_error_type=1 # TODO: figure out why there are cache misses with PCH enabled CCACHE_SLOPPINESS: pch_defines,time_macros @@ -34,7 +57,7 @@ jobs: - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} + key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Set up Python uses: actions/setup-python@v5 @@ -73,7 +96,7 @@ jobs: - name: CMake run: | - cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DANALYZE_UNDEFINED=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify ${{ matrix.cmake_opts }} -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache env: CC: clang-22 CXX: clang++-22 @@ -91,13 +114,14 @@ jobs: cmake --build cmake.output --target gui-tests -- -j $(nproc) - name: Run tests - run: ./cmake.output/bin/testrunner + run: ./cmake.output/bin/testrunner -t - name: Run cfg tests run: | cmake --build cmake.output --target checkcfg -- -j $(nproc) - name: Run CTest + if: matrix.run_ctest run: | ctest --test-dir cmake.output --output-on-failure -j$(nproc) @@ -105,6 +129,8 @@ jobs: run: | pwd=$(pwd) TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli + env: + TEST_CPPCHECK_INJECT_EXECUTOR: ${{ matrix.inject_executor }} - name: Run test/cli (-j2) run: | @@ -129,6 +155,7 @@ jobs: TEST_CPPCHECK_INJECT_BUILDDIR: injected - name: Generate dependencies + if: matrix.run_selfcheck run: | # make sure auto-generated GUI files exist make -C cmake.output autogen @@ -136,18 +163,6 @@ jobs: # TODO: only fail the step on sanitizer issues - since we use processes it will only fail the underlying process which will result in an cppcheckError - name: Self check + if: matrix.run_selfcheck run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude,information --exception-handling --debug-warnings --check-level=exhaustive" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - gui_options="-DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt" - gui_options="$gui_options --suppress=autoNoType:*/moc_*.cpp --suppress=symbolDatabaseWarning:*/moc_*.cpp" - ec=0 - ./cmake.output/bin/cppcheck $selfcheck_options externals || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json frontend || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json -Ifrontend cli || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json --enable=internal lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options $gui_options --addon=naming.json --suppress=constVariablePointer:*/moc_*.cpp -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli -Ifrontend test/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options $gui_options -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage || ec=1 - exit $ec + ./selfcheck_san.sh ./cmake.output ${{ matrix.selfcheck_opts }} diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 27cd1254dcb..cfd1107e92d 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -64,7 +64,7 @@ jobs: # unusedFunction - start - name: CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies run: | @@ -90,7 +90,7 @@ jobs: # unusedFunction notest - start - name: CMake (no test) run: | - cmake -S . -B cmake.output.notest -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_GUI=ON -DBUILD_TRIAGE=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_GUI=ON -DBUILD_TRIAGE=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test) run: | @@ -112,7 +112,7 @@ jobs: # unusedFunction notest nogui - start - name: CMake (no test / no gui) run: | - cmake -S . -B cmake.output.notest_nogui -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest_nogui -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test / no gui) run: | @@ -121,7 +121,7 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:196 --suppress=unusedFunction:lib/importproject.cpp:1530 --suppress=unusedFunction:lib/importproject.cpp:1554" + supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1665 --suppress=unusedFunction:lib/importproject.cpp:1689" ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs env: DISABLE_VALUEFLOW: 1 @@ -131,7 +131,7 @@ jobs: # unusedFunction notest nocli - start - name: CMake (no test / no cli) run: | - cmake -S . -B cmake.output.notest_nocli -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_CLI=Off -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest_nocli -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test / no cli) run: | @@ -154,7 +154,7 @@ jobs: # unusedFunction notest nocli nogui - start - name: CMake (no test / no cli / no gui) run: | - cmake -S . -B cmake.output.notest_nocli_nogui -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_CLI=Off -DBUILD_GUI=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest_nocli_nogui -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test / no cli / no gui) run: | @@ -172,12 +172,12 @@ jobs: - name: Fetch corpus run: | - wget https://github.com/danmar/cppcheck/archive/refs/tags/2.8.tar.gz + wget https://github.com/cppcheck-opensource/cppcheck/archive/refs/tags/2.8.tar.gz tar xvf 2.8.tar.gz - name: CMake (corpus / no test) run: | - cmake -S cppcheck-2.8 -B cmake.output.corpus -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_GUI=ON -DUSE_QT6=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + cmake -S cppcheck-2.8 -B cmake.output.corpus -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_GUI=ON -DUSE_QT6=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_POLICY_VERSION_MINIMUM=3.5 - name: Generate dependencies (corpus) run: | @@ -202,3 +202,16 @@ jobs: with: name: Callgrind Output path: ./callgrind.* + + - name: Self check (unusedFunction / corpus / no test / memcheck) + run: | + # TODO: fix -rp so the suppressions actually work + valgrind --error-limit=yes --leak-check=full --num-callers=50 --show-reachable=yes --track-origins=yes --gen-suppressions=all --log-fd=9 --error-exitcode=42 ./cppcheck --template=selfcheck --error-exitcode=0 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.corpus/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr 9>memcheck.log || (cat memcheck.log && false) + cat memcheck.log + env: + DISABLE_VALUEFLOW: 1 + + - uses: actions/upload-artifact@v4 + with: + name: Memcheck Output + path: ./memcheck.* diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml deleted file mode 100644 index cd1fad16751..00000000000 --- a/.github/workflows/tsan.yml +++ /dev/null @@ -1,160 +0,0 @@ -# Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions -# Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: thread sanitizer - -on: - push: - branches: - - 'main' - - 'releases/**' - - '2.*' - tags: - - '2.*' - pull_request: - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-22.04 - - env: - QT_VERSION: 6.10.0 - TSAN_OPTIONS: halt_on_error=1 - # TODO: figure out why there are cache misses with PCH enabled - CCACHE_SLOPPINESS: pch_defines,time_macros - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.14' - check-latest: true - - - name: Install missing software on ubuntu - run: | - sudo apt-get update - sudo apt-get install -y cmake make libpcre3-dev libboost-container-dev libxml2-utils - sudo apt-get install -y libcups2-dev # required for Qt6PrintSupport in CMake since Qt 6.7.3 - - - name: Install clang - run: | - sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14 - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 22 - - - name: Install Qt ${{ env.QT_VERSION }} - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - modules: 'qtcharts' - setup-python: 'false' - cache: true - - - name: Install missing Python packages - run: | - python3 -m pip install pip --upgrade - python3 -m pip install pytest - python3 -m pip install pytest-timeout - python3 -m pip install pytest-xdist - python3 -m pip install psutil - - - name: CMake - run: | - cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DANALYZE_THREAD=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=Off -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - env: - CC: clang-22 - CXX: clang++-22 - - - name: Build cppcheck - run: | - cmake --build cmake.output --target cppcheck -- -j $(nproc) - - - name: Build test - run: | - cmake --build cmake.output --target testrunner -- -j $(nproc) - - - name: Build GUI tests - run: | - cmake --build cmake.output --target gui-tests -- -j $(nproc) - - - name: Run tests - run: ./cmake.output/bin/testrunner - - - name: Run cfg tests - run: | - cmake --build cmake.output --target checkcfg -- -j $(nproc) - - - name: Run CTest - if: false # TODO: test-filelist fails with data race in pthread_cond_destroy - run: | - ctest --test-dir cmake.output --output-on-failure -j$(nproc) - - - name: Run test/cli - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_EXECUTOR: thread - - - name: Run test/cli (-j2) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_J: 2 - - - name: Run test/cli (--clang) - if: false - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_CLANG: clang - - - name: Run test/cli (--cppcheck-build-dir) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_BUILDDIR: injected - - - name: Generate dependencies - if: false - run: | - # make sure auto-generated GUI files exist - make -C cmake.output autogen - make -C cmake.output gui-build-deps triage-build-ui-deps - - # TODO: disabled for now as it takes around 40 minutes to finish - # set --error-exitcode=0 so we only fail on sanitizer issues - since it uses threads for execution it will exit the whole process on the first issue - - name: Self check - if: false - run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=0 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude,information --exception-handling --debug-warnings --check-level=exhaustive" - selfcheck_options="$selfcheck_options --executor=thread" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - gui_options="-DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt" - gui_options="$gui_options --suppress=autoNoType:*/moc_*.cpp --suppress=symbolDatabaseWarning:*/moc_*.cpp" - ec=0 - ./cmake.output/bin/cppcheck $selfcheck_options externals || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json frontend || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json -Ifrontend cli || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json --enable=internal lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options $gui_options --addon=naming.json --suppress=constVariablePointer:*/moc_*.cpp -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli -Ifrontend test/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options $gui_options -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage || ec=1 - exit $ec diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 9a6026aa25b..3e4a02dbb48 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -51,7 +51,13 @@ jobs: - name: Run valgrind run: | ec=0 - valgrind --error-limit=yes --leak-check=full --num-callers=50 --show-reachable=yes --track-origins=yes --suppressions=valgrind/testrunner.supp --gen-suppressions=all --log-fd=9 --error-exitcode=42 ./testrunner TestGarbage TestOther TestSimplifyTemplate 9>memcheck.log || ec=1 + # disabled all tests invoking processes because the child processes fail with still reachable memory. + # some of the TestProcessExecutor* tests are also extremely slow. + excluded_tests="TestProcessExecutorFS \ + TestProcessExecutorFiles \ + TestSuppressions::suppressionsSettingsProcessesFiles \ + TestSuppressions::suppressionsSettingsProcessesFS" + valgrind --error-limit=yes --leak-check=full --num-callers=50 --show-reachable=yes --track-origins=yes --suppressions=valgrind/testrunner.supp --gen-suppressions=all -s --log-fd=9 --error-exitcode=42 ./testrunner -t -x $excluded_tests 9>memcheck.log || ec=1 cat memcheck.log exit $ec # TODO: debuginfod.ubuntu.com is currently not responding to any requests causing it to run into a 40(!) minute timeout diff --git a/.selfcheck_suppressions b/.selfcheck_suppressions index 7728225cd44..1687753c268 100644 --- a/.selfcheck_suppressions +++ b/.selfcheck_suppressions @@ -1,18 +1,50 @@ missingIncludeSystem # should not be reported - see #13387 checkersReport -# false positive - see #14308 -nullPointerRedundantCheck:externals/simplecpp/simplecpp.cpp:3246 # warnings in Qt generated code we cannot fix +funcArgNamesDifferentUnnamed:*/moc_aboutdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_applicationdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_applicationlist.cpp funcArgNamesDifferent:*/moc_checkthread.cpp +funcArgNamesDifferentUnnamed:*/moc_checkthread.cpp +funcArgNamesDifferentUnnamed:*/moc_codeeditor.cpp funcArgNamesDifferent:*/moc_codeeditstylecontrols.cpp +funcArgNamesDifferentUnnamed:*/moc_codeeditstylecontrols.cpp +funcArgNamesDifferentUnnamed:*/moc_compliancereportdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_codeeditstyledialog.cpp +funcArgNamesDifferentUnnamed:*/moc_fileviewdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_helpdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_libraryaddfunctiondialog.cpp +funcArgNamesDifferentUnnamed:*/moc_librarydialog.cpp +funcArgNamesDifferentUnnamed:*/moc_libraryeditargdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_mainwindow.cpp +funcArgNamesDifferentUnnamed:*/moc_newsuppressiondialog.cpp +funcArgNamesDifferentUnnamed:*/moc_platforms.cpp +funcArgNamesDifferentUnnamed:*/moc_projectfile.cpp +funcArgNamesDifferentUnnamed:*/moc_projectfiledialog.cpp funcArgNamesDifferent:*/moc_resultstree.cpp +funcArgNamesDifferentUnnamed:*/moc_resultstree.cpp funcArgNamesDifferent:*/moc_resultsview.cpp +funcArgNamesDifferentUnnamed:*/moc_resultsview.cpp +funcArgNamesDifferentUnnamed:*/moc_scratchpad.cpp +funcArgNamesDifferentUnnamed:*/moc_settingsdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_statsdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_testcppchecklibrarydata.cpp +funcArgNamesDifferentUnnamed:*/moc_testfilelist.cpp +funcArgNamesDifferentUnnamed:*/moc_testprojectfile.cpp +funcArgNamesDifferentUnnamed:*/moc_testresultstree.cpp +funcArgNamesDifferentUnnamed:*/moc_testtranslationhandler.cpp +funcArgNamesDifferentUnnamed:*/moc_testxmlreportv2.cpp +funcArgNamesDifferentUnnamed:*/moc_threaddetails.cpp funcArgNamesDifferent:*/moc_threadhandler.cpp +funcArgNamesDifferentUnnamed:*/moc_threadhandler.cpp funcArgNamesDifferent:*/moc_threadresult.cpp +funcArgNamesDifferentUnnamed:*/moc_threadresult.cpp +funcArgNamesDifferentUnnamed:*/moc_translationhandler.cpp +funcArgNamesDifferentUnnamed:*/moc_txtreport.cpp naming-varname:*/gui/ui_*.h -functionStatic:*/ui_fileview.h +functionStatic:*/gui/ui_*.h # --debug-warnings suppressions valueFlowBailout @@ -39,6 +71,12 @@ invalidPrintfArgType_sint:externals/tinyxml2/tinyxml2.h naming-privateMemberVariable:externals/tinyxml2/tinyxml2.h functionStatic:externals/tinyxml2/tinyxml2.cpp funcArgNamesDifferent:externals/tinyxml2/tinyxml2.cpp +funcArgNamesDifferentUnnamed:externals/tinyxml2/tinyxml2.cpp +funcArgNamesDifferentUnnamed:externals/tinyxml2/tinyxml2.h nullPointerRedundantCheck:externals/tinyxml2/tinyxml2.cpp +knownConditionTrueFalse:externals/tinyxml2/tinyxml2.cpp useStlAlgorithm:externals/simplecpp/simplecpp.cpp +funcArgNamesDifferentUnnamed:externals/simplecpp/simplecpp.h missingMemberCopy:externals/simplecpp/simplecpp.h +shadowFunction:externals/simplecpp/simplecpp.cpp +shadowFunction:externals/simplecpp/simplecpp.h diff --git a/AUTHORS b/AUTHORS index be41c3c525c..04cff0891a9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -105,6 +105,7 @@ Debrard Sebastien Deepak Gupta Degen's Regens dencat +Devansh Varshney Diego de las Heras Dirk Jagdmann Dirk Mueller @@ -131,6 +132,7 @@ Felix Faber Felix Geyer Felix Passenberg Felix Wolff +Florian Mueller Florin Iucha flovent Francesc Elies @@ -139,6 +141,7 @@ Frank Winklmeier Frank Zingsheim Frederik Schwarzer fu7mu4 +Gaël Bonithon Galimov Albert Garrett Bodily Gary Leutheuser @@ -192,6 +195,7 @@ Jim Zhou jlguardi Joel Johnson Johan Bertrand +Johan Crone Johan Samuelson John Marshall John-Paul Ore @@ -251,6 +255,7 @@ Maarten van der Schrieck Maksim Derbasov Malcolm Parsons Marc-Antoine Perennou +Marcel Petrick Marcel Raad Marco Trevisan Marek Zmysłowski @@ -425,6 +430,7 @@ Vesa Pikki Ville-Pekka Vahteala Ville Skyttä Vincent Le Garrec +Vít Kučera Vladimir Petrigo Wang Haoyu Wang Yang diff --git a/CMakeLists.txt b/CMakeLists.txt index 3595154f7ae..3c037a10b36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 3.13) -project(Cppcheck VERSION 2.18.99 LANGUAGES CXX) +cmake_minimum_required(VERSION 3.22) +project(Cppcheck VERSION 2.20.99 LANGUAGES CXX) include(cmake/options.cmake) @@ -11,11 +11,13 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include(GNUInstallDirs) +include(CTest) include(cmake/compilerCheck.cmake) include(cmake/versions.cmake) include(cmake/findDependencies.cmake) include(cmake/compileroptions.cmake) +include(cmake/includechecks.cmake) include(cmake/compilerDefinitions.cmake) include(cmake/buildFiles.cmake) if(BUILD_GUI) @@ -77,10 +79,6 @@ endif() # - Cygwin handling # - MinGW handling -if(BUILD_TESTS) - enable_testing() -endif() - add_custom_target(copy_cfg ALL ${CMAKE_COMMAND} -E copy_directory "${PROJECT_SOURCE_DIR}/cfg" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/cfg" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 715a913b6fc..09e88f021e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ These are some guidelines *any* contributor should follow. They will help to mak ## Code Changes -Code contributions are handled via GitHub pull requests: https://github.com/danmar/cppcheck/pulls. +Code contributions are handled via GitHub pull requests: https://github.com/cppcheck-opensource/cppcheck/pulls. If you file a pull request you might not get a reply immediately. We are a very small team and it might not fit in the current scope or time. @@ -18,7 +18,7 @@ Also after you filed a pull request please be ready to reply to questions and fe Please do not be discouraged if your change was rejected or if the review process might not have been as smooth as it could have been. -Each change should be accompanied with a unit ([C++](https://github.com/danmar/cppcheck/tree/main/test)) or integration ([Python](https://github.com/danmar/cppcheck/tree/main/test/cli)) test to ensure that it doesn't regress with future changes. Negative tests (testing the opposite behavior) would be favorable but might not be required or might already exist depending on the change. Tests which introduce `TODO_ASSERT_` or `@pytest.mark.skip`/`@pytest.mark.xfail` should have tickets filed. +Each change should be accompanied with a unit ([C++](https://github.com/cppcheck-opensource/cppcheck/tree/main/test)) or integration ([Python](https://github.com/cppcheck-opensource/cppcheck/tree/main/test/cli)) test to ensure that it doesn't regress with future changes. Negative tests (testing the opposite behavior) would be favorable but might not be required or might already exist depending on the change. Tests which introduce `TODO_ASSERT_` or `@pytest.mark.skip`/`@pytest.mark.xfail` should have tickets filed. If the change is modifying existing behavior (i.e. adding a feature or fixing a bug) it should be accompanied by an issue in the [tracker](https://trac.cppcheck.net) (if you do not have access we can assist with that). Depending on the change it might also warrant an entry in `releasenotes.txt`. @@ -56,7 +56,7 @@ So if you start spending a lot of time on these, you might want to get into touc ## simplecpp -At its core Cppcheck is relying on the `simplecpp` library which is a preprocessor implementation which was spun off into its [separate project](https://github.com/danmar/simplecpp) with its own [bug tracker](https://github.com/danmar/simplecpp/issues). This is also maintained by the Cppcheck developers and contributions to it are also welcome. +At its core Cppcheck is relying on the `simplecpp` library which is a preprocessor implementation which was spun off into its [separate project](https://github.com/cppcheck-opensource/simplecpp) with its own [bug tracker](https://github.com/cppcheck-opensource/simplecpp/issues). This is also maintained by the Cppcheck developers and contributions to it are also welcome. ## Translations diff --git a/Makefile b/Makefile index 753348c618a..5a348e27001 100644 --- a/Makefile +++ b/Makefile @@ -155,6 +155,15 @@ else ifneq ($(HAVE_RULES),) $(error invalid HAVE_RULES value '$(HAVE_RULES)') endif +# older make versions do not support # in $(shell) and newer ones handle the escape sequence literally +REQUIRE_ESCAPE=$(shell echo "\#define DEF" | $(CXX) -c -xc - 2> /dev/null && echo "1" || echo "0") +ifeq ($(REQUIRE_ESCAPE),1) + HAVE_EXECINFO_H=$(shell echo "\#include " | $(CXX) -c -xc - 2> /dev/null && echo "1" || echo "0") +else + HAVE_EXECINFO_H=$(shell echo "#include " | $(CXX) -c -xc - 2> /dev/null && echo "1" || echo "0") +endif +override CPPFLAGS += -DHAVE_EXECINFO_H=$(HAVE_EXECINFO_H) + override CXXFLAGS += $(CXXOPTS) override CPPFLAGS += $(CPPOPTS) override LDFLAGS += $(LDOPTS) @@ -219,6 +228,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/checknullpointer.o \ $(libcppdir)/checkother.o \ $(libcppdir)/checkpostfixoperator.o \ + $(libcppdir)/checks.o \ $(libcppdir)/checksizeof.o \ $(libcppdir)/checkstl.o \ $(libcppdir)/checkstring.o \ @@ -294,6 +304,7 @@ TESTOBJ = test/fixture.o \ test/testbufferoverrun.o \ test/testcharvar.o \ test/testcheck.o \ + test/testcheckersreport.o \ test/testclangimport.o \ test/testclass.o \ test/testcmdlineparser.o \ @@ -472,13 +483,13 @@ check-nonneg: ###### Build -$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkuninitvar.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkuninitvar.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/regex.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp -$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenize.cpp -$(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/symboldatabase.cpp $(libcppdir)/addoninfo.o: lib/addoninfo.cpp externals/picojson/picojson.h lib/addoninfo.h lib/config.h lib/json.h lib/path.h lib/standards.h lib/utils.h @@ -487,31 +498,31 @@ $(libcppdir)/addoninfo.o: lib/addoninfo.cpp externals/picojson/picojson.h lib/ad $(libcppdir)/analyzerinfo.o: lib/analyzerinfo.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp -$(libcppdir)/astutils.o: lib/astutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/config.h lib/errortypes.h lib/findtoken.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/astutils.o: lib/astutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/config.h lib/errortypes.h lib/findtoken.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/astutils.cpp -$(libcppdir)/check.o: lib/check.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/check.o: lib/check.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check.cpp -$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check64bit.cpp -$(libcppdir)/checkassert.o: lib/checkassert.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkassert.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkassert.o: lib/checkassert.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkassert.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkassert.cpp -$(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkautovariables.cpp -$(libcppdir)/checkbool.o: lib/checkbool.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbool.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkbool.o: lib/checkbool.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbool.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp -$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp -$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkclass.cpp -$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkother.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkother.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp $(libcppdir)/checkers.o: lib/checkers.cpp lib/checkers.h lib/config.h @@ -520,73 +531,76 @@ $(libcppdir)/checkers.o: lib/checkers.cpp lib/checkers.h lib/config.h $(libcppdir)/checkersidmapping.o: lib/checkersidmapping.cpp lib/checkers.h lib/config.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersidmapping.cpp -$(libcppdir)/checkersreport.o: lib/checkersreport.cpp lib/addoninfo.h lib/checkers.h lib/checkersreport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h +$(libcppdir)/checkersreport.o: lib/checkersreport.cpp lib/addoninfo.h lib/checkers.h lib/checkersreport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersreport.cpp -$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkexceptionsafety.cpp -$(libcppdir)/checkfunctions.o: lib/checkfunctions.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkfunctions.o: lib/checkfunctions.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkfunctions.cpp -$(libcppdir)/checkinternal.o: lib/checkinternal.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkinternal.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkinternal.o: lib/checkinternal.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkinternal.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkinternal.cpp -$(libcppdir)/checkio.o: lib/checkio.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkio.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkio.o: lib/checkio.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkio.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkio.cpp -$(libcppdir)/checkleakautovar.o: lib/checkleakautovar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkleakautovar.o: lib/checkleakautovar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkleakautovar.cpp -$(libcppdir)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkmemoryleak.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkmemoryleak.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkmemoryleak.cpp -$(libcppdir)/checknullpointer.o: lib/checknullpointer.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checknullpointer.o: lib/checknullpointer.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checknullpointer.cpp -$(libcppdir)/checkother.o: lib/checkother.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkother.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkother.o: lib/checkother.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkother.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkother.cpp -$(libcppdir)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkpostfixoperator.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkpostfixoperator.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkpostfixoperator.cpp -$(libcppdir)/checksizeof.o: lib/checksizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checksizeof.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checks.o: lib/checks.cpp lib/check.h lib/check64bit.h lib/checkassert.h lib/checkautovariables.h lib/checkbool.h lib/checkbufferoverrun.h lib/checkclass.h lib/checkcondition.h lib/checkexceptionsafety.h lib/checkfunctions.h lib/checkinternal.h lib/checkio.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/checkother.h lib/checkpostfixoperator.h lib/checks.h lib/checksizeof.h lib/checkstl.h lib/checkstring.h lib/checktype.h lib/checkuninitvar.h lib/checkunusedvar.h lib/checkvaarg.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/standards.h lib/vfvalue.h + $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checks.cpp + +$(libcppdir)/checksizeof.o: lib/checksizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checksizeof.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checksizeof.cpp -$(libcppdir)/checkstl.o: lib/checkstl.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/checkstl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathanalysis.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkstl.o: lib/checkstl.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/checkstl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathanalysis.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstl.cpp -$(libcppdir)/checkstring.o: lib/checkstring.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkstring.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkstring.o: lib/checkstring.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkstring.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp -$(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp -$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/checkuninitvar.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/checkuninitvar.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkuninitvar.cpp -$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/astutils.h lib/checkers.h lib/checkunusedfunctions.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/astutils.h lib/checkers.h lib/checkunusedfunctions.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedfunctions.cpp -$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkunusedvar.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkunusedvar.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedvar.cpp -$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp -$(libcppdir)/clangimport.o: lib/clangimport.cpp lib/addoninfo.h lib/checkers.h lib/clangimport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/clangimport.o: lib/clangimport.cpp lib/clangimport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/clangimport.cpp $(libcppdir)/color.o: lib/color.cpp lib/color.h lib/config.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/color.cpp -$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkunusedfunctions.h lib/clangimport.h lib/color.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h lib/vfvalue.h +$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checks.h lib/checkunusedfunctions.h lib/clangimport.h lib/color.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/cppcheck.cpp $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/utils.h @@ -595,13 +609,13 @@ $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/ $(libcppdir)/findtoken.o: lib/findtoken.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/findtoken.cpp -$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/forwardanalyzer.cpp -$(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h +$(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp -$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp $(libcppdir)/infer.o: lib/infer.cpp lib/calculate.h lib/config.h lib/errortypes.h lib/infer.h lib/mathlib.h lib/smallvector.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h @@ -625,328 +639,331 @@ $(libcppdir)/pathanalysis.o: lib/pathanalysis.cpp lib/astutils.h lib/config.h li $(libcppdir)/pathmatch.o: lib/pathmatch.cpp lib/config.h lib/path.h lib/pathmatch.h lib/standards.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/pathmatch.cpp -$(libcppdir)/platform.o: lib/platform.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/xml.h +$(libcppdir)/platform.o: lib/platform.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/platform.cpp -$(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +$(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/preprocessor.cpp -$(libcppdir)/programmemory.o: lib/programmemory.cpp lib/addoninfo.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/programmemory.o: lib/programmemory.cpp lib/addoninfo.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/programmemory.cpp $(libcppdir)/regex.o: lib/regex.cpp lib/config.h lib/regex.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/regex.cpp -$(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/reverseanalyzer.cpp -$(libcppdir)/sarifreport.o: lib/sarifreport.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h +$(libcppdir)/sarifreport.o: lib/sarifreport.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/sarifreport.cpp -$(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/utils.h lib/vfvalue.h +$(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/settings.cpp $(libcppdir)/standards.o: lib/standards.cpp externals/simplecpp/simplecpp.h lib/config.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/standards.cpp -$(libcppdir)/summaries.o: lib/summaries.cpp lib/addoninfo.h lib/analyzerinfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/summaries.o: lib/summaries.cpp lib/addoninfo.h lib/analyzerinfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp -$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp -$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp $(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/timer.cpp -$(libcppdir)/token.o: lib/token.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/token.o: lib/token.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/token.cpp -$(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenlist.cpp $(libcppdir)/utils.o: lib/utils.cpp lib/config.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/utils.cpp -$(libcppdir)/vf_analyzers.o: lib/vf_analyzers.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/vf_analyzers.o: lib/vf_analyzers.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_analyzers.cpp -$(libcppdir)/vf_common.o: lib/vf_common.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/vf_common.o: lib/vf_common.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_common.cpp -$(libcppdir)/vf_settokenvalue.o: lib/vf_settokenvalue.cpp lib/addoninfo.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/vf_settokenvalue.o: lib/vf_settokenvalue.cpp lib/addoninfo.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_settokenvalue.cpp $(libcppdir)/vfvalue.o: lib/vfvalue.cpp lib/config.h lib/errortypes.h lib/mathlib.h lib/smallvector.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vfvalue.cpp -frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h +frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_FE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ frontend/frontend.cpp -cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h lib/xml.h +cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cmdlineparser.cpp -cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/sarifreport.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutor.cpp -cli/executor.o: cli/executor.cpp cli/executor.h lib/addoninfo.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +cli/executor.o: cli/executor.cpp cli/executor.h lib/addoninfo.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/executor.cpp cli/filelister.o: cli/filelister.cpp cli/filelister.h lib/config.h lib/filesettings.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/filelister.cpp -cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/config.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h +cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/config.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/main.cpp -cli/processexecutor.o: cli/processexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/processexecutor.o: cli/processexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/processexecutor.cpp cli/sehwrapper.o: cli/sehwrapper.cpp cli/sehwrapper.h lib/config.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/sehwrapper.cpp -cli/signalhandler.o: cli/signalhandler.cpp cli/signalhandler.h cli/stacktrace.h lib/config.h lib/utils.h +cli/signalhandler.o: cli/signalhandler.cpp cli/signalhandler.h cli/stacktrace.h lib/config.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/signalhandler.cpp -cli/singleexecutor.o: cli/singleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h +cli/singleexecutor.o: cli/singleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/singleexecutor.cpp cli/stacktrace.o: cli/stacktrace.cpp cli/stacktrace.h lib/config.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/stacktrace.cpp -cli/threadexecutor.o: cli/threadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/threadexecutor.o: cli/threadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/threadexecutor.cpp -test/fixture.o: test/fixture.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h test/options.h test/redirect.h +test/fixture.o: test/fixture.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h test/options.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/fixture.cpp -test/helpers.o: test/helpers.cpp cli/filelister.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/helpers.h +test/helpers.o: test/helpers.cpp cli/filelister.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/helpers.cpp -test/main.o: test/main.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h +test/main.o: test/main.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/main.cpp -test/options.o: test/options.cpp test/options.h +test/options.o: test/options.cpp lib/config.h lib/timer.h test/options.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp -test/test64bit.o: test/test64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/test64bit.o: test/test64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/test64bit.cpp -test/testanalyzerinformation.o: test/testanalyzerinformation.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h +test/testanalyzerinformation.o: test/testanalyzerinformation.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testanalyzerinformation.cpp -test/testassert.o: test/testassert.cpp lib/addoninfo.h lib/check.h lib/checkassert.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testassert.o: test/testassert.cpp lib/addoninfo.h lib/check.h lib/checkassert.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testassert.cpp -test/testastutils.o: test/testastutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testastutils.o: test/testastutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testastutils.cpp -test/testautovariables.o: test/testautovariables.cpp lib/addoninfo.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testautovariables.o: test/testautovariables.cpp lib/addoninfo.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testautovariables.cpp -test/testbool.o: test/testbool.cpp lib/addoninfo.h lib/check.h lib/checkbool.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testbool.o: test/testbool.cpp lib/addoninfo.h lib/check.h lib/checkbool.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbool.cpp -test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/addoninfo.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/addoninfo.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbufferoverrun.cpp -test/testcharvar.o: test/testcharvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testcharvar.o: test/testcharvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcharvar.cpp -test/testcheck.o: test/testcheck.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testcheck.o: test/testcheck.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcheck.cpp -test/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/clangimport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testcheckersreport.o: test/testcheckersreport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h + $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcheckersreport.cpp + +test/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/clangimport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclangimport.cpp -test/testclass.o: test/testclass.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testclass.o: test/testclass.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp -test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp -test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcolor.cpp -test/testcondition.o: test/testcondition.cpp lib/addoninfo.h lib/check.h lib/checkcondition.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testcondition.o: test/testcondition.cpp lib/addoninfo.h lib/check.h lib/checkcondition.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcondition.cpp -test/testconstructors.o: test/testconstructors.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testconstructors.o: test/testconstructors.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testconstructors.cpp -test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcppcheck.cpp -test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h +test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testerrorlogger.cpp -test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testexceptionsafety.cpp -test/testexecutor.o: test/testexecutor.cpp cli/executor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testexecutor.o: test/testexecutor.cpp cli/executor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testexecutor.cpp -test/testfilelister.o: test/testfilelister.cpp cli/filelister.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfilelister.o: test/testfilelister.cpp cli/filelister.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfilelister.cpp -test/testfilesettings.o: test/testfilesettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfilesettings.o: test/testfilesettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfilesettings.cpp -test/testfrontend.o: test/testfrontend.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfrontend.o: test/testfrontend.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfrontend.cpp -test/testfunctions.o: test/testfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testfunctions.o: test/testfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfunctions.cpp -test/testgarbage.o: test/testgarbage.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testgarbage.o: test/testgarbage.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testgarbage.cpp -test/testimportproject.o: test/testimportproject.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h test/fixture.h test/redirect.h +test/testimportproject.o: test/testimportproject.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h test/fixture.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testimportproject.cpp -test/testincompletestatement.o: test/testincompletestatement.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testincompletestatement.o: test/testincompletestatement.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testincompletestatement.cpp -test/testinternal.o: test/testinternal.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkinternal.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testinternal.o: test/testinternal.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkinternal.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testinternal.cpp -test/testio.o: test/testio.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkio.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testio.o: test/testio.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkio.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testio.cpp -test/testleakautovar.o: test/testleakautovar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkleakautovar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testleakautovar.o: test/testleakautovar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkleakautovar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testleakautovar.cpp -test/testlibrary.o: test/testlibrary.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testlibrary.o: test/testlibrary.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testlibrary.cpp -test/testmathlib.o: test/testmathlib.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testmathlib.o: test/testmathlib.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testmathlib.cpp -test/testmemleak.o: test/testmemleak.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkmemoryleak.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testmemleak.o: test/testmemleak.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkmemoryleak.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testmemleak.cpp -test/testnullpointer.o: test/testnullpointer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testnullpointer.o: test/testnullpointer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testnullpointer.cpp -test/testoptions.o: test/testoptions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h +test/testoptions.o: test/testoptions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testoptions.cpp -test/testother.o: test/testother.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testother.o: test/testother.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testother.cpp -test/testpath.o: test/testpath.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testpath.o: test/testpath.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpath.cpp -test/testpathmatch.o: test/testpathmatch.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testpathmatch.o: test/testpathmatch.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpathmatch.cpp -test/testplatform.o: test/testplatform.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h +test/testplatform.o: test/testplatform.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testplatform.cpp -test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkpostfixoperator.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkpostfixoperator.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpostfixoperator.cpp -test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpreprocessor.cpp -test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprocessexecutor.cpp -test/testprogrammemory.o: test/testprogrammemory.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testprogrammemory.o: test/testprogrammemory.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprogrammemory.cpp test/testregex.o: test/testregex.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testregex.cpp -test/testsarifreport.o: test/testsarifreport.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testsarifreport.o: test/testsarifreport.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsarifreport.cpp -test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsettings.cpp -test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytemplate.cpp -test/testsimplifytokens.o: test/testsimplifytokens.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifytokens.o: test/testsimplifytokens.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytokens.cpp -test/testsimplifytypedef.o: test/testsimplifytypedef.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifytypedef.o: test/testsimplifytypedef.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytypedef.cpp -test/testsimplifyusing.o: test/testsimplifyusing.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifyusing.o: test/testsimplifyusing.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifyusing.cpp -test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsingleexecutor.cpp -test/testsizeof.o: test/testsizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checksizeof.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testsizeof.o: test/testsizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checksizeof.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsizeof.cpp -test/teststandards.o: test/teststandards.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/teststandards.o: test/teststandards.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststandards.cpp -test/teststl.o: test/teststl.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkstl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/teststl.o: test/teststl.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkstl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststl.cpp -test/teststring.o: test/teststring.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkstring.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/teststring.o: test/teststring.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkstring.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststring.cpp -test/testsummaries.o: test/testsummaries.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testsummaries.o: test/testsummaries.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/summaries.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsummaries.cpp -test/testsuppressions.o: test/testsuppressions.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/singleexecutor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testsuppressions.o: test/testsuppressions.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/singleexecutor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsuppressions.cpp -test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsymboldatabase.cpp -test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testthreadexecutor.cpp -test/testtimer.o: test/testtimer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.h +test/testtimer.o: test/testtimer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtimer.cpp -test/testtoken.o: test/testtoken.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtoken.o: test/testtoken.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtoken.cpp -test/testtokenize.o: test/testtokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtokenize.o: test/testtokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenize.cpp -test/testtokenlist.o: test/testtokenlist.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtokenlist.o: test/testtokenlist.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenlist.cpp -test/testtokenrange.o: test/testtokenrange.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtokenrange.o: test/testtokenrange.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenrange.cpp -test/testtype.o: test/testtype.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checktype.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testtype.o: test/testtype.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checktype.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtype.cpp -test/testuninitvar.o: test/testuninitvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testuninitvar.o: test/testuninitvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testuninitvar.cpp -test/testunusedfunctions.o: test/testunusedfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testunusedfunctions.o: test/testunusedfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedfunctions.cpp -test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedprivfunc.cpp -test/testunusedvar.o: test/testunusedvar.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checkunusedvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testunusedvar.o: test/testunusedvar.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checkunusedvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedvar.cpp -test/testutils.o: test/testutils.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testutils.o: test/testutils.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testutils.cpp -test/testvaarg.o: test/testvaarg.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkvaarg.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testvaarg.o: test/testvaarg.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkvaarg.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvaarg.cpp -test/testvalueflow.o: test/testvalueflow.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testvalueflow.o: test/testvalueflow.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvalueflow.cpp -test/testvarid.o: test/testvarid.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testvarid.o: test/testvarid.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvarid.cpp -test/testvfvalue.o: test/testvfvalue.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testvfvalue.o: test/testvfvalue.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvfvalue.cpp externals/simplecpp/simplecpp.o: externals/simplecpp/simplecpp.cpp externals/simplecpp/simplecpp.h diff --git a/TUNING.md b/TUNING.md index 4643e7d506a..ba1f7f49738 100644 --- a/TUNING.md +++ b/TUNING.md @@ -46,7 +46,7 @@ In our case Clang is mostly faster than GCC. See https://trac.cppcheck.net/ticke ### Use More Advanced Optimizations -By default we enforce the `-O2` optimization level. Even when using the `Release` build type in CMake which defaults to `-O3`. It might be possible that building with `-O3` might yield a perfomance increase. +By default we enforce the `-O2` optimization level. Even when using the `Release` build type in CMake which defaults to `-O3`. It might be possible that building with `-O3` might yield a performance increase. There are also no additional code generation flags provided so the resulting binary can run on any system. You might be able to tune this and apply more optimization which is tailored to the system you will be running the binary on. diff --git a/addons/README.md b/addons/README.md index 8df8229b970..05502f547b6 100644 --- a/addons/README.md +++ b/addons/README.md @@ -4,19 +4,19 @@ Addons are scripts that analyses Cppcheck dump files to check compatibility with ## Supported addons -+ [misra.py](https://github.com/danmar/cppcheck/blob/main/addons/misra.py) - Used to verify compliance with MISRA C 2012 - a proprietary set of guidelines to avoid such questionable code, developed for embedded systems. Since this standard is proprietary, cppcheck does not display error text by specifying only the number of violated rules (for example, [c2012-21.3]). If you want to display full texts for violated rules, you will need to create a text file containing MISRA rules, which you will have to pass when calling the script with `--rule-texts` key. Some examples of rule texts files available in [tests directory](https://github.com/danmar/cppcheck/blob/main/addons/test/misra/). -+ [y2038.py](https://github.com/danmar/cppcheck/blob/main/addons/y2038.py) - Checks code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. See complete description [here](https://github.com/danmar/cppcheck/blob/main/addons/doc/y2038.md). -+ [threadsafety.py](https://github.com/danmar/cppcheck/blob/main/addons/threadsafety.py) ++ [misra.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misra.py) + Used to verify compliance with MISRA C 2012 - a proprietary set of guidelines to avoid such questionable code, developed for embedded systems. Since this standard is proprietary, cppcheck does not display error text by specifying only the number of violated rules (for example, [c2012-21.3]). If you want to display full texts for violated rules, you will need to create a text file containing MISRA rules, which you will have to pass when calling the script with `--rule-texts` key. Some examples of rule texts files available in [tests directory](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/test/misra/). ++ [y2038.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/y2038.py) + Checks code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. See complete description [here](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/doc/y2038.md). ++ [threadsafety.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/threadsafety.py) Analyse Cppcheck dump files to locate threadsafety issues like static local objects used by multiple threads. -+ [naming.py](https://github.com/danmar/cppcheck/blob/main/addons/naming.py) ++ [naming.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/naming.py) Enforces naming conventions across the code. -+ [namingng.py](https://github.com/danmar/cppcheck/blob/main/addons/namingng.py) ++ [namingng.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/namingng.py) Enforces naming conventions across the code. Enhanced version with support for type prefixes in variable and function names. -+ [findcasts.py](https://github.com/danmar/cppcheck/blob/main/addons/findcasts.py) ++ [findcasts.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/findcasts.py) Locates casts in the code. -+ [misc.py](https://github.com/danmar/cppcheck/blob/main/addons/misc.py) ++ [misc.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misc.py) Performs miscellaneous checks. ### Other files @@ -68,5 +68,5 @@ This allows you to add additional parameters when calling the script (for exampl When using the graphical interface `cppcheck-gui`, the selection and configuration of addons is carried out on the tab `Addons and tools` in the project settings (`Edit Project File`): -![Screenshot](https://raw.githubusercontent.com/danmar/cppcheck/main/addons/doc/img/cppcheck-gui-addons.png) +![Screenshot](https://raw.githubusercontent.com/cppcheck-opensource/cppcheck/main/addons/doc/img/cppcheck-gui-addons.png) diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index dbe36d56a57..06028e2005c 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -274,7 +274,7 @@ class Token: astParent ast parent astOperand1 ast operand1 astOperand2 ast operand2 - orriginalName orriginal name of the token + orriginalName original name of the token valueType type information: container/.. file file name linenr line number @@ -1003,7 +1003,7 @@ def isMatch(self, file, line, message, errorId): and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*')) and fnmatch(errorId, self.errorId)): return True - # Other Suppression (Globaly set via suppression file or cli command) + # Other Suppression (Globally set via suppression file or cli command) if ((self.fileName is None or fnmatch(file, self.fileName)) and (self.suppressionType is None) and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*')) diff --git a/addons/misra.py b/addons/misra.py index cea5596d47d..933ef4c2025 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -803,8 +803,7 @@ def get_function_pointer_type(tok): ret += '(' tok = tok.next.next while tok and (tok.str not in '()'): - if tok.varId is None: - ret += ' ' + tok.str + ret += ' ' + tok.str tok = tok.next if (tok is None) or tok.str != ')': return None @@ -2460,20 +2459,38 @@ def get_category(essential_type): if essential_type.split(' ')[0] in ('unsigned', 'signed'): return essential_type.split(' ')[0] return None + for tok in cfg.tokenlist: - if tok.isAssignmentOp: - lhs = getEssentialType(tok.astOperand1) - rhs = getEssentialType(tok.astOperand2) - #print(lhs) - #print(rhs) - if lhs is None or rhs is None: + if not tok.isAssignmentOp: + continue + + lhs = getEssentialType(tok.astOperand1) + rhs = getEssentialType(tok.astOperand2) + if lhs is None or rhs is None: + continue + + find_std = cfg.standards.c if cfg.standards and cfg.standards.c else self.stdversion + + rhs_tok = tok.astOperand2 + rhs_macro_name = rhs_tok.macroName if rhs_tok else None + rhs_spelling = rhs_macro_name if rhs_macro_name in ('true', 'false') else rhs_tok.str + + rhs_is_source_bool_literal = rhs_spelling in ('true', 'false') + rhs_is_source_int_literal_0_1 = rhs_spelling in ('0', '1') + + if lhs == 'bool': + if rhs_is_source_bool_literal: continue - lhs_category = get_category(lhs) - rhs_category = get_category(rhs) - if lhs_category and rhs_category and lhs_category != rhs_category and rhs_category not in ('signed','unsigned'): - self.reportError(tok, 10, 3) - if bitsOfEssentialType(lhs) < bitsOfEssentialType(rhs) and (lhs != "bool" or tok.astOperand2.str not in ('0','1')): - self.reportError(tok, 10, 3) + if find_std == 'c89' and rhs_is_source_int_literal_0_1: + continue + + lhs_category = get_category(lhs) + rhs_category = get_category(rhs) + if lhs_category and rhs_category and lhs_category != rhs_category and rhs_category not in ('signed', 'unsigned'): + self.reportError(tok, 10, 3) + + if bitsOfEssentialType(lhs) < bitsOfEssentialType(rhs): + self.reportError(tok, 10, 3) def misra_10_4(self, data): op = {'+', '-', '*', '/', '%', '&', '|', '^', '+=', '-=', ':'} diff --git a/addons/test/misra/crash10.c b/addons/test/misra/crash10.c index 455d86e57ec..65e3a14ac96 100644 --- a/addons/test/misra/crash10.c +++ b/addons/test/misra/crash10.c @@ -2,7 +2,7 @@ extern uint32_t end; -//#define KEEP // if uncomment this then wont crash +//#define KEEP // if uncomment this then won't crash KEEP static const int32_t ptr_to_end = &end; diff --git a/addons/test/misra/misra-test-c11.c b/addons/test/misra/misra-test-c11.c index 031bc361e5f..aa00b2f0b42 100644 --- a/addons/test/misra/misra-test-c11.c +++ b/addons/test/misra/misra-test-c11.c @@ -2,6 +2,7 @@ // ~/cppcheck/cppcheck --dump misra/misra-test-c11.c --std=c11 // ~/cppcheck/cppcheck --dump -DDUMMY --suppress=uninitvar --inline-suppr misra/misra-test-c11.c --std=c11 --platform=unix64 && python3 ../misra.py -verify misra/misra-test-c11.c.dump +#include #include typedef unsigned int UINT_TYPEDEF; @@ -23,3 +24,15 @@ static void misra6_1_fn(void) { struct_with_bitfields s; s.h = 61; } + +static void misra_10_3_c11(void) { + bool b = false; + bool b0 = 0; // 10.3 + bool b1 = 1; // 10.3 + bool bf = false; // no-warning + bool bt = true; // no-warning + b = 0; // 10.3 + b = 1; // 10.3 + b = false; // no-warning + b = true; // no-warning +} diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 743637117a5..6b6f52342aa 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -726,6 +726,10 @@ static void misra_10_3(uint32_t u32a, uint32_t u32b) { const char c = '0'; // no-warning bool b = true; // no-warning uint32_t u = UINT32_C(10); // no-warning + bool b0 = 0; // no-warning + bool b1 = 1; // no-warning + b = 0; // no-warning + b = 1; // no-warning } static void misra_10_4(u32 x, s32 y) { diff --git a/cfg/boost.cfg b/cfg/boost.cfg index d181860f0bc..722c4c83cd7 100644 --- a/cfg/boost.cfg +++ b/cfg/boost.cfg @@ -83,12 +83,12 @@ - + - + - - + + diff --git a/cfg/gtk.cfg b/cfg/gtk.cfg index 4dd9700c62c..b561aad91b2 100644 --- a/cfg/gtk.cfg +++ b/cfg/gtk.cfg @@ -10,10 +10,24 @@ + + + + + + + + + + + + + + @@ -234,6 +248,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g_thread_new g_thread_try_new @@ -807,7 +901,6 @@ g_app_info_get_default_for_uri_scheme g_application_new g_application_get_dbus_connection - g_application_get_default g_buffered_input_stream_new g_buffered_output_stream_new g_cancellable_new @@ -926,6 +1019,12 @@ g_file_attribute_matcher_ref g_file_attribute_matcher_unref + + + false + + + true @@ -8761,7 +8860,7 @@ false - + @@ -22967,6 +23066,10 @@ + + + + diff --git a/cfg/libcurl.cfg b/cfg/libcurl.cfg index 381fbb237d7..949b6de0282 100644 --- a/cfg/libcurl.cfg +++ b/cfg/libcurl.cfg @@ -167,7 +167,7 @@ - + diff --git a/cfg/qt.cfg b/cfg/qt.cfg index 00cb66c1909..66f6e78b3b6 100644 --- a/cfg/qt.cfg +++ b/cfg/qt.cfg @@ -2319,10 +2319,28 @@ + + + + + false + + + + + + + + + + false + + + - + false @@ -2338,6 +2356,68 @@ + + + false + + + + + + + + + + + false + + + + + + + + + + + false + + + + + + + + + + + false + + + + + + + + false + + + + + + + + + + + false + + + + + + + false @@ -2346,8 +2426,9 @@ - + false + @@ -2356,17 +2437,11 @@ - - - false - - - - false + @@ -2375,6 +2450,34 @@ + + + false + + + + + + + false + + + + + + + false + + + + + + + false + + + + diff --git a/cfg/selinux.cfg b/cfg/selinux.cfg index e2d7ac34dc3..31a48c6da5e 100644 --- a/cfg/selinux.cfg +++ b/cfg/selinux.cfg @@ -219,7 +219,7 @@ false - + diff --git a/cfg/std.cfg b/cfg/std.cfg index 6cd0c371a5e..ec5fbb72548 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -1665,7 +1665,7 @@ false - + @@ -1929,7 +1929,7 @@ false - + @@ -2255,7 +2255,7 @@ false - + @@ -3993,7 +3993,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -4100,7 +4100,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -4121,7 +4121,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -4411,7 +4411,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + @@ -4444,7 +4444,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + @@ -4861,7 +4861,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -4911,7 +4911,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -5044,7 +5044,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -5433,7 +5433,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -7130,6 +7130,16 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false + + + + + + + + + false + @@ -7137,6 +7147,13 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false + + + + + + false + @@ -8734,7 +8751,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init false - + @@ -8742,7 +8759,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init false - + diff --git a/cfg/windows.cfg b/cfg/windows.cfg index 7020162805a..6a0bd111afa 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -3504,7 +3504,7 @@ HFONT CreateFont( - + @@ -3559,7 +3559,7 @@ HFONT CreateFont( - + @@ -4120,7 +4120,7 @@ HFONT CreateFont( - + @@ -5595,7 +5595,7 @@ HFONT CreateFont( arg1 false - + @@ -5963,7 +5963,7 @@ HFONT CreateFont( - + @@ -6009,7 +6009,7 @@ HFONT CreateFont( - + @@ -13345,9 +13345,9 @@ HFONT CreateFont( - - - + + + diff --git a/cfg/wxwidgets.cfg b/cfg/wxwidgets.cfg index c1370373b54..9dea60761d1 100644 --- a/cfg/wxwidgets.cfg +++ b/cfg/wxwidgets.cfg @@ -17078,12 +17078,16 @@ wxItemKind kind = wxITEM_NORMAL) --> - - + false + + + + false + diff --git a/clang-tidy.md b/clang-tidy.md index aae6918e372..f00a39cde12 100644 --- a/clang-tidy.md +++ b/clang-tidy.md @@ -133,6 +133,7 @@ Does not improve the readability. `misc-unconventional-assign-operator`
`bugprone-throwing-static-initialization`
`bugprone-command-processor`
+`misc-multiple-inheritance`
To be evaluated (need to remove exclusion). @@ -163,6 +164,18 @@ We are not interested in this. Reports false positives - see https://github.com/llvm/llvm-project/issues/164125. +`readability-inconsistent-ifelse-braces`
+ +The suggestions are too intrusive. + +`modernize-avoid-c-style-cast`
+ +Currently flags functional casts - see https://github.com/llvm/llvm-project/issues/186784. + +`misc-use-internal-linkage.AnalyzeTypes`
+ +Adding anonymous namespaces requires identation which is too instrusive right now. Would require changes to our fomatting configuration. + ### Disabled for performance reasons `portability-std-allocator-const`
@@ -187,7 +200,7 @@ We are currently using our own `naming.json` to enforce naming schemes. Also dis `portability-simd-intrinsics`
-We are not using SIMD instructions and it suggests to use `std::experiemental::` features which might not be commonly available. Also disabled for performance reasons - see https://github.com/llvm/llvm-project/issues/57527#issuecomment-1237935132. +We are not using SIMD instructions and it suggests to use `std::experimental::` features which might not be commonly available. Also disabled for performance reasons - see https://github.com/llvm/llvm-project/issues/57527#issuecomment-1237935132. `modernize-macro-to-enum`
diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 2664a29a65d..f63f3291849 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,4 +1,3 @@ - file(GLOB hdrs "*.h") file(GLOB srcs "*.cpp") file(GLOB mainfile "main.cpp") diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 92f4c6cef3b..27cfe08d871 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "addoninfo.h" #include "check.h" +#include "checks.h" #include "checkers.h" #include "color.h" #include "config.h" @@ -36,7 +37,6 @@ #include "settings.h" #include "standards.h" #include "suppressions.h" -#include "timer.h" #include "utils.h" #include "frontend.h" @@ -76,9 +76,7 @@ static bool addFilesToList(const std::string& fileList, std::vector files = &infile; } std::string fileName; - // cppcheck-suppress accessMoved - FP while (std::getline(*files, fileName)) { // next line - // cppcheck-suppress accessMoved - FP if (!fileName.empty()) { pathNames.emplace_back(std::move(fileName)); } @@ -92,7 +90,6 @@ static bool addIncludePathsToList(const std::string& fileList, std::list fileSettings; if (!mSettings.fileFilters.empty()) { // filter only for the selected filenames from all project files @@ -225,6 +220,8 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) fileSettings = fileSettingsRef; } + // TODO: de-duplicate + mFileSettings.clear(); frontend::applyLang(fileSettings, mSettings, mEnforcedLang); @@ -265,19 +262,6 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) return false; } - // de-duplicate files - { - auto it = filesResolved.begin(); - while (it != filesResolved.end()) { - const std::string& name = it->path(); - // TODO: log if duplicated files were dropped - filesResolved.erase(std::remove_if(std::next(it), filesResolved.end(), [&](const FileWithDetails& entry) { - return entry.path() == name; - }), filesResolved.end()); - ++it; - } - } - std::list files; if (!mSettings.fileFilters.empty()) { files = filterFiles(mSettings.fileFilters, filesResolved); @@ -291,6 +275,19 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) files = std::move(filesResolved); } + // de-duplicate files + { + auto it = files.begin(); + while (it != files.end()) { + const std::string& absname = it->abspath(); + // TODO: log if duplicated files were dropped + files.erase(std::remove_if(std::next(it), files.end(), [&](const FileWithDetails& entry) { + return entry.abspath() == absname; + }), files.end()); + ++it; + } + } + frontend::applyLang(files, mSettings, mEnforcedLang); // sort the markup last @@ -363,9 +360,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (std::strcmp(argv[i], "--doc") == 0) { std::ostringstream doc; // Get documentation.. - for (const Check * it : Check::instances()) { - const std::string& name(it->name()); - const std::string info(it->classInfo()); + for (const Check * const c : CheckInstances::get()) { + const std::string& name(c->name()); + const std::string info(c->classInfo()); if (!name.empty() && !info.empty()) doc << "## " << name << " ##\n" << info << "\n"; @@ -621,6 +618,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.cppHeaderProbe = true; } + else if (std::strcmp(argv[i], "--debug-analyzerinfo") == 0) + mSettings.debugainfo = true; + else if (std::strcmp(argv[i], "--debug-ast") == 0) mSettings.debugast = true; @@ -632,6 +632,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strcmp(argv[i], "--debug-ignore") == 0) mSettings.debugignore = true; + else if (std::strcmp(argv[i], "--debug-ipc") == 0) + mSettings.debugipc = true; + // Show --debug output after the first simplifications else if (std::strcmp(argv[i], "--debug") == 0 || std::strcmp(argv[i], "--debug-normal") == 0) @@ -753,6 +756,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } } + else if (std::strncmp(argv[i], "--exitcode-suppress=", 20) == 0) { + const std::string suppression = argv[i]+20; + const std::string errmsg(mSuppressions.nofail.addSuppressionLine(suppression)); + if (!errmsg.empty()) { + mLogger.printError(errmsg); + return Result::Fail; + } + } + // Filter errors else if (std::strncmp(argv[i], "--exitcode-suppressions=", 24) == 0) { // exitcode-suppressions=filename.txt @@ -1140,6 +1152,11 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mLogger.printError("invalid --premium option '" + (p2.empty() ? p : p2) + "'."); return Result::Fail; } + if (p2 == "cert-c-int-precision") { + int tmp; + if (!parseNumberArg(argv[i], 31, tmp, true)) + return Result::Fail; + } mSettings.premiumArgs += "--" + p; if (isCodingStandard) { // All checkers related to the coding standard should be enabled. The coding standards @@ -1185,7 +1202,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } if (projectType == ImportProject::Type::COMPILE_DB) mSettings.maxConfigsProject = 1; - if (projectType == ImportProject::Type::VS_SLN || projectType == ImportProject::Type::VS_VCXPROJ) { + if (projectType == ImportProject::Type::VS_SLN || + projectType == ImportProject::Type::VS_SLNX || + projectType == ImportProject::Type::VS_VCXPROJ) { mSettings.libraries.emplace_back("windows"); } for (const auto &error : project.errors) @@ -1211,7 +1230,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mLogger.printError("--project-configuration parameter is empty."); return Result::Fail; } - if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_VCXPROJ) { + if (projectType != ImportProject::Type::VS_SLN && + projectType != ImportProject::Type::VS_SLNX && + projectType != ImportProject::Type::VS_VCXPROJ) { mLogger.printError("--project-configuration has no effect - no Visual Studio project provided."); return Result::Fail; } @@ -1291,7 +1312,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } std::string regex_err; - auto regex = Regex::create(rule.pattern, regex_err); + auto regex = Regex::create(rule.pattern, Regex::Engine::Pcre, regex_err); if (!regex) { mLogger.printError("failed to compile rule pattern '" + rule.pattern + "' (" + regex_err + ")."); return Result::Fail; @@ -1348,6 +1369,16 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } } } + else if (std::strcmp(subname, "engine") == 0) { + const char * const engine = empty_if_null(subtext); + if (std::strcmp(engine, "pcre") == 0) { + rule.engine = Regex::Engine::Pcre; + } + else { + mLogger.printError(std::string("unknown regex engine '") + engine + "'."); + return Result::Fail; + } + } else { mLogger.printError("unable to load rule-file '" + ruleFile + "' - unknown element '" + subname + "' encountered in 'rule'."); return Result::Fail; @@ -1375,7 +1406,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } std::string regex_err; - auto regex = Regex::create(rule.pattern, regex_err); + auto regex = Regex::create(rule.pattern, rule.engine, regex_err); if (!regex) { mLogger.printError("unable to load rule-file '" + ruleFile + "' - pattern '" + rule.pattern + "' failed to compile (" + regex_err + ")."); return Result::Fail; @@ -1407,17 +1438,17 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strncmp(argv[i], "--showtime=", 11) == 0) { const std::string showtimeMode = argv[i] + 11; if (showtimeMode == "file") - mSettings.showtime = ShowTime::FILE; + mSettings.showtime = Settings::ShowTime::FILE; else if (showtimeMode == "file-total") - mSettings.showtime = ShowTime::FILE_TOTAL; + mSettings.showtime = Settings::ShowTime::FILE_TOTAL; else if (showtimeMode == "summary") - mSettings.showtime = ShowTime::SUMMARY; + mSettings.showtime = Settings::ShowTime::SUMMARY; else if (showtimeMode == "top5_file") - mSettings.showtime = ShowTime::TOP5_FILE; + mSettings.showtime = Settings::ShowTime::TOP5_FILE; else if (showtimeMode == "top5_summary") - mSettings.showtime = ShowTime::TOP5_SUMMARY; + mSettings.showtime = Settings::ShowTime::TOP5_SUMMARY; else if (showtimeMode == "none") - mSettings.showtime = ShowTime::NONE; + mSettings.showtime = Settings::ShowTime::NONE; else if (showtimeMode.empty()) { mLogger.printError("no mode provided for --showtime"); return Result::Fail; @@ -1646,7 +1677,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.platform.defaultSign = defaultSign; if (!mSettings.analyzeAllVsConfigs) { - if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_VCXPROJ) { + if (projectType != ImportProject::Type::VS_SLN && + projectType != ImportProject::Type::VS_SLNX && + projectType != ImportProject::Type::VS_VCXPROJ) { if (mAnalyzeAllVsConfigsSetOnCmdLine) { mLogger.printError("--no-analyze-all-vs-configs has no effect - no Visual Studio project provided."); return Result::Fail; @@ -1792,6 +1825,9 @@ void CmdLineParser::printHelp() const " provided. Note that your operating system can modify\n" " this value, e.g. '256' can become '0'.\n" " --errorlist Print a list of all the error messages in XML format.\n" + " --exitcode-suppress=\n" + " Used to specify an error ID which should not result in\n" + " a non-zero exitcode." " --exitcode-suppressions=\n" " Used when certain messages should be displayed but\n" " should not cause a non-zero exitcode.\n" @@ -1932,13 +1968,13 @@ void CmdLineParser::printHelp() const oss << " --project= Run Cppcheck on project. The can be a Visual\n" - " Studio Solution (*.sln), Visual Studio Project\n" + " Studio Solution (*.sln) or (*.slnx), Visual Studio Project\n" " (*.vcxproj), compile database (compile_commands.json),\n" " or Borland C++ Builder 6 (*.bpr). The files to analyse,\n" " include paths, defines, platform and undefines in\n" " the specified file will be used.\n" " --project-configuration=\n" - " If used together with a Visual Studio Solution (*.sln)\n" + " If used together with a Visual Studio Solution (*.sln) or (*.slnx)\n" " or Visual Studio Project (*.vcxproj) you can limit\n" " the configuration cppcheck should check.\n" " For example: '--project-configuration=Release|Win32'\n" diff --git a/cli/cmdlineparser.h b/cli/cmdlineparser.h index 3fafce3ce57..54e7ae4b0aa 100644 --- a/cli/cmdlineparser.h +++ b/cli/cmdlineparser.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index a16f76183c0..72a20315272 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -174,10 +175,8 @@ namespace { { std::set activeCheckers; std::string line; - // cppcheck-suppress accessMoved - FP while (std::getline(fin, line)) { - // cppcheck-suppress accessMoved - FP activeCheckers.emplace(std::move(line)); } mActiveCheckers = std::move(activeCheckers); @@ -269,7 +268,9 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) return EXIT_SUCCESS; } - Timer realTimeClock("", settings.showtime, nullptr, Timer::Type::OVERALL); + std::unique_ptr overallTimer; + if (settings.showtime == Settings::ShowTime::SUMMARY || settings.showtime == Settings::ShowTime::TOP5_SUMMARY) + overallTimer.reset(new OneShotTimer("Overall time")); settings.loadSummaries(); @@ -295,19 +296,21 @@ int CppCheckExecutor::check_wrapper(const Settings& settings, Suppressions& supp } /** - * Report unmatched suppressions - * @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions) - * @return true is returned if errors are reported + * Get list of unmatchedSuppression errors + * @param unmatched list of unmatched suppressions + * @param filters a list of (globbed) IDs to filter out + * @return vector of unmatchedSuppression errors */ -static bool reportUnmatchedSuppressions(const std::list &unmatched, ErrorLogger &errorLogger, const std::vector& filters) +static std::vector getUnmatchedSuppressions(const std::list &unmatched, const std::vector& filters) { - bool err = false; + std::vector errors; + // Report unmatched suppressions for (const SuppressionList::Suppression &s : unmatched) { // check if this unmatched suppression is suppressed bool suppressed = false; for (const SuppressionList::Suppression &s2 : unmatched) { - if (s2.errorId == "unmatchedSuppression") { + if (s2.errorId == "unmatchedSuppression") { // TODO: handle unmatchedPolyspaceSuppression? if ((s2.fileName.empty() || s2.fileName == "*" || s2.fileName == s.fileName) && (s2.lineNumber == SuppressionList::Suppression::NO_LINE || s2.lineNumber == s.lineNumber)) { suppressed = true; @@ -325,14 +328,15 @@ static bool reportUnmatchedSuppressions(const std::list callStack; + std::list callStack; if (!s.fileName.empty()) { - callStack.emplace_back(s.fileName, s.lineNumber, 0); + callStack.emplace_back(s.fileName, s.lineNumber == -1 ? 0 : s.lineNumber, s.column); // TODO: get rid of s.lineNumber == -1 hack } - errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal)); - err = true; + const std::string unmatchedSuppressionId = s.isPolyspace ? "unmatchedPolyspaceSuppression" : "unmatchedSuppression"; + errors.emplace_back(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppressionId, Certainty::normal); } - return err; + + return errors; } bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, const SuppressionList& suppressions, const std::list &files, const std::list& fileSettings, ErrorLogger& errorLogger) { @@ -342,6 +346,7 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con // bail out if there is a suppression of unmatchedSuppression which matches any file auto suppr = suppressions.getSuppressions(); if (std::any_of(suppr.cbegin(), suppr.cend(), [](const SuppressionList::Suppression& s) { + // TODO: handle unmatchedPolyspaceSuppression? return s.errorId == "unmatchedSuppression" && (s.fileName.empty() || s.fileName == "*") && s.lineNumber == SuppressionList::Suppression::NO_LINE; })) return false; @@ -358,21 +363,55 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con supprlist.addSuppression(std::move(s)); } + const auto reportErrorsFn = [&](const std::string& sourcefile, std::size_t fsFileId, const std::vector& errors) -> bool { + if (errors.empty()) + return false; + + // TODO: what if sourcefile is empty? + + AnalyzerInformation analyzerInfo; + // FIXME: this is a horrible hack + // we need to "re-open" the file so we can add the unmatchedSuppression findings. + // we cannot keep it open conditionally because the whole program analysis reads the XML. + // re-ordering the code is also not an option because the unmatched suppression reporting needs to be run after all other checks. + analyzerInfo.reopen(settings.buildDir, sourcefile, /*cfgname*/ "", fsFileId); + + for (const auto& errmsg : errors) { + analyzerInfo.reportErr(errmsg); + errorLogger.reportErr(errmsg); + } + return true; + }; + bool err = false; for (auto i = files.cbegin(); i != files.cend(); ++i) { - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), settings.unmatchedSuppressionFilters); + err |= reportErrorsFn(i->spath(), i->fsFileId(), errors); } for (auto i = fileSettings.cbegin(); i != fileSettings.cend(); ++i) { - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), settings.unmatchedSuppressionFilters); + err |= reportErrorsFn(i->file.spath(), i->file.fsFileId(), errors); } if (settings.inlineSuppressions) { - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = getUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), settings.unmatchedSuppressionFilters); + for (const auto& errmsg : errors) { + std::string sourcefile; + if (!errmsg.callStack.empty()) + sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path? + err |= reportErrorsFn(sourcefile, 0, {errmsg}); + } } - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = getUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), settings.unmatchedSuppressionFilters); + for (const auto& errmsg : errors) { + std::string sourcefile; + if (!errmsg.callStack.empty()) + sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path? + err |= reportErrorsFn(sourcefile, 0, {errmsg}); + } return err; } @@ -382,7 +421,9 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& supprs) const { StdLogger stdLogger(settings); - TimerResults timerResults; + std::unique_ptr timerResults; + if (settings.showtime != Settings::ShowTime::NONE) + timerResults.reset(new TimerResults); if (settings.reportProgress >= 0) stdLogger.resetLatestProgressOutputTime(); @@ -395,7 +436,7 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup std::list fileNames; for (auto i = mFiles.cbegin(); i != mFiles.cend(); ++i) fileNames.emplace_back(i->path()); - AnalyzerInformation::writeFilesTxt(settings.buildDir, fileNames, settings.userDefines, mFileSettings); + AnalyzerInformation::writeFilesTxt(settings.buildDir, fileNames, mFileSettings); stdLogger.readActiveCheckers(); } @@ -403,31 +444,40 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup if (!settings.checkersReportFilename.empty()) std::remove(settings.checkersReportFilename.c_str()); - CppCheck cppcheck(settings, supprs, stdLogger, &timerResults, true, executeCommand); + CppCheck cppcheck(settings, supprs, stdLogger, timerResults.get(), true, executeCommand); unsigned int returnValue = 0; if (settings.useSingleJob()) { // Single process - SingleExecutor executor(cppcheck, mFiles, mFileSettings, settings, supprs, stdLogger, &timerResults); + SingleExecutor executor(cppcheck, mFiles, mFileSettings, settings, supprs, stdLogger, timerResults.get()); returnValue = executor.check(); } else { #if defined(HAS_THREADING_MODEL_THREAD) if (settings.executor == Settings::ExecutorType::Thread) { - ThreadExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, &timerResults, CppCheckExecutor::executeCommand); + ThreadExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, timerResults.get(), CppCheckExecutor::executeCommand); returnValue = executor.check(); } #endif #if defined(HAS_THREADING_MODEL_FORK) if (settings.executor == Settings::ExecutorType::Process) { - ProcessExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, &timerResults, CppCheckExecutor::executeCommand); + ProcessExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, timerResults.get(), CppCheckExecutor::executeCommand); returnValue = executor.check(); } #endif } + // TODO: show time *after* the whole program analysis + if (timerResults) { + if (settings.showtime == Settings::ShowTime::SUMMARY) + timerResults->showResults(); + else if (settings.showtime == Settings::ShowTime::TOP5_SUMMARY) + timerResults->showResults(5); + } + + // TODO: is this run again instead of using previously cached results? returnValue |= cppcheck.analyseWholeProgram(settings.buildDir, mFiles, mFileSettings, stdLogger.getCtuInfo()); - if (settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) { + if ((settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) && !supprs.nomsg.getSuppressions().empty()) { const bool err = reportUnmatchedSuppressions(settings, supprs.nomsg, mFiles, mFileSettings, stdLogger); if (err && returnValue == 0) returnValue = settings.exitCode; @@ -451,6 +501,7 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup void StdLogger::writeCheckersReport(const Suppressions& supprs) { + // TODO: only necessary when we actually issue a checkers report? if (!mCheckersFile.empty()) { std::ofstream fout(mCheckersFile); @@ -460,15 +511,14 @@ void StdLogger::writeCheckersReport(const Suppressions& supprs) } } - const bool summary = mSettings.safety || mSettings.severity.isEnabled(Severity::information); - const bool xmlReport = mSettings.outputFormat == Settings::OutputFormat::xml && mSettings.xml_version == 3; - const bool textReport = !mSettings.checkersReportFilename.empty(); + bool summary, xmlReport, textReport; - if (!summary && !xmlReport && !textReport) + if (!mSettings.collectLogCheckers(&summary, &xmlReport, &textReport)) return; CheckersReport checkersReport(mSettings, mActiveCheckers); + // TODO: include in summary boolean const auto& suppressions = supprs.nomsg.getSuppressions(); const bool summarySuppressed = std::any_of(suppressions.cbegin(), suppressions.cend(), [](const SuppressionList::Suppression& s) { return s.errorId == "checkersReport"; diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index a063a795241..a1b35280597 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/cli/executor.cpp b/cli/executor.cpp index c9c0c73c56e..d0a05eda5f7 100644 --- a/cli/executor.cpp +++ b/cli/executor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/cli/executor.h b/cli/executor.h index d5a20fd4527..7e6fb83eeba 100644 --- a/cli/executor.h +++ b/cli/executor.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/cli/filelister.cpp b/cli/filelister.cpp index 24acc186818..65a77ea6306 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -172,7 +172,7 @@ std::string FileLister::addFiles(std::list &files, const std::s std::string err = addFiles2(filesSorted, path, extra, recursive, ignored, debug); - // files need to be sorted as the filesystems dosn't provide a stable order + // files need to be sorted as the filesystems doesn't provide a stable order filesSorted.sort([](const FileWithDetails& a, const FileWithDetails& b) { return a.path() < b.path(); }); @@ -293,7 +293,7 @@ std::string FileLister::addFiles(std::list &files, const std::s std::string err = addFiles2(filesSorted, corrected_path, extra, recursive, ignored, debug); - // files need to be sorted as the filesystems dosn't provide a stable order + // files need to be sorted as the filesystems doesn't provide a stable order filesSorted.sort([](const FileWithDetails& a, const FileWithDetails& b) { return a.path() < b.path(); }); diff --git a/cli/main.cpp b/cli/main.cpp index aa9b2aa3889..9bea4336c84 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ /** * * @mainpage Cppcheck - * @version 2.18.99 + * @version 2.20.99 * * @section overview_sec Overview * Cppcheck is a simple tool for static analysis of C/C++ code. diff --git a/cli/processexecutor.cpp b/cli/processexecutor.cpp index 963818ecfb2..e77a75ba39e 100644 --- a/cli/processexecutor.cpp +++ b/cli/processexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,9 +78,9 @@ ProcessExecutor::ProcessExecutor(const std::list &files, const namespace { class PipeWriter : public ErrorLogger { public: - enum PipeSignal : std::uint8_t {REPORT_OUT='1',REPORT_ERROR='2',REPORT_SUPPR_INLINE='3',REPORT_SUPPR='4',CHILD_END='5',REPORT_METRIC='6'}; + enum PipeSignal : std::uint8_t {REPORT_OUT='1',REPORT_ERROR='2',REPORT_SUPPR_INLINE='3',REPORT_SUPPR='4',CHILD_END='5',REPORT_METRIC='6',REPORT_TIMER='7'}; - explicit PipeWriter(int pipe) : mWpipe(pipe) {} + explicit PipeWriter(int pipe, bool debug) : mWpipe(pipe), mDebug(debug) {} void reportOut(const std::string &outmsg, Color c) override { writeToPipe(REPORT_OUT, static_cast(c) + outmsg); @@ -104,6 +104,18 @@ namespace { writeToPipe(REPORT_METRIC, metric); } + void writeTimer(const TimerResults* timerResults) const { + if (!timerResults) + return; + + for (const auto& entry : timerResults->getResults()) + { + for (const auto& d : entry.second) { + writeToPipe(REPORT_TIMER, entry.first + ";" + std::to_string(d.count())); + } + } + } + void writeEnd(const std::string& str) const { writeToPipe(CHILD_END, str); } @@ -113,6 +125,8 @@ namespace { { std::string suppr_str = suppr.toString(); suppr_str += ";"; + suppr_str += std::to_string(suppr.column); + suppr_str += ";"; suppr_str += suppr.checked ? "1" : "0"; suppr_str += ";"; suppr_str += suppr.matched ? "1" : "0"; @@ -139,6 +153,9 @@ namespace { void writeToPipe(PipeSignal type, const std::string &data) const { + if (mDebug) + std::cout << "writeToPipe - " << static_cast(type) << " - " << data << std::endl; + { const auto t = static_cast(type); writeToPipeInternal(type, &t, 1); @@ -155,6 +172,7 @@ namespace { } const int mWpipe; + const bool mDebug; }; } @@ -186,7 +204,8 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str type != PipeWriter::REPORT_SUPPR_INLINE && type != PipeWriter::REPORT_SUPPR && type != PipeWriter::CHILD_END && - type != PipeWriter::REPORT_METRIC) { + type != PipeWriter::REPORT_METRIC && + type != PipeWriter::REPORT_TIMER) { std::cerr << "#### ThreadExecutor::handleRead(" << filename << ") invalid type " << int(type) << std::endl; std::exit(EXIT_FAILURE); } @@ -220,6 +239,9 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str } while (bytes_to_read != 0); } + if (mSettings.debugipc) + std::cout << "handleRead - " << type << " - " << buf << std::endl; + bool res = true; if (type == PipeWriter::REPORT_OUT) { // the first character is the color @@ -241,7 +263,7 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str if (!buf.empty()) { // TODO: avoid string splitting auto parts = splitString(buf, ';'); - if (parts.size() < 4) + if (parts.size() < 5) { // TODO: make this non-fatal std::cerr << "#### ThreadExecutor::handleRead(" << filename << ") adding of inline suppression failed - insufficient data" << std::endl; @@ -249,10 +271,11 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str } auto suppr = SuppressionList::parseLine(parts[0]); suppr.isInline = (type == PipeWriter::REPORT_SUPPR_INLINE); - suppr.checked = parts[1] == "1"; - suppr.matched = parts[2] == "1"; - suppr.extraComment = parts[3]; - for (std::size_t i = 4; i < parts.size(); i++) { + suppr.column = strToInt(parts[1]); + suppr.checked = parts[2] == "1"; + suppr.matched = parts[3] == "1"; + suppr.extraComment = parts[4]; + for (std::size_t i = 5; i < parts.size(); i++) { suppr.extraComment += ";" + parts[i]; } const std::string err = mSuppressions.nomsg.addSuppression(suppr); @@ -269,6 +292,20 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str res = false; } else if (type == PipeWriter::REPORT_METRIC) { mErrorLogger.reportMetric(buf); + } else if (type == PipeWriter::REPORT_TIMER) { + if (!mTimerResults) { + // TODO: make this non-fatal + std::cerr << "#### ThreadExecutor::handleRead(" << filename << ") received timer results when no timer is enabled" << std::endl; + std::exit(EXIT_FAILURE); + } + const auto parts = splitString(buf, ';'); + if (parts.size() < 2) + { + // TODO: make this non-fatal + std::cerr << "#### ThreadExecutor::handleRead(" << filename << ") adding of timer result failed - insufficient data" << std::endl; + std::exit(EXIT_FAILURE); + } + mTimerResults->addResults(parts[0], std::chrono::milliseconds{strToInt(parts[1])}); } return res; @@ -305,6 +342,12 @@ unsigned int ProcessExecutor::check() return v + p.size(); }); + // pass unmodified suppressions to forked process so we only transfer back the actual changes done by the fork + // and do not see the changes which have already been transferred back + Suppressions supprs; + supprs.nomsg.addSuppressions(mSuppressions.nomsg.getSuppressions()); + supprs.nofail.addSuppressions(mSuppressions.nofail.getSuppressions()); + std::list rpipes; std::map childFile; std::map pipeFile; @@ -343,8 +386,13 @@ unsigned int ProcessExecutor::check() #endif close(pipes[0]); - PipeWriter pipewriter(pipes[1]); - CppCheck fileChecker(mSettings, mSuppressions, pipewriter, mTimerResults, false, mExecuteCommand); + // create a separate result object so we do not get the results which have already been transferred back + std::unique_ptr timerResults; + if (mTimerResults) + timerResults.reset(new TimerResults); + + PipeWriter pipewriter(pipes[1], mSettings.debugipc); + CppCheck fileChecker(mSettings, supprs, pipewriter, timerResults.get(), false, mExecuteCommand); unsigned int resultOfCheck = 0; if (iFileSettings != mFileSettings.end()) { @@ -354,7 +402,9 @@ unsigned int ProcessExecutor::check() resultOfCheck = fileChecker.check(*iFile); } - pipewriter.writeSuppr(mSuppressions.nomsg); + pipewriter.writeSuppr(supprs.nomsg); + + pipewriter.writeTimer(timerResults.get()); pipewriter.writeEnd(std::to_string(resultOfCheck)); std::exit(EXIT_SUCCESS); @@ -449,9 +499,7 @@ unsigned int ProcessExecutor::check() } } - // TODO: wee need to get the timing information from the subprocess - if (mTimerResults && (mSettings.showtime == ShowTime::SUMMARY || mSettings.showtime == ShowTime::TOP5_SUMMARY)) - mTimerResults->showResults(mSettings.showtime); + // TODO: we need to get the timing information from the subprocess return result; } @@ -467,7 +515,7 @@ void ProcessExecutor::reportInternalChildErr(const std::string &childname, const "cppcheckError", Certainty::normal); - if (!mSuppressions.nomsg.isSuppressed(errmsg, {})) + if (hasToLog(errmsg)) mErrorLogger.reportErr(errmsg); } diff --git a/cli/processexecutor.h b/cli/processexecutor.h index f813b1893e5..6c590da4072 100644 --- a/cli/processexecutor.h +++ b/cli/processexecutor.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/cli/signalhandler.cpp b/cli/signalhandler.cpp index d09bbd349d0..64e5038e82e 100644 --- a/cli/signalhandler.cpp +++ b/cli/signalhandler.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,8 +24,6 @@ #if defined(USE_UNIX_SIGNAL_HANDLING) -#include "utils.h" - #ifdef USE_UNIX_BACKTRACE_SUPPORT #include "stacktrace.h" #endif @@ -108,23 +106,24 @@ static const Signalmap_t listofsignals = { * but when ending up here something went terribly wrong anyway. * And all which is left is just printing some information and terminate. */ -static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) +static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) // cppcheck-suppress constParameterCallback - info can be const { - int type = -1; + const char* typeStr = ""; pid_t killid; // TODO: separate these two defines #if defined(__linux__) && defined(REG_ERR) const auto* const uc = reinterpret_cast(context); killid = static_cast(syscall(SYS_gettid)); if (uc) { - type = static_cast(uc->uc_mcontext.gregs[REG_ERR]) & 2; + const int type = static_cast(uc->uc_mcontext.gregs[REG_ERR]) & 2; + typeStr = (type == 0) ? "reading " : "writing "; } #else (void)context; killid = getpid(); #endif - const auto it = utils::as_const(listofsignals).find(signo); + const auto it = listofsignals.find(signo); const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str(); bool unexpectedSignal=true; // unexpected indicates program failure bool terminate=true; // exit process/thread @@ -260,9 +259,7 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) break; } fprintf(output, " (%sat 0x%lx).%s\n", - // cppcheck-suppress knownConditionTrueFalse ; FP - (type==-1)? "" : - (type==0) ? "reading " : "writing ", + typeStr, reinterpret_cast(info->si_addr), isAddressOnStack ? " Stackoverflow?" : "" ); diff --git a/cli/singleexecutor.cpp b/cli/singleexecutor.cpp index 9da1645a6a4..d710a4d4c57 100644 --- a/cli/singleexecutor.cpp +++ b/cli/singleexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,12 +67,10 @@ unsigned int SingleExecutor::check() reportStatus(c, mFileSettings.size(), c, mFileSettings.size()); } + // TODO: show time after the whole program analysis // TODO: CppCheckExecutor::check_internal() is also invoking the whole program analysis - is it run twice? if (mCppcheck.analyseWholeProgram()) result++; - if (mTimerResults && (mSettings.showtime == ShowTime::SUMMARY || mSettings.showtime == ShowTime::TOP5_SUMMARY)) - mTimerResults->showResults(mSettings.showtime); - return result; } diff --git a/cli/singleexecutor.h b/cli/singleexecutor.h index b6cae501214..8b908bd6c4e 100644 --- a/cli/singleexecutor.h +++ b/cli/singleexecutor.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index bdf1fb6f2e0..b8581d7e772 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -216,9 +216,6 @@ unsigned int ThreadExecutor::check() return v + f.get(); }); - if (mTimerResults && (mSettings.showtime == ShowTime::SUMMARY || mSettings.showtime == ShowTime::TOP5_SUMMARY)) - mTimerResults->showResults(mSettings.showtime); - return result; } diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index e827969037c..a0ab4933573 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/cmake/clang_tidy.cmake b/cmake/clang_tidy.cmake index fe0efbbe32f..f8324b98d21 100644 --- a/cmake/clang_tidy.cmake +++ b/cmake/clang_tidy.cmake @@ -25,8 +25,11 @@ if(RUN_CLANG_TIDY_NAMES) endif() message(STATUS "NPROC=${NPROC}") - # TODO: introduced in run-clang-tidy-22 - set(CLANG_TIDY_CONFIG "-enable-check-profile") + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 22) + set(CLANG_TIDY_CONFIG "-enable-check-profile") + else() + set(CLANG_TIDY_CONFIG "") + endif() # most of these are disabled because they are too noisy in our code # clang-analyzer-core.CallAndMessage @@ -40,6 +43,8 @@ if(RUN_CLANG_TIDY_NAMES) set(CLANG_TIDY_CSA_CONFIG "-config={InheritParentConfig: true, Checks: '-*,clang-analyzer-*,-clang-analyzer-core.CallAndMessage,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-cplusplus.NewDeleteLeaks,-clang-analyzer-cplusplus.NewDelete,-clang-analyzer-core.NullDereference,-clang-analyzer-unix.Stream,-clang-analyzer-alpha.clone.CloneChecker,-clang-analyzer-alpha.webkit.*'}") if (ENABLE_CSA_ALPHA) set(CLANG_TIDY_CSA_ALPHA_OPTS "-allow-enabling-alpha-checkers" "-extra-arg=-Xclang" "-extra-arg=-analyzer-config" "-extra-arg=-Xclang" "-extra-arg=aggressive-binary-operation-simplification=true") + else() + set(CLANG_TIDY_CSA_ALPHA_OPTS "") endif() # TODO: exclude moc_*.cpp diff --git a/cmake/compilerCheck.cmake b/cmake/compilerCheck.cmake index 47c8fc1245e..c26bf9e336e 100644 --- a/cmake/compilerCheck.cmake +++ b/cmake/compilerCheck.cmake @@ -2,12 +2,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) message(ERROR "GCC >= 5.1 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported") endif() -elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) message(ERROR "Clang >= 3.5 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported") endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) + message(ERROR "AppleClang >= 6.0 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported") + endif() elseif(MSVC) if(MSVC_VERSION VERSION_LESS 1900) message(ERROR "Visual Studio >= 2015 (19.0) required - detected ${MSVC_VERSION} not supported") endif() +else() + message(WARNING "Unknown compiler ${CMAKE_CXX_COMPILER_ID}") endif() diff --git a/cmake/compilerDefinitions.cmake b/cmake/compilerDefinitions.cmake index 4967c282336..5f03b83dcee 100644 --- a/cmake/compilerDefinitions.cmake +++ b/cmake/compilerDefinitions.cmake @@ -8,26 +8,30 @@ if(MSVC) add_definitions(-DWIN32_LEAN_MEAN) endif() -# TODO: this should probably apply to the compiler and not the platform - I think it is only "broken" with MinGW -# TODO: AppleClang only has libc++ -# TODO: what about clang-cl and native Win32 clang? -if(CPPCHK_GLIBCXX_DEBUG AND UNIX AND CMAKE_BUILD_TYPE STREQUAL "Debug") - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - if(USE_LIBCXX) - if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18) - add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG) - else() - add_definitions(-D_LIBCPP_ENABLE_ASSERTIONS=1) - endif() - # TODO: also add _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS? +# libstdc++-specific flags +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR (NOT USE_LIBCXX AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + if(CPPCHK_GLIBCXX_DEBUG AND CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-D_GLIBCXX_DEBUG) + endif() +endif() + +# TODO: what about clang-cl? +# libc++-specific flags - AppleClang only has libc++ +if ((USE_LIBCXX AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + if(CPPCHK_GLIBCXX_DEBUG AND CMAKE_BUILD_TYPE STREQUAL "Debug") + # TODO: determine proper version for AppleClang - current value is based on the oldest version avaialble in CI + if((CMAKE_CXX_COMPILER_ID STREQUALS "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18) OR + (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17)) + add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG) + else() + add_definitions(-D_LIBCPP_ENABLE_ASSERTIONS=1) endif() + # TODO: also add _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS? else() # TODO: check if this can be enabled again for Clang - also done in Makefile add_definitions(-D_GLIBCXX_DEBUG) endif() -endif() -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND USE_LIBCXX) add_definitions(-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) endif() @@ -66,6 +70,10 @@ if(NO_WINDOWS_SEH) add_definitions(-DNO_WINDOWS_SEH) endif() +if(NOT MSVC) + add_definitions(-DHAVE_EXECINFO_H=${HAVE_EXECINFO_H}) +endif() + if(FILESDIR_DEF) file(TO_CMAKE_PATH "${FILESDIR_DEF}" _filesdir) add_definitions(-DFILESDIR="${_filesdir}") diff --git a/cmake/compileroptions.cmake b/cmake/compileroptions.cmake index 4112ddd2418..aa7deb8552c 100644 --- a/cmake/compileroptions.cmake +++ b/cmake/compileroptions.cmake @@ -132,11 +132,8 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() # TODO: fix and enable these warnings - or move to suppression list below - add_compile_options_safe(-Wno-documentation-unknown-command) # TODO: Clang currently does not support all commands - add_compile_options_safe(-Wno-unused-exception-parameter) add_compile_options_safe(-Wno-sign-conversion) add_compile_options_safe(-Wno-shadow-field-in-constructor) - add_compile_options_safe(-Wno-covered-switch-default) add_compile_options_safe(-Wno-shorten-64-to-32) add_compile_options_safe(-Wno-implicit-int-conversion) add_compile_options_safe(-Wno-double-promotion) @@ -173,6 +170,12 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wno-weak-vtables) add_compile_options(-Wno-multichar) + # FIXME: only reported when running clang-tidy + # /home/runner/work/cppcheck/cppcheck/tools/triage/mainwindow.cpp:19:10: error: multiple candidates for header 'mainwindow.h' found; directory '/home/runner/work/cppcheck/cppcheck/tools/triage' chosen, ignoring others including '/home/runner/work/cppcheck/cppcheck/gui' [clang-diagnostic-shadow-header] + # 19 | #include "mainwindow.h" + # | ^ + add_compile_options_safe(-Wno-shadow-header) + if(ENABLE_COVERAGE OR ENABLE_COVERAGE_XML) message(FATAL_ERROR "Do not use clang to generate code coverage. Use GCC instead.") endif() diff --git a/cmake/findDependencies.cmake b/cmake/findDependencies.cmake index 61458ced051..b1f6571504d 100644 --- a/cmake/findDependencies.cmake +++ b/cmake/findDependencies.cmake @@ -3,7 +3,7 @@ if(BUILD_GUI) if(WITH_QCHART) list(APPEND qt_components Charts) endif() - if(BUILD_TESTS) + if(BUILD_TESTING) list(APPEND qt_components Test) endif() find_package(Qt6 COMPONENTS ${qt_components} REQUIRED) @@ -34,6 +34,8 @@ if(HAVE_RULES) if(NOT PCRE_LIBRARY OR NOT PCRE_INCLUDE) message(FATAL_ERROR "pcre dependency for RULES has not been found") endif() +else() + set(PCRE_LIBRARY "") endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -47,7 +49,8 @@ if(NOT Python_Interpreter_FOUND) endif() else() if(${Python_VERSION} VERSION_LESS 3.7) - message(FATAL_ERROR "The minimum supported Python version is 3.7 - found ${Python_VERSION}") + message(WARNING "The minimum supported Python version is 3.7, found ${Python_VERSION} - disabling matchcompiler.") + set(USE_MATCHCOMPILER_OPT "Off") endif() endif() @@ -70,6 +73,9 @@ if(NOT USE_BUNDLED_TINYXML2) endif() find_package(Threads REQUIRED) +if(NOT DEFINED CMAKE_THREAD_LIBS_INIT) + set(CMAKE_THREAD_LIBS_INIT "") +endif() if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30") # avoid legacy warning about Boost lookup in CMake @@ -90,7 +96,7 @@ if(USE_BOOST) endif() set(Boost_FOUND ON) set(Boost_INCLUDE_DIRS "${BOOST_INCLUDEDIR}") - # TODO: set Boost_VERSION_STRING + set(Boost_VERSION_STRING "") # TODO: set proper value elseif(USE_BOOST STREQUAL "Auto") find_package(Boost) else() diff --git a/cmake/includechecks.cmake b/cmake/includechecks.cmake new file mode 100644 index 00000000000..b9cbbd03183 --- /dev/null +++ b/cmake/includechecks.cmake @@ -0,0 +1,8 @@ +include(CheckIncludeFileCXX) + +if(NOT MSVC) + check_include_file_cxx(execinfo.h HAVE_EXECINFO_H) + if(NOT HAVE_EXECINFO_H) + set(HAVE_EXECINFO_H 0) + endif() +endif() \ No newline at end of file diff --git a/cmake/options.cmake b/cmake/options.cmake index 7de7cb360f6..d640710e428 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -25,7 +25,7 @@ option(ANALYZE_TYPE "Build with TypeSanitizer to detect aliasing issues" option(WARNINGS_ARE_ERRORS "Treat warnings as errors" OFF) if(WARNINGS_ARE_ERRORS) if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24") - message(WARNING "WARNINGS_ARE_ERRORS is deprecated - please use CMAKE_COMPILE_WARNING_AS_ERROR instead") + message(DEPRECATION "WARNINGS_ARE_ERRORS is deprecated - please use CMAKE_COMPILE_WARNING_AS_ERROR instead") endif() set(CMAKE_COMPILE_WARNING_AS_ERROR On) endif() @@ -56,6 +56,18 @@ option(BUILD_CORE_DLL "Build lib as cppcheck-core.dll with Visual Studio" if(BUILD_CORE_DLL AND NOT MSVC) message(FATAL_ERROR "Building of lib as DLL is only supported with Visual Studio") endif() +# need to check before the option() specifying it or it will be defined +if(DEFINED BUILD_TESTS) + message(DEPRECATION "BUILD_TESTS has been deprecated and will be removed in Cppcheck 2.22 - please use BUILD_TESTING instead") + if(DEFINED BUILD_TESTING) + message(AUTHOR_WARNING "BUILD_TESTS and BUILD_TESTING have been defined at the same time - ignoring BUILD_TESTS") + else() + set(BUILD_TESTING "${BUILD_TESTS}") + endif() +elseif(NOT DEFINED BUILD_TESTING) + # disable tests by default - TODO: remove this + set(BUILD_TESTING OFF) +endif() option(BUILD_TESTS "Build tests" OFF) option(REGISTER_TESTS "Register tests in CTest" ON) option(ENABLE_CHECK_INTERNAL "Enable internal checks" OFF) @@ -63,7 +75,7 @@ option(DISABLE_DMAKE "Disable run-dmake dependencies" option(BUILD_MANPAGE "Enable man target to build manpage" OFF) option(BUILD_CLI "Build the CLI application" ON) -if(NOT BUILD_CLI AND BUILD_TESTS) +if(NOT BUILD_CLI AND BUILD_TESTING) message(FATAL_ERROR "Building the tests requires the CLI to be build as well") endif() @@ -104,6 +116,10 @@ if (NOT USE_BOOST AND USE_BOOST_INT128) endif() option(USE_LIBCXX "Use libc++ instead of libstdc++" OFF) +if(USE_LIBCXX AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "libc++ can only be used with a Clang-based compiler") +endif() + option(NO_UNIX_SIGNAL_HANDLING "Disable usage of Unix Signal Handling" OFF) option(NO_UNIX_BACKTRACE_SUPPORT "Disable usage of Unix Backtrace support" OFF) option(NO_WINDOWS_SEH "Disable usage of Windows SEH" OFF) @@ -113,14 +129,10 @@ option(ENABLE_CSA_ALPHA "Enable Clang Static Analyzer alpha checkers for run # TODO: disable by default like make build? option(FILESDIR "Hard-coded directory for files to load from" OFF) -if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.16") - set(CMAKE_DISABLE_PRECOMPILE_HEADERS Off CACHE BOOL "Disable precompiled headers") - # need to disable the prologue or it will be treated like a system header and not emit any warnings - # see https://gitlab.kitware.com/cmake/cmake/-/issues/21219 - set(CMAKE_PCH_PROLOGUE "") -else() - set(CMAKE_DISABLE_PRECOMPILE_HEADERS On CACHE BOOL "Disable precompiled headers") -endif() +set(CMAKE_DISABLE_PRECOMPILE_HEADERS Off CACHE BOOL "Disable precompiled headers") +# need to disable the prologue or it will be treated like a system header and not emit any warnings +# see https://gitlab.kitware.com/cmake/cmake/-/issues/21219 +set(CMAKE_PCH_PROLOGUE "") set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Output directory for headers") set(CMAKE_LIB_DIRS_CONFIGCMAKE ${CMAKE_INSTALL_PREFIX}/lib CACHE PATH "Output directory for libraries") @@ -132,7 +144,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) string(LENGTH "${FILESDIR}" _filesdir_len) # override FILESDIR if it is set or empty if(FILESDIR OR ${_filesdir_len} EQUAL 0) -# TODO: verify that it is an abolute path? +# TODO: verify that it is an absolute path? set(FILESDIR_DEF ${FILESDIR}) else() set(FILESDIR_DEF ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME} CACHE STRING "Cppcheck files directory") diff --git a/cmake/printInfo.cmake b/cmake/printInfo.cmake index 6ea93bed207..87c7e41f284 100644 --- a/cmake/printInfo.cmake +++ b/cmake/printInfo.cmake @@ -15,6 +15,9 @@ message(STATUS "C++ flags (RelWithDebInfo) = ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") message(STATUS "C++ flags (Debug) = ${CMAKE_CXX_FLAGS_DEBUG}") message(STATUS "CMAKE_EXE_LINKER_FLAGS = ${CMAKE_EXE_LINKER_FLAGS}") message(STATUS "CPPCHK_GLIBCXX_DEBUG = ${CPPCHK_GLIBCXX_DEBUG}") +if(DEFINED HAVE_EXECINFO_H) + message(STATUS "HAVE_EXECINFO_H = ${HAVE_EXECINFO_H}") +endif() get_directory_property(DirCompileDefs DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS) message(STATUS "COMPILE_DEFINITIONS (global) = ${DirCompileDefs}") get_directory_property(DirCompileOptions DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_OPTIONS) @@ -52,7 +55,8 @@ endif() message(STATUS "LIBXML2_XMLLINT_EXECUTABLE = ${LIBXML2_XMLLINT_EXECUTABLE}") message(STATUS "BUILD_CORE_DLL = ${BUILD_CORE_DLL}") message(STATUS "BUILD_TESTS = ${BUILD_TESTS}") -if(BUILD_TESTS) +message(STATUS "BUILD_TESTING = ${BUILD_TESTING}") +if(BUILD_TESTING) message(STATUS "REGISTER_TESTS = ${REGISTER_TESTS}") endif() message(STATUS "ENABLE_CHECK_INTERNAL = ${ENABLE_CHECK_INTERNAL}") @@ -68,7 +72,9 @@ if(BUILD_GUI) message(STATUS "QT_VERSION = ${QT_VERSION}") message(STATUS "Qt6Core_LIBRARIES = ${Qt6Core_LIBRARIES}") message(STATUS "Qt6Core_INCLUDE_DIRS = ${Qt6Core_INCLUDE_DIRS}") - message(STATUS "QHELPGENERATOR = ${QHELPGENERATOR}") + if(BUILD_ONLINE_HELP) + message(STATUS "QHELPGENERATOR = ${QHELPGENERATOR}") + endif() endif() message(STATUS) message(STATUS "HAVE_RULES = ${HAVE_RULES}") @@ -82,16 +88,22 @@ message(STATUS "CMAKE_THREAD_LIBS_INIT = ${CMAKE_THREAD_LIBS_INIT}") message(STATUS) message(STATUS "USE_BUNDLED_TINYXML2 = ${USE_BUNDLED_TINYXML2}") if(NOT USE_BUNDLED_TINYXML2) - message(STATUS "tinyxml2_LIBRARIES = ${tinyxml2_LIBRARIES}") - message(STATUS "tinyxml2_INCLUDE_DIRS = ${tinyxml2_INCLUDE_DIRS}") + if(TARGET tinyxml2::tinyxml2) + # TODO: print libraries and include dirs + else() + message(STATUS "tinyxml2_LIBRARIES = ${tinyxml2_LIBRARIES}") + message(STATUS "tinyxml2_INCLUDE_DIRS = ${tinyxml2_INCLUDE_DIRS}") + endif() endif() message(STATUS) message(STATUS "USE_BOOST = ${USE_BOOST}") if(USE_BOOST) message(STATUS "Boost_FOUND = ${Boost_FOUND}") - message(STATUS "Boost_VERSION_STRING = ${Boost_VERSION_STRING}") - message(STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}") - message(STATUS "USE_BOOST_INT128 = ${USE_BOOST_INT128}") + if(Boost_FOUND) + message(STATUS "Boost_VERSION_STRING = ${Boost_VERSION_STRING}") + message(STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}") + message(STATUS "USE_BOOST_INT128 = ${USE_BOOST_INT128}") + endif() endif() message(STATUS) message(STATUS "USE_LIBCXX = ${USE_LIBCXX}") diff --git a/cppcheckpremium-suppressions b/cppcheckpremium-suppressions index 6d3f16782bc..1b26fa55cc1 100644 --- a/cppcheckpremium-suppressions +++ b/cppcheckpremium-suppressions @@ -196,7 +196,7 @@ premium-misra-cpp-2023-12.3.1 # TODO ensure overrides match premium-misra-cpp-2023-13.3.2 -# TODO use the same parameter names in overriden methods. +# TODO use the same parameter names in overridden methods. premium-misra-cpp-2023-13.3.3 # we sometimes use both public/private data members by intention diff --git a/createrelease b/createrelease index 47f9dd74ab2..de85d64395b 100755 --- a/createrelease +++ b/createrelease @@ -12,6 +12,10 @@ # create jira issue "CI: update cppcheck binary" # cd ~/cppchecksolutions/addon/tools && python3 ci-update-cppcheck.py # +# update mappings.. +# cd ~/cppchecksolutions/addon/coverage +# CPPCHECK_REPO=~/cppchecksolutions/cppcheck python3 coverage.py --code +# # check every isPremiumEnabled call: TODO write helper script # - every id should be in --errorlist # git grep 'isPremiumEnabled[(]"' | sed 's/.*isPremiumEnabled[(]"//' | sed 's/".*//' | sort | uniq > ids1.txt @@ -47,6 +51,9 @@ # # Create 2.18.x branch # git checkout -b 2.18.x ; git push -u origin 2.18.x +# in fork: +# * add upstream: git remote add upstream git@github.com:/cppcheck-opensource//cppcheck.git +# * add branch: git fetch upstream 2.19.x # # Release notes: # - ensure safety critical issues are listed properly @@ -102,6 +109,12 @@ # ssh -t danielmarjamaki,cppcheck@shell.sourceforge.net create # ./build-cppcheck.sh # +# create a ticket with data from http://cppcheck1.osuosl.org:8000/time_gt.html for performance tracking +# (example: https://trac.cppcheck.net/ticket/13715) +# - type: defect +# - component: Performance +# - summary: [meta] performance regressions in 2.x +# # run daca with new release # 1. edit tools/donate-cpu-server.py. Update OLD_VERSION and SERVER_VERSION # 2. scp -i ~/.ssh/osuosl_id_rsa tools/donate-cpu-server.py danielmarjamaki@cppcheck1.osuosl.org:/var/daca@home/ @@ -111,7 +124,7 @@ # * daca: cd /var && nice tar -cJf ~/daca.tar.xz daca@home # * git: git checkout -f && git checkout main && git pull && tar -cJf git.tar.xz .git # * git log 2.16.0..2.17.0 > Changelog -# * mkdir out && python3 ~/cppchecksolutions/release/getWorkflowAndIssueLogs.py -r danmar/cppcheck -t 2.15.0 -p out +# * mkdir out && python3 ~/cppchecksolutions/release/getWorkflowAndIssueLogs.py -r /cppcheck-opensource//cppcheck -t 2.15.0 -p out # Folder/tag to use folder=$1 @@ -127,28 +140,26 @@ cd ~/cppcheck git checkout $tag rm -rf upload -mkdir -p upload +mkdir -p upload/htdocs upload/frs +# htdocs make clean - -# Create archives.. -git archive --format=tar --prefix=$releasename/ $tag | gzip > upload/$releasename.tar.gz -git archive --format=tar --prefix=$releasename/ $tag | bzip2 > upload/$releasename.tar.bz2 -git archive --format=zip -9 --prefix=$releasename/ $tag > upload/$releasename.zip -cd upload -scp $releasename.* danielmarjamaki,cppcheck@frs.sourceforge.net:/home/frs/project/c/cp/cppcheck/cppcheck/$folder/ -rm $releasename.* -cd .. - -# Generate version.txt make -j12 rm -f cppcheck.cfg -./cppcheck --version > upload/version.txt +./cppcheck --version > upload/htdocs/version.txt +# TODO manual, update version on webpage -cd ~/cppcheck/upload -scp version.txt danielmarjamaki,cppcheck@web.sourceforge.net:htdocs/ +# frs +git archive --format=tar --prefix=$releasename/ $tag | gzip > upload/frs/$releasename.tar.gz +git archive --format=tar --prefix=$releasename/ $tag | bzip2 > upload/frs/$releasename.tar.bz2 +git archive --format=zip -9 --prefix=$releasename/ $tag > upload/frs/$releasename.zip +cp releasenotes.txt upload/frs/README.md +# TODO msi -cd ~/cppcheck +cd upload +scp frs/* danielmarjamaki,cppcheck@frs.sourceforge.net:/home/frs/project/c/cp/cppcheck/cppcheck/$folder/ +scp htdocs/* danielmarjamaki,cppcheck@web.sourceforge.net:htdocs/ +cd .. rm -rf upload # Local cppcheck binary diff --git a/democlient/democlient.cpp b/democlient/democlient.cpp index 177aff28b71..8560596f4f3 100644 --- a/democlient/democlient.cpp +++ b/democlient/democlient.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp index 581c9b10990..7afc17ab735 100644 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -67,14 +67,12 @@ static bool isOct(const std::string &s) return s.size()>1 && (s[0]=='0') && (s[1] >= '0') && (s[1] < '8'); } -// TODO: added an undercore since this conflicts with a function of the same name in utils.h from Cppcheck source when building Cppcheck with MSBuild -static bool isStringLiteral_(const std::string &s) +static bool isStringLiteral(const std::string &s) { return s.size() > 1 && (s[0]=='\"') && (*s.rbegin()=='\"'); } -// TODO: added an undercore since this conflicts with a function of the same name in utils.h from Cppcheck source when building Cppcheck with MSBuild -static bool isCharLiteral_(const std::string &s) +static bool isCharLiteral(const std::string &s) { // char literal patterns can include 'a', '\t', '\000', '\xff', 'abcd', and maybe '' // This only checks for the surrounding '' but doesn't parse the content. @@ -351,121 +349,124 @@ class simplecpp::TokenList::Stream { bool isUtf16; }; -class StdIStream : public simplecpp::TokenList::Stream { -public: - // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members - explicit StdIStream(std::istream &istr) - : istr(istr) { - assert(istr.good()); - init(); - } +namespace { + class StdIStream : public simplecpp::TokenList::Stream { + public: + // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members + explicit StdIStream(std::istream &istr) + : istr(istr) { + assert(istr.good()); + init(); + } - int get() override { - return istr.get(); - } - int peek() override { - return istr.peek(); - } - void unget() override { - istr.unget(); - } - bool good() override { - return istr.good(); - } + int get() override { + return istr.get(); + } + int peek() override { + return istr.peek(); + } + void unget() override { + istr.unget(); + } + bool good() override { + return istr.good(); + } -private: - std::istream &istr; -}; + private: + std::istream &istr; + }; -class StdCharBufStream : public simplecpp::TokenList::Stream { -public: - // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members - StdCharBufStream(const unsigned char* str, std::size_t size) - : str(str) - , size(size) - { - init(); - } + class StdCharBufStream : public simplecpp::TokenList::Stream { + public: + // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members + StdCharBufStream(const unsigned char* str, std::size_t size) + : str(str) + , size(size) + { + init(); + } - int get() override { - if (pos >= size) - return lastStatus = EOF; - return str[pos++]; - } - int peek() override { - if (pos >= size) - return lastStatus = EOF; - return str[pos]; - } - void unget() override { - --pos; - } - bool good() override { - return lastStatus != EOF; - } + int get() override { + if (pos >= size) + return lastStatus = EOF; + return str[pos++]; + } + int peek() override { + if (pos >= size) + return lastStatus = EOF; + return str[pos]; + } + void unget() override { + --pos; + } + bool good() override { + return lastStatus != EOF; + } -private: - const unsigned char *str; - const std::size_t size; - std::size_t pos{}; - int lastStatus{}; -}; + private: + const unsigned char *str; + const std::size_t size; + std::size_t pos{}; + int lastStatus{}; + }; -class FileStream : public simplecpp::TokenList::Stream { -public: - /** - * @throws simplecpp::Output thrown if file is not found - */ - // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members - explicit FileStream(const std::string &filename, std::vector &files) - : file(fopen(filename.c_str(), "rb")) - { - if (!file) { - files.push_back(filename); - throw simplecpp::Output(simplecpp::Output::FILE_NOT_FOUND, {}, "File is missing: " + filename); + class FileStream : public simplecpp::TokenList::Stream { + public: + /** + * @throws simplecpp::Output thrown if file is not found + */ + // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members + explicit FileStream(const std::string &filename, std::vector &files) + : file(fopen(filename.c_str(), "rb")) + { + if (!file) { + files.emplace_back(filename); + throw simplecpp::Output(simplecpp::Output::FILE_NOT_FOUND, {}, "File is missing: " + filename); + } + init(); } - init(); - } - FileStream(const FileStream&) = delete; - FileStream &operator=(const FileStream&) = delete; + FileStream(const FileStream&) = delete; + FileStream &operator=(const FileStream&) = delete; - ~FileStream() override { - fclose(file); - file = nullptr; - } + ~FileStream() override { + fclose(file); + file = nullptr; + } - int get() override { - lastStatus = lastCh = fgetc(file); - return lastCh; - } - int peek() override { - // keep lastCh intact - const int ch = fgetc(file); - unget_internal(ch); - return ch; - } - void unget() override { - unget_internal(lastCh); - } - bool good() override { - return lastStatus != EOF; - } + int get() override { + lastStatus = lastCh = fgetc(file); + return lastCh; + } + int peek() override { + // keep lastCh intact + const int ch = fgetc(file); + unget_internal(ch); + return ch; + } + void unget() override { + unget_internal(lastCh); + } + bool good() override { + return lastStatus != EOF; + } -private: - void unget_internal(int ch) { - if (isUtf16) { - // TODO: use ungetc() as well - // UTF-16 has subsequent unget() calls - fseek(file, -1, SEEK_CUR); - } else - ungetc(ch, file); - } + private: + void unget_internal(int ch) { + if (isUtf16) { + // TODO: use ungetc() as well + // UTF-16 has subsequent unget() calls + fseek(file, -1, SEEK_CUR); + } else { + ungetc(ch, file); + } + } - FILE *file; - int lastCh{}; - int lastStatus{}; -}; + FILE *file; + int lastCh{}; + int lastStatus{}; + }; +} simplecpp::TokenList::TokenList(std::vector &filenames) : frontToken(nullptr), backToken(nullptr), files(filenames) {} @@ -490,7 +491,7 @@ simplecpp::TokenList::TokenList(const std::string &filename, std::vectorpush_back(e); + outputList->emplace_back(e); } } @@ -565,6 +566,7 @@ std::string simplecpp::TokenList::stringify(bool linenrs) const { std::ostringstream ret; Location loc; + loc.line = 1; bool filechg = true; for (const Token *tok = cfront(); tok; tok = tok->next) { if (tok->location.line < loc.line || tok->location.fileIndex != loc.fileIndex) { @@ -619,12 +621,12 @@ static void portabilityBackslash(simplecpp::OutputList *outputList, const simple { if (!outputList) return; - simplecpp::Output err = { + simplecpp::Output err{ simplecpp::Output::PORTABILITY_BACKSLASH, location, "Combination 'backslash space newline' is not portable." }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } static bool isStringLiteralPrefix(const std::string &str) @@ -668,12 +670,12 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, if (ch >= 0x80) { if (outputList) { - simplecpp::Output err = { + simplecpp::Output err{ simplecpp::Output::UNHANDLED_CHAR_ERROR, location, "The code contains unhandled character(s) (character code=" + std::to_string(static_cast(ch)) + "). Neither unicode nor extended ascii is supported." }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } clear(); return; @@ -870,12 +872,12 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, } if (!stream.good() || ch == '\n') { if (outputList) { - Output err = { + Output err{ Output::SYNTAX_ERROR, location, "Invalid newline in raw string delimiter." }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } return; } @@ -884,12 +886,12 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, currentToken += stream.readChar(); if (!endsWith(currentToken, endOfRawString)) { if (outputList) { - Output err = { + Output err{ Output::SYNTAX_ERROR, location, "Raw string missing terminating delimiter." }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } return; } @@ -1004,6 +1006,14 @@ static bool isFloatSuffix(const simplecpp::Token *tok) return c == 'f' || c == 'l'; } +static const std::string AND("and"); +static const std::string BITAND("bitand"); +static const std::string BITOR("bitor"); +static bool isAlternativeAndBitandBitor(const simplecpp::Token* tok) +{ + return isAlternativeBinaryOp(tok, AND) || isAlternativeBinaryOp(tok, BITAND) || isAlternativeBinaryOp(tok, BITOR); +} + void simplecpp::TokenList::combineOperators() { std::stack executableScope; @@ -1039,7 +1049,7 @@ void simplecpp::TokenList::combineOperators() if (tok->previous && tok->previous->number && sameline(tok->previous, tok) && tok->previous->str().find_first_of("._") == std::string::npos) { tok->setstr(tok->previous->str() + '.'); deleteToken(tok->previous); - if (sameline(tok, tok->next) && (isFloatSuffix(tok->next) || (tok->next && tok->next->startsWithOneOf("AaBbCcDdEeFfPp")))) { + if (sameline(tok, tok->next) && (isFloatSuffix(tok->next) || (tok->next && tok->next->startsWithOneOf("AaBbCcDdEeFfPp") && !isAlternativeAndBitandBitor(tok->next)))) { tok->setstr(tok->str() + tok->next->str()); deleteToken(tok->next); } @@ -1178,8 +1188,9 @@ void simplecpp::TokenList::constFoldMulDivRem(Token *tok) continue; long long result; - if (tok->op == '*') + if (tok->op == '*') { result = (stringToLL(tok->previous->str()) * stringToLL(tok->next->str())); + } else if (tok->op == '/' || tok->op == '%') { const long long rhs = stringToLL(tok->next->str()); if (rhs == 0) @@ -1191,8 +1202,9 @@ void simplecpp::TokenList::constFoldMulDivRem(Token *tok) result = (lhs / rhs); else result = (lhs % rhs); - } else + } else { continue; + } tok = tok->previous; tok->setstr(toString(result)); @@ -1284,8 +1296,6 @@ void simplecpp::TokenList::constFoldComparison(Token *tok) } } -static const std::string BITAND("bitand"); -static const std::string BITOR("bitor"); static const std::string XOR("xor"); void simplecpp::TokenList::constFoldBitwise(Token *tok) { @@ -1320,7 +1330,6 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok) } } -static const std::string AND("and"); static const std::string OR("or"); void simplecpp::TokenList::constFoldLogicalOp(Token *tok) { @@ -1416,8 +1425,9 @@ std::string simplecpp::TokenList::readUntil(Stream &stream, const Location &loca ret.erase(ret.size()-1U); backslash = (next == '\r'); update_ch = false; - } else if (next == '\\') + } else if (next == '\\') { update_ch = !update_ch; + } ret += next; } while (next == '\\'); if (update_ch) @@ -1428,12 +1438,12 @@ std::string simplecpp::TokenList::readUntil(Stream &stream, const Location &loca if (!stream.good() || ch != end) { clear(); if (outputList) { - Output err = { + Output err{ Output::SYNTAX_ERROR, location, std::string("No pair for character (") + start + "). Can't process file. File is either invalid or unicode, which is currently not supported." }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } return ""; } @@ -1471,7 +1481,7 @@ unsigned int simplecpp::TokenList::fileIndex(const std::string &filename) if (files[i] == filename) return i; } - files.push_back(filename); + files.emplace_back(filename); return files.size() - 1U; } @@ -1538,8 +1548,9 @@ namespace simplecpp { if (this != &other) { files = other.files; valueDefinedInCode_ = other.valueDefinedInCode_; - if (other.tokenListDefine.empty()) + if (other.tokenListDefine.empty()) { parseDefine(other.nameTokDef); + } else { tokenListDefine = other.tokenListDefine; parseDefine(tokenListDefine.cfront()); @@ -1608,15 +1619,17 @@ namespace simplecpp { if (par==0) break; --par; - } else if (macro2tok->op == ')') + } else if (macro2tok->op == ')') { ++par; + } macro2tok = macro2tok->previous; } if (macro2tok) { // macro2tok->op == '(' macro2tok = macro2tok->previous; expandedmacros.insert(name()); - } else if (rawtok->op == '(') + } else if (rawtok->op == '(') { macro2tok = output2.back(); + } if (!macro2tok || !macro2tok->name) break; if (output2.cfront() != output2.cback() && macro2tok->str() == this->name()) @@ -1636,8 +1649,9 @@ namespace simplecpp { const Token *rawtok2 = rawtok; for (; rawtok2; rawtok2 = rawtok2->next) { rawtokens2.push_back(new Token(rawtok2->str(), loc)); - if (rawtok2->op == '(') + if (rawtok2->op == '(') { ++par; + } else if (rawtok2->op == ')') { if (par <= 1U) break; @@ -1699,19 +1713,19 @@ namespace simplecpp { : Error(loc, format(macroName, message)) {} static inline invalidHashHash unexpectedToken(const Location &loc, const std::string ¯oName, const Token *tokenA) { - return invalidHashHash(loc, macroName, "Unexpected token '"+ tokenA->str()+"'"); + return {loc, macroName, "Unexpected token '"+ tokenA->str()+"'"}; } static inline invalidHashHash cannotCombine(const Location &loc, const std::string ¯oName, const Token *tokenA, const Token *tokenB) { - return invalidHashHash(loc, macroName, "Combining '"+ tokenA->str()+ "' and '"+ tokenB->str() + "' yields an invalid token."); + return {loc, macroName, "Combining '"+ tokenA->str()+ "' and '"+ tokenB->str() + "' yields an invalid token."}; } static inline invalidHashHash unexpectedNewline(const Location &loc, const std::string ¯oName) { - return invalidHashHash(loc, macroName, "Unexpected newline"); + return {loc, macroName, "Unexpected newline"}; } static inline invalidHashHash universalCharacterUB(const Location &loc, const std::string ¯oName, const Token* tokenA, const std::string& strAB) { - return invalidHashHash(loc, macroName, "Combining '\\"+ tokenA->str()+ "' and '"+ strAB.substr(tokenA->str().size()) + "' yields universal character '\\" + strAB + "'. This is undefined behavior according to C standard chapter 5.1.1.2, paragraph 4."); + return {loc, macroName, "Combining '\\"+ tokenA->str()+ "' and '"+ strAB.substr(tokenA->str().size()) + "' yields universal character '\\" + strAB + "'. This is undefined behavior according to C standard chapter 5.1.1.2, paragraph 4."}; } }; private: @@ -1753,7 +1767,7 @@ namespace simplecpp { break; } if (argtok->op != ',') - args.push_back(argtok->str()); + args.emplace_back(argtok->str()); argtok = argtok->next; } if (!sameline(nametoken, argtok)) { @@ -1828,22 +1842,24 @@ namespace simplecpp { std::vector getMacroParameters(const Token *nameTokInst, bool calledInDefine) const { if (!nameTokInst->next || nameTokInst->next->op != '(' || !functionLike()) - return std::vector(); + return {}; std::vector parametertokens; - parametertokens.push_back(nameTokInst->next); + parametertokens.emplace_back(nameTokInst->next); unsigned int par = 0U; for (const Token *tok = nameTokInst->next->next; calledInDefine ? sameline(tok, nameTokInst) : (tok != nullptr); tok = tok->next) { - if (tok->op == '(') + if (tok->op == '(') { ++par; + } else if (tok->op == ')') { if (par == 0U) { - parametertokens.push_back(tok); + parametertokens.emplace_back(tok); break; } --par; - } else if (par == 0U && tok->op == ',' && (!variadic || parametertokens.size() < args.size())) - parametertokens.push_back(tok); + } else if (par == 0U && tok->op == ',' && (!variadic || parametertokens.size() < args.size())) { + parametertokens.emplace_back(tok); + } } return parametertokens; } @@ -1871,8 +1887,9 @@ namespace simplecpp { tokens.back()->macro = name(); } - if (tok->op == '(') + if (tok->op == '(') { ++par; + } else if (tok->op == ')') { --par; if (par == 0U) @@ -1893,7 +1910,7 @@ namespace simplecpp { std::cout << " expand " << name() << " " << locstring(defineLocation()) << std::endl; #endif - usageList.push_back(loc); + usageList.emplace_back(loc); if (nameTokInst->str() == "__FILE__") { output.push_back(new Token('\"'+output.file(loc)+'\"', loc)); @@ -1945,19 +1962,20 @@ namespace simplecpp { const MacroMap::const_iterator m = macros.find("__COUNTER__"); - if (!counter || m == macros.end()) + if (!counter || m == macros.end()) { parametertokens2.swap(parametertokens1); + } else { const Macro &counterMacro = m->second; unsigned int par = 0; for (const Token *tok = parametertokens1[0]; tok && par < parametertokens1.size(); tok = tok->next) { if (tok->str() == "__COUNTER__") { tokensparams.push_back(new Token(toString(counterMacro.usageList.size()), tok->location)); - counterMacro.usageList.push_back(tok->location); + counterMacro.usageList.emplace_back(tok->location); } else { tokensparams.push_back(new Token(*tok)); if (tok == parametertokens1[par]) { - parametertokens2.push_back(tokensparams.cback()); + parametertokens2.emplace_back(tokensparams.cback()); par++; } } @@ -2135,8 +2153,9 @@ namespace simplecpp { TokenList tokens(files); tokens.push_back(new Token(*tok)); const Token * tok2 = nullptr; - if (tok->next->op == '(') + if (tok->next->op == '(') { tok2 = appendTokens(tokens, loc, tok->next, macros, expandedmacros, parametertokens); + } else if (expandArg(tokens, tok->next, loc, macros, expandedmacros, parametertokens)) { tokens.front()->location = loc; if (tokens.cfront()->next && tokens.cfront()->next->op == '(') @@ -2274,7 +2293,7 @@ namespace simplecpp { throw invalidHashHash::unexpectedNewline(tok->location, name()); const bool canBeConcatenatedWithEqual = A->isOneOf("+-*/%&|^") || A->str() == "<<" || A->str() == ">>"; - const bool canBeConcatenatedStringOrChar = isStringLiteral_(A->str()) || isCharLiteral_(A->str()); + const bool canBeConcatenatedStringOrChar = isStringLiteral(A->str()) || isCharLiteral(A->str()); const bool unexpectedA = (!A->name && !A->number && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar); const Token * const B = tok->next->next; @@ -2312,12 +2331,15 @@ namespace simplecpp { const bool varargs = variadic && !args.empty() && B->str() == args[args.size()-1U]; if (expandArg(tokensB, B, parametertokens)) { - if (tokensB.empty()) + if (tokensB.empty()) { strAB = A->str(); - else if (varargs && A->op == ',') + } + else if (varargs && A->op == ',') { strAB = ","; - else if (varargs && unexpectedA) + } + else if (varargs && unexpectedA) { throw invalidHashHash::unexpectedToken(tok->location, name(), A); + } else { strAB = A->str() + tokensB.cfront()->str(); tokensB.deleteToken(tokensB.front()); @@ -2336,8 +2358,9 @@ namespace simplecpp { throw invalidHashHash::universalCharacterUB(tok->location, name(), A, strAB); } - if (varargs && tokensB.empty() && tok->previous->str() == ",") + if (varargs && tokensB.empty() && tok->previous->str() == ",") { output.deleteToken(A); + } else if (strAB != "," && macros.find(strAB) == macros.end()) { A->setstr(strAB); for (Token *b = tokensB.front(); b; b = b->next) @@ -2691,7 +2714,7 @@ static void simplifyName(simplecpp::TokenList &expr) { for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) { if (tok->name) { - static const std::set altop = {"and","or","bitand","bitor","compl","not","not_eq","xor"}; + static const std::set altop{"and","or","bitand","bitor","compl","not","not_eq","xor"}; if (altop.find(tok->str()) != altop.end()) { bool alt; if (tok->str() == "not" || tok->str() == "compl") { @@ -2755,8 +2778,9 @@ long long simplecpp::characterLiteralToLL(const std::string& str) pos = 3; } else if (str.size() >= 2 && (str[0] == 'L' || str[0] == 'U') && str[1] == '\'') { pos = 2; - } else + } else { throw std::runtime_error("expected a character literal"); + } unsigned long long multivalue = 0; @@ -2956,6 +2980,7 @@ static void simplifyComments(simplecpp::TokenList &expr) /** * @throws std::runtime_error thrown on invalid literals, missing sizeof arguments or invalid expressions, * missing __has_include() arguments or expressions, undefined function-like macros, invalid number literals + * @throws std::overflow_error thrown on overflow or division by zero */ static long long evaluate(simplecpp::TokenList &expr, const simplecpp::DUI &dui, const std::map &sizeOfType) { @@ -3120,7 +3145,7 @@ std::pair simplecpp::FileDataCache::get(const std:: bool simplecpp::FileDataCache::getFileId(const std::string &path, FileID &id) { #ifdef _WIN32 - HANDLE hFile = CreateFileA(path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE hFile = CreateFileA(path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) return false; @@ -3176,12 +3201,12 @@ simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, if (filedata == nullptr) { if (outputList) { - simplecpp::Output err = { + simplecpp::Output err{ simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND, {}, "Can not open include file '" + filename + "' that is explicitly included." }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } continue; } @@ -3195,7 +3220,7 @@ simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, if (dui.removeComments) filedata->tokens.removeComments(); - filelist.push_back(filedata->tokens.front()); + filelist.emplace_back(filedata->tokens.front()); } for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : nullptr) { @@ -3234,7 +3259,7 @@ simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, if (dui.removeComments) filedata->tokens.removeComments(); - filelist.push_back(filedata->tokens.front()); + filelist.emplace_back(filedata->tokens.front()); } return cache; @@ -3250,12 +3275,12 @@ static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token tok1 = it->second.expand(value, tok, macros, files); } catch (const simplecpp::Macro::Error &err) { if (outputList) { - simplecpp::Output out = { + simplecpp::Output out{ simplecpp::Output::SYNTAX_ERROR, err.location, "failed to expand \'" + tok->str() + "\', " + err.what }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } return false; } @@ -3340,8 +3365,21 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL continue; const std::string lhs(macrostr.substr(0,eq)); const std::string rhs(eq==std::string::npos ? std::string("1") : macrostr.substr(eq+1)); - const Macro macro(lhs, rhs, dummy); - macros.insert(std::pair(macro.name(), macro)); + try { + const Macro macro(lhs, rhs, dummy); + macros.insert(std::pair(macro.name(), macro)); + } catch (const std::runtime_error& e) { + if (outputList) { + simplecpp::Output err{ + Output::DUI_ERROR, + {}, + e.what() + }; + outputList->emplace_back(std::move(err)); + } + output.clear(); + return; + } } const bool strictAnsiUndefined = dui.undefined.find("__STRICT_ANSI__") != dui.undefined.cend(); @@ -3351,7 +3389,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL macros.insert(std::make_pair("__FILE__", Macro("__FILE__", "__FILE__", dummy))); macros.insert(std::make_pair("__LINE__", Macro("__LINE__", "__LINE__", dummy))); macros.insert(std::make_pair("__COUNTER__", Macro("__COUNTER__", "__COUNTER__", dummy))); - struct tm ltime = {}; + struct tm ltime {}; getLocaltime(ltime); macros.insert(std::make_pair("__DATE__", Macro("__DATE__", getDateDefine(<ime), dummy))); macros.insert(std::make_pair("__TIME__", Macro("__TIME__", getTimeDefine(<ime), dummy))); @@ -3366,12 +3404,12 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL const cppstd_t cpp_std = simplecpp::getCppStd(dui.std); if (cpp_std == CPPUnknown) { if (outputList) { - simplecpp::Output err = { + simplecpp::Output err{ Output::DUI_ERROR, {}, "unknown standard specified: '" + dui.std + "'" }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } output.clear(); return; @@ -3423,12 +3461,12 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL if (ifstates.size() <= 1U && (rawtok->str() == ELIF || rawtok->str() == ELSE || rawtok->str() == ENDIF)) { if (outputList) { - simplecpp::Output err = { + simplecpp::Output err{ Output::SYNTAX_ERROR, rawtok->location, "#" + rawtok->str() + " without #if" }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } output.clear(); return; @@ -3443,13 +3481,13 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL msg += tok->str(); } msg = '#' + rawtok->str() + ' ' + msg; - simplecpp::Output err = { + simplecpp::Output err{ rawtok->str() == ERROR ? Output::ERROR : Output::WARNING, rawtok->location, std::move(msg) }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } if (rawtok->str() == ERROR) { output.clear(); @@ -3471,23 +3509,23 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL } } catch (const std::runtime_error &) { if (outputList) { - simplecpp::Output err = { + simplecpp::Output err{ Output::SYNTAX_ERROR, rawtok->location, "Failed to parse #define" }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } output.clear(); return; } catch (const simplecpp::Macro::Error &err) { if (outputList) { - simplecpp::Output out = { + simplecpp::Output out{ simplecpp::Output::SYNTAX_ERROR, err.location, "Failed to parse #define, " + err.what }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } output.clear(); return; @@ -3523,12 +3561,12 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL if (inc2.empty() || inc2.cfront()->str().size() <= 2U) { if (outputList) { - simplecpp::Output err = { + simplecpp::Output err{ Output::SYNTAX_ERROR, rawtok->location, "No header in #include" }; - outputList->push_back(std::move(err)); + outputList->emplace_back(std::move(err)); } output.clear(); return; @@ -3541,21 +3579,21 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL const FileData *const filedata = cache.get(rawtokens.file(rawtok->location), header, dui, systemheader, files, outputList).first; if (filedata == nullptr) { if (outputList) { - simplecpp::Output out = { + simplecpp::Output out{ simplecpp::Output::MISSING_HEADER, rawtok->location, "Header not found: " + inctok->str() }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } } else if (includetokenstack.size() >= 400) { if (outputList) { - simplecpp::Output out = { + simplecpp::Output out{ simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY, rawtok->location, "#include nested too deeply" }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } } else if (pragmaOnce.find(filedata->filename) == pragmaOnce.end()) { includetokenstack.push(gotoNextLine(rawtok)); @@ -3565,26 +3603,27 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL } else if (rawtok->str() == IF || rawtok->str() == IFDEF || rawtok->str() == IFNDEF || rawtok->str() == ELIF) { if (!sameline(rawtok,rawtok->next)) { if (outputList) { - simplecpp::Output out = { + simplecpp::Output out{ simplecpp::Output::SYNTAX_ERROR, rawtok->location, "Syntax error in #" + rawtok->str() }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } output.clear(); return; } bool conditionIsTrue; - if (ifstates.top() == AlwaysFalse || (ifstates.top() == ElseIsTrue && rawtok->str() != ELIF)) + if (ifstates.top() == AlwaysFalse || (ifstates.top() == ElseIsTrue && rawtok->str() != ELIF)) { conditionIsTrue = false; + } else if (rawtok->str() == IFDEF) { conditionIsTrue = (macros.find(rawtok->next->str()) != macros.end() || (hasInclude && rawtok->next->str() == HAS_INCLUDE)); - maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); + maybeUsedMacros[rawtok->next->str()].emplace_back(rawtok->next->location); } else if (rawtok->str() == IFNDEF) { conditionIsTrue = (macros.find(rawtok->next->str()) == macros.end() && !(hasInclude && rawtok->next->str() == HAS_INCLUDE)); - maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); + maybeUsedMacros[rawtok->next->str()].emplace_back(rawtok->next->location); } else { /*if (rawtok->str() == IF || rawtok->str() == ELIF)*/ TokenList expr(files); for (const Token *tok = rawtok->next; tok && tok->location.sameline(rawtok->location); tok = tok->next) { @@ -3598,7 +3637,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL const bool par = (tok && tok->op == '('); if (par) tok = tok->next; - maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); + maybeUsedMacros[rawtok->next->str()].emplace_back(rawtok->next->location); if (tok) { if (macros.find(tok->str()) != macros.end()) expr.push_back(new Token("1", tok->location)); @@ -3611,12 +3650,12 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL tok = tok ? tok->next : nullptr; if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')')) { if (outputList) { - Output out = { + Output out{ Output::SYNTAX_ERROR, rawtok->location, "failed to evaluate " + std::string(rawtok->str() == IF ? "#if" : "#elif") + " condition" }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } output.clear(); return; @@ -3654,12 +3693,12 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL tok = tok ? tok->next : nullptr; if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')') || (!closingAngularBracket)) { if (outputList) { - Output out = { + Output out{ Output::SYNTAX_ERROR, rawtok->location, "failed to evaluate " + std::string(rawtok->str() == IF ? "#if" : "#elif") + " condition" }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } output.clear(); return; @@ -3667,7 +3706,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL continue; } - maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); + maybeUsedMacros[rawtok->next->str()].emplace_back(rawtok->next->location); const Token *tmp = tok; if (!preprocessToken(expr, tmp, macros, files, outputList)) { @@ -3695,12 +3734,12 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL std::string msg = "failed to evaluate " + std::string(rawtok->str() == IF ? "#if" : "#elif") + " condition"; if (e.what() && *e.what()) msg += std::string(", ") + e.what(); - Output out = { + Output out{ Output::SYNTAX_ERROR, rawtok->location, std::move(msg) }; - outputList->push_back(std::move(out)); + outputList->emplace_back(std::move(out)); } output.clear(); return; @@ -3799,7 +3838,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL mu.macroName = macro.name(); mu.macroLocation = macro.defineLocation(); mu.useLocation = *usageIt; - macroUsage->push_back(std::move(mu)); + macroUsage->emplace_back(std::move(mu)); } } } diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h index 9a847d14969..d499b132b69 100644 --- a/externals/simplecpp/simplecpp.h +++ b/externals/simplecpp/simplecpp.h @@ -57,7 +57,9 @@ #ifndef SIMPLECPP_TOKENLIST_ALLOW_PTR // still provide the legacy API in case we lack the performant wrappers # if !defined(__cpp_lib_string_view) && !defined(__cpp_lib_span) -# define SIMPLECPP_TOKENLIST_ALLOW_PTR +# define SIMPLECPP_TOKENLIST_ALLOW_PTR 1 +# else +# define SIMPLECPP_TOKENLIST_ALLOW_PTR 0 # endif #endif @@ -81,7 +83,7 @@ namespace simplecpp { , mSize(strlen(data)) {} - // only provide when std::span is not available so using untyped initilization won't use View + // only provide when std::span is not available so using untyped initialization won't use View #if !defined(__cpp_lib_span) View(const char* data, std::size_t size) : mData(data) @@ -141,7 +143,7 @@ namespace simplecpp { } unsigned int fileIndex{}; - unsigned int line{1}; + unsigned int line{}; unsigned int col{}; }; @@ -267,7 +269,7 @@ namespace simplecpp { TokenList(const unsigned char (&data)[size], std::vector &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr) : TokenList(data, size-1, filenames, filename, outputList, 0) {} -#ifdef SIMPLECPP_TOKENLIST_ALLOW_PTR +#if SIMPLECPP_TOKENLIST_ALLOW_PTR /** generates a token list from the given buffer */ TokenList(const unsigned char* data, std::size_t size, std::vector &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr) : TokenList(data, size, filenames, filename, outputList, 0) @@ -311,6 +313,10 @@ namespace simplecpp { std::string stringify(bool linenrs = false) const; void readfile(Stream &stream, const std::string &filename=std::string(), OutputList *outputList = nullptr); + /** + * @throws std::overflow_error thrown on overflow or division by zero + * @throws std::runtime_error thrown on invalid expressions + */ void constFold(); void removeComments(); diff --git a/externals/tinyxml2/CMakeLists.txt b/externals/tinyxml2/CMakeLists.txt index 9f15c558682..2e1aa036b81 100644 --- a/externals/tinyxml2/CMakeLists.txt +++ b/externals/tinyxml2/CMakeLists.txt @@ -15,6 +15,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") target_compile_options_safe(tinyxml2 -Wno-zero-as-null-pointer-constant) target_compile_options_safe(tinyxml2 -Wno-format-nonliteral) target_compile_options_safe(tinyxml2 -Wno-inconsistent-missing-destructor-override) + target_compile_options_safe(tinyxml2 -Wno-sign-conversion) + target_compile_options_safe(tinyxml2 -Wno-double-promotion) endif() if(CYGWIN) target_compile_definitions(-D_LARGEFILE_SOURCE) # required for fseeko() and ftello() diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 493c6a482d0..d640c341458 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -87,7 +87,7 @@ CheckOptions: add_dependencies(cppcheck-gui run-dmake) endif() - if (BUILD_TESTS) + if (BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/gui/checkstatistics.cpp b/gui/checkstatistics.cpp index 25bee336811..612e79da63b 100644 --- a/gui/checkstatistics.cpp +++ b/gui/checkstatistics.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,8 @@ #include "checkstatistics.h" +#include "utils.h" + #include #include #include @@ -59,7 +61,6 @@ void CheckStatistics::addItem(const QString &tool, ShowTypes::ShowType type) ::addItem(mInformation, lower); break; case ShowTypes::ShowNone: - default: qDebug() << "Unknown error type - not added to statistics."; break; } @@ -99,10 +100,10 @@ unsigned CheckStatistics::getCount(const QString &tool, ShowTypes::ShowType type case ShowTypes::ShowInformation: return mInformation.value(lower,0); case ShowTypes::ShowNone: - default: qDebug() << "Unknown error type - returning zero statistics."; return 0; } + cppcheck::unreachable(); } QStringList CheckStatistics::getTools() const diff --git a/gui/checkthread.cpp b/gui/checkthread.cpp index 8f042068ee9..07ca4e77ed2 100644 --- a/gui/checkthread.cpp +++ b/gui/checkthread.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -105,8 +105,9 @@ int CheckThread::executeCommand(std::string exe, std::vector args, } -CheckThread::CheckThread(ThreadResult &result) : - mResult(result) +CheckThread::CheckThread(ThreadResult &result, int threadIndex) + : mResult(result) + , mThreadIndex(threadIndex) {} void CheckThread::setSettings(const Settings &settings, std::shared_ptr supprs) @@ -147,9 +148,14 @@ void CheckThread::run() while (file && mState == Running) { const std::string& fname = file->spath(); qDebug() << "Checking file" << QString::fromStdString(fname); + + const Details details{ mThreadIndex, QString::fromStdString(fname), QTime::currentTime(), }; + emit startCheck(details); + cppcheck.check(*file); runAddonsAndTools(mSettings, nullptr, QString::fromStdString(fname)); - emit fileChecked(QString::fromStdString(fname)); + + emit finishCheck(details); if (mState == Running) mResult.getNextFile(file); @@ -160,9 +166,15 @@ void CheckThread::run() while (fileSettings && mState == Running) { const std::string& fname = fileSettings->filename(); qDebug() << "Checking file" << QString::fromStdString(fname); + + const Details details{ mThreadIndex, QString::fromStdString(fname), QTime::currentTime(), }; + emit startCheck(details); + cppcheck.check(*fileSettings); runAddonsAndTools(mSettings, fileSettings, QString::fromStdString(fname)); - emit fileChecked(QString::fromStdString(fname)); + + emit finishCheck(details); + if (mState == Running) mResult.getNextFileSettings(fileSettings); @@ -178,7 +190,7 @@ void CheckThread::run() void CheckThread::runAddonsAndTools(const Settings& settings, const FileSettings *fileSettings, const QString &fileName) { - for (const QString& addon : mAddonsAndTools) { + for (const QString& addon : utils::as_const(mAddonsAndTools)) { if (addon == CLANG_ANALYZER || addon == CLANG_TIDY) { if (!fileSettings) continue; @@ -238,7 +250,7 @@ void CheckThread::runAddonsAndTools(const Settings& settings, const FileSettings const std::string &buildDir = settings.buildDir; if (!buildDir.empty()) { - analyzerInfoFile = QString::fromStdString(AnalyzerInformation::getAnalyzerInfoFile(buildDir, fileSettings->filename(), fileSettings->cfg, fileSettings->fileIndex)); + analyzerInfoFile = QString::fromStdString(AnalyzerInformation::getAnalyzerInfoFile(buildDir, fileSettings->sfilename(), fileSettings->cfg, fileSettings->file.fsFileId())); QStringList args2(args); args2.insert(0,"-E"); @@ -291,7 +303,7 @@ void CheckThread::runAddonsAndTools(const Settings& settings, const FileSettings { const QString cmd(clangTidyCmd()); QString debug(cmd.contains(" ") ? ('\"' + cmd + '\"') : cmd); - for (const QString& arg : args) { + for (const QString& arg : utils::as_const(args)) { if (arg.contains(" ")) debug += " \"" + arg + '\"'; else @@ -486,3 +498,4 @@ QString CheckThread::clangTidyCmd() return QString(); } + diff --git a/gui/checkthread.h b/gui/checkthread.h index 4247a45094c..a630ef7fc13 100644 --- a/gui/checkthread.h +++ b/gui/checkthread.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,7 @@ #include #include #include +#include class ThreadResult; @@ -49,7 +50,14 @@ class ThreadResult; class CheckThread : public QThread { Q_OBJECT public: - explicit CheckThread(ThreadResult &result); + struct Details { + int threadIndex; + QString file; + QTime startTime; + }; + +public: + CheckThread(ThreadResult &result, int threadIndex); /** * @brief Set settings for cppcheck @@ -102,8 +110,8 @@ class CheckThread : public QThread { */ void done(); - // NOLINTNEXTLINE(readability-inconsistent-declaration-parameter-name) - caused by generated MOC code - void fileChecked(const QString &file); + void startCheck(CheckThread::Details details); + void finishCheck(CheckThread::Details details); protected: /** @@ -126,6 +134,7 @@ class CheckThread : public QThread { std::atomic mState{Ready}; ThreadResult &mResult; + int mThreadIndex{}; Settings mSettings; std::shared_ptr mSuppressions; @@ -150,5 +159,6 @@ class CheckThread : public QThread { QStringList mClangIncludePaths; QList mSuppressionsUi; }; +Q_DECLARE_METATYPE(CheckThread::Details); /// @} #endif // CHECKTHREAD_H diff --git a/gui/codeeditor.cpp b/gui/codeeditor.cpp index b6d88a061d3..d6c8c1c4071 100644 --- a/gui/codeeditor.cpp +++ b/gui/codeeditor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "codeeditor.h" #include "codeeditorstyle.h" +#include "utils.h" #include #include @@ -133,7 +134,7 @@ Highlighter::Highlighter(QTextDocument *parent, << "volatile" << "wchar_t" << "while"; - for (const QString &pattern : keywordPatterns) { + for (const QString &pattern : utils::as_const(keywordPatterns)) { rule.pattern = QRegularExpression("\\b" + pattern + "\\b"); rule.format = mKeywordFormat; rule.ruleRole = RuleRole::Keyword; @@ -216,7 +217,7 @@ void Highlighter::setStyle(const CodeEditorStyle &newStyle) void Highlighter::highlightBlock(const QString &text) { - for (const HighlightingRule &rule : mHighlightingRulesWithSymbols) { + for (const HighlightingRule &rule : utils::as_const(mHighlightingRulesWithSymbols)) { QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); while (matchIterator.hasNext()) { QRegularExpressionMatch match = matchIterator.next(); diff --git a/gui/codeeditor.h b/gui/codeeditor.h index 1ba8b3fd84d..00205d1c4e1 100644 --- a/gui/codeeditor.h +++ b/gui/codeeditor.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -129,9 +129,9 @@ class CodeEditor : public QPlainTextEdit { void resizeEvent(QResizeEvent *event) override; private slots: - void updateLineNumberAreaWidth(int newBlockCount); + void updateLineNumberAreaWidth(int /*newBlockCount*/); void highlightErrorLine(); - void updateLineNumberArea(const QRect & /*rect*/, int /*dy*/); + void updateLineNumberArea(const QRect& rect, int dy); private: QString generateStyleString(); diff --git a/gui/codeeditorstyle.cpp b/gui/codeeditorstyle.cpp index 0536c4ba4b3..6d7a15fb2f8 100644 --- a/gui/codeeditorstyle.cpp +++ b/gui/codeeditorstyle.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include "codeeditorstyle.h" +#include #include #include diff --git a/gui/codeeditstyledialog.cpp b/gui/codeeditstyledialog.cpp index fa3f0f46f22..44304ddddc1 100644 --- a/gui/codeeditstyledialog.cpp +++ b/gui/codeeditstyledialog.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/gui/codeeditstyledialog.h b/gui/codeeditstyledialog.h index 80b8b06214d..763372cbef6 100644 --- a/gui/codeeditstyledialog.h +++ b/gui/codeeditstyledialog.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ #include #include #include +#include class CodeEditor; class SelectColorButton; diff --git a/gui/compliancereportdialog.cpp b/gui/compliancereportdialog.cpp deleted file mode 100644 index ae903f47dc4..00000000000 --- a/gui/compliancereportdialog.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "compliancereportdialog.h" - -#include "ui_compliancereportdialog.h" - -#include "errortypes.h" -#include "filelist.h" -#include "filesettings.h" -#include "importproject.h" -#include "projectfile.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void addHeaders(const QString& file1, QSet &allFiles) { - if (allFiles.contains(file1)) - return; - QFile file(file1); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - return; - allFiles << file1; - const QRegularExpression re("^#include[ ]*\"([^\">]+)\".*"); - QTextStream in(&file); - QString line = in.readLine(); - while (!in.atEnd()) { - if (line.startsWith("#include")) { - const QRegularExpressionMatch match = re.match(line); - if (match.hasMatch()) { - QString hfile = match.captured(1); - if (file1.contains("/")) - hfile = file1.mid(0,file1.lastIndexOf("/") + 1) + hfile; - addHeaders(hfile, allFiles); - } - } - line = in.readLine(); - } -} - -static std::vector toStdStringList(const QStringList& from) { - std::vector ret; - std::transform(from.cbegin(), from.cend(), std::back_inserter(ret), [](const QString& e) { - return e.toStdString(); - }); - return ret; -} - -ComplianceReportDialog::ComplianceReportDialog(ProjectFile* projectFile, QString resultsFile, QString checkersReport) - : QDialog(nullptr), - mUI(new Ui::ComplianceReportDialog), - mProjectFile(projectFile), - mResultsFile(std::move(resultsFile)), - mCheckersReport(std::move(checkersReport)) -{ - mUI->setupUi(this); - mUI->mEditProjectName->setText(projectFile->getProjectName()); - connect(mUI->buttonBox, &QDialogButtonBox::clicked, this, &ComplianceReportDialog::buttonClicked); - mUI->mCodingStandard->clear(); - if (!projectFile->getCodingStandards().contains("misra-c-2023") && projectFile->getAddons().contains("misra")) - mUI->mCodingStandard->addItem("Misra C 2012"); - for (QString std: projectFile->getCodingStandards()) { - std[0] = std[0].toUpper(); - std = std.replace("-", " ").replace(" c ", " C ").replace(" cpp ", " C++ ").replace(" c++ ", " C++ "); - mUI->mCodingStandard->addItem(std); - } -} - -ComplianceReportDialog::~ComplianceReportDialog() -{ - delete mUI; -} - -void ComplianceReportDialog::buttonClicked(QAbstractButton* button) -{ - switch (mUI->buttonBox->standardButton(button)) { - case QDialogButtonBox::StandardButton::Save: - save(); - break; - case QDialogButtonBox::StandardButton::Close: - close(); - break; - default: - break; - } -} - -void ComplianceReportDialog::save() -{ - const QString std(mUI->mCodingStandard->currentText().toLower().replace(" ", "-")); - - const QString outFile = QFileDialog::getSaveFileName(this, - tr("Compliance report"), - QDir::homePath() + "/" + std + "-compliance-report.html", - tr("HTML files (*.html)")); - if (outFile.isEmpty()) - return; - - close(); - - const QString& projectName = mUI->mEditProjectName->text(); - const QString& projectVersion = mUI->mEditProjectVersion->text(); - const bool files = mUI->mCheckFiles->isChecked(); - - if (projectName != mProjectFile->getProjectName()) { - mProjectFile->setProjectName(projectName); - mProjectFile->write(); - } - - QTemporaryFile tempCheckersReport; - if (tempCheckersReport.open()) { - QTextStream out(&tempCheckersReport); - out << mCheckersReport << "\n"; - tempCheckersReport.close(); - } - - QTemporaryFile tempFiles; - if (files && tempFiles.open()) { - QTextStream out(&tempFiles); - FileList fileList; - fileList.addPathList(mProjectFile->getCheckPaths()); - if (!mProjectFile->getImportProject().isEmpty()) { - QFileInfo inf(mProjectFile->getFilename()); - - QString prjfile; - if (QFileInfo(mProjectFile->getImportProject()).isAbsolute()) - prjfile = mProjectFile->getImportProject(); - else - prjfile = inf.canonicalPath() + '/' + mProjectFile->getImportProject(); - - ImportProject p; - try { - p.import(prjfile.toStdString()); - } catch (InternalError &e) { - QMessageBox msg(QMessageBox::Critical, - tr("Save compliance report"), - tr("Failed to import '%1' (%2), can not show files in compliance report").arg(prjfile).arg(QString::fromStdString(e.errorMessage)), - QMessageBox::Ok, - this); - msg.exec(); - return; - } - - p.ignorePaths(toStdStringList(mProjectFile->getExcludedPaths())); - - QDir dir(inf.absoluteDir()); - for (const FileSettings& fs: p.fileSettings) - fileList.addFile(dir.relativeFilePath(QString::fromStdString(fs.filename()))); - } - - QSet allFiles; - for (const QString &sourcefile: fileList.getFileList()) - addHeaders(sourcefile, allFiles); - for (const QString& fileName: allFiles) { - QFile f(fileName); - if (f.open(QFile::ReadOnly)) { - QCryptographicHash hash(QCryptographicHash::Algorithm::Md5); - if (hash.addData(&f)) { - for (auto b: hash.result()) - out << QString::number(static_cast(b),16); - out << " " << fileName << "\n"; - } - } - } - tempFiles.close(); - } - - QStringList suppressions; - for (const auto& suppression: mProjectFile->getSuppressions()) { - if (!suppression.errorId.empty()) - suppressions.append(QString::fromStdString(suppression.errorId)); - } - - QStringList args{"--project-name=" + projectName, - "--project-version=" + projectVersion, - "--output-file=" + outFile, - "--checkers-report=" + tempCheckersReport.fileName()}; - if (!suppressions.isEmpty()) - args << "--suppressions=" + suppressions.join(","); - - args << ("--" + std); - - if (files) - args << "--files=" + tempFiles.fileName(); - args << mResultsFile; - - const QString appPath = QFileInfo(QCoreApplication::applicationFilePath()).canonicalPath(); - - QProcess process; -#ifdef Q_OS_WIN - process.start(appPath + "/compliance-report.exe", args); -#else - process.start(appPath + "/compliance-report", args); -#endif - process.waitForFinished(); - const QString output = process.readAll(); - if (!output.isEmpty()) { - QMessageBox msg(QMessageBox::Critical, - tr("Save compliance report"), - output, - QMessageBox::Ok, - this); - msg.exec(); - } -} diff --git a/gui/compliancereportdialog.h b/gui/compliancereportdialog.h deleted file mode 100644 index c7ef27f1cc5..00000000000 --- a/gui/compliancereportdialog.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- C++ -*- - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef COMPLIANCEREPORTDIALOG_H -#define COMPLIANCEREPORTDIALOG_H - -#include -#include -#include - -namespace Ui { - class ComplianceReportDialog; -} - -class ProjectFile; -class QAbstractButton; - -class ComplianceReportDialog final : public QDialog -{ - Q_OBJECT - -public: - explicit ComplianceReportDialog(ProjectFile* projectFile, QString resultsFile, QString checkersReport); - ~ComplianceReportDialog() final; - -private slots: - void buttonClicked(QAbstractButton* button); - -private: - void save(); - - Ui::ComplianceReportDialog *mUI; - ProjectFile* mProjectFile; - const QString mResultsFile; - const QString mCheckersReport; -}; - -#endif // COMPLIANCEREPORTDIALOG_H diff --git a/gui/compliancereportdialog.ui b/gui/compliancereportdialog.ui deleted file mode 100644 index b756ec7eab5..00000000000 --- a/gui/compliancereportdialog.ui +++ /dev/null @@ -1,104 +0,0 @@ - - - ComplianceReportDialog - - - - 0 - 0 - 403 - 199 - - - - Compliance Report - - - - - - - - Project version - - - - - - - Project name - - - - - - - - - - - - - Coding Standard - - - - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - - - - - - List of files with md5 checksums - - - true - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close|QDialogButtonBox::Save - - - - - - - - diff --git a/gui/cppcheck_de.ts b/gui/cppcheck_de.ts index 0197f93c728..c0d68ed6d8a 100644 --- a/gui/cppcheck_de.ts +++ b/gui/cppcheck_de.ts @@ -334,40 +334,40 @@ Parameter: -l(line) (file) Bearbeiten - - + + Library files (*.cfg) Bibliotheksdateien (*.cfg) - + Open library file Bibliothek öffnen - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Datei %1 kann nicht geöffnet werden. - + Failed to load %1. %2. %1 kann nicht geladen werden. %2. - + Cannot save file %1. Datei %1 kann nicht gespeichert werden. - + Save the library as Speichere Bibliothek unter @@ -496,25 +496,25 @@ Parameter: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + Standard Standard @@ -534,236 +534,236 @@ Parameter: -l(line) (file) &Symbolleisten - + A&nalyze A&nalysieren - + C++ standard C++-Standard - + &C standard &C-Standard - + &Edit &Bearbeiten - + &License... &Lizenz... - + A&uthors... &Autoren... - + &About... Ü&ber... - + &Files... &Dateien... - - + + Analyze files Analysiere Dateien - + Ctrl+F Strg+F - + &Directory... &Verzeichnis... - - + + Analyze directory Analysiere Verzeichnis - + Ctrl+D Strg+D - + Ctrl+R Strg+R - + &Stop &Stoppen - - + + Stop analysis Analyse abbrechen - + Esc Esc - + &Save results to file... &Ergebnisse in Datei speichern... - + Ctrl+S Strg+S - + &Quit &Beenden - + &Clear results Ergebnisse &löschen - + &Preferences &Einstellungen - - - + + + Show errors Zeige Fehler - - - + + + Show warnings Zeige Warnungen - - + + Show performance warnings Zeige Performance-Warnungen - + Show &hidden Zeige &versteckte - + Information Information - + Show information messages Zeige Informationsmeldungen - + Show portability warnings Zeige Portabilitätswarnungen - + Show Cppcheck results Zeige Cppcheck-Ergebnisse - + Clang Clang - + Show Clang results Zeige Clang-Ergebnisse - + &Filter &Filter - + Filter results Gefilterte Ergebnisse - + Windows 32-bit ANSI Windows 32-bit, ANSI - + Windows 32-bit Unicode Windows 32-bit, Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... Drucken... - + Print the Current Report Aktuellen Bericht ausdrucken - + Print Pre&view... Druckvorschau - + Open a Print Preview Dialog for the Current Results Druckvorschaudialog für aktuelle Ergebnisse öffnen - + Open library editor Bibliothekseditor öffnen - + &Check all Alle &auswählen @@ -779,324 +779,334 @@ Parameter: -l(line) (file) - + Report - + Filter Filter - + &Reanalyze modified files Veränderte Dateien neu analysieren - + Reanal&yze all files Alle Dateien erneut anal&ysieren - + Ctrl+Q - + Style war&nings Stilwar&nungen - + E&rrors F&ehler - + &Uncheck all Alle a&bwählen - + Collapse &all Alle &reduzieren - + &Expand all Alle &erweitern - + &Standard &Standard - + Standard items Standardeinträge - + Toolbar Symbolleiste - + &Categories &Kategorien - + Error categories Fehler-Kategorien - + &Open XML... Öffne &XML... - + Open P&roject File... Pr&ojektdatei öffnen... - + Ctrl+Shift+O - + Sh&ow Scratchpad... &Zeige Schmierzettel... - + &New Project File... &Neue Projektdatei... - + Ctrl+Shift+N - + &Log View &Loganzeige - + Log View Loganzeige - + C&lose Project File Projektdatei &schließen - + &Edit Project File... Projektdatei &bearbeiten... - + &Statistics &Statistik - + &Warnings &Warnungen - + Per&formance warnings Per&formance-Warnungen - + &Information &Information - + &Portability &Portabilität - + P&latforms P&lattformen - + C++&11 C++&11 - + C&99 C&99 - + &Posix Posix - + C&11 C&11 - + &C89 &C89 - + &C++03 &C++03 - + &Library Editor... &Bibliothekseditor - + &Auto-detect language Sprache &automatisch erkennen - + &Enforce C++ C++ &erzwingen - + E&nforce C C e&rzwingen - + C++14 C++14 - + Reanalyze and check library Neu analysieren und Bibliothek prüfen - + Check configuration (defines, includes) Prüfe Konfiguration (Definitionen, Includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal - + Misra C Misra C - + Misra C++ 2008 - + Cert C Cert C - + Cert C++ Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents &Inhalte - + Categories Kategorien - - + + Show style warnings Zeige Stilwarnungen - + Open the help contents Öffnet die Hilfe-Inhalte - + F1 F1 - + &Help &Hilfe - - + + Quick Filter: Schnellfilter: - + Select configuration Konfiguration wählen - + Found project file: %1 Do you want to load this project file instead? @@ -1105,37 +1115,37 @@ Do you want to load this project file instead? Möchten Sie stattdessen diese öffnen? - + File not found Datei nicht gefunden - + Bad XML Fehlerhaftes XML - + Missing attribute Fehlendes Attribut - + Bad attribute value Falscher Attributwert - + Duplicate platform type Plattformtyp doppelt - + Platform type redefined Plattformtyp neu definiert - + Duplicate define @@ -1157,50 +1167,50 @@ Möchten Sie stattdessen diese öffnen? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Lizenz - + Authors Autoren - + Save the report file Speichert die Berichtdatei - - + + XML files (*.xml) XML-Dateien (*.xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -1209,37 +1219,38 @@ This is probably because the settings were changed between the Cppcheck versions Dies wurde vermutlich durch einen Wechsel der Cppcheck-Version hervorgerufen. Bitte prüfen (und korrigieren) Sie die Einstellungen, andernfalls könnte die Editor-Anwendung nicht korrekt starten. - + You must close the project file before selecting new files or directories! Sie müssen die Projektdatei schließen, bevor Sie neue Dateien oder Verzeichnisse auswählen! - + The library '%1' contains unknown elements: %2 Die Bibliothek '%1' enthält unbekannte Elemente: %2 - + Unsupported format Nicht unterstütztes Format - + Unknown element Unbekanntes Element - Unknown issue - Unbekannter Fehler + Unknown element + Unknown issue + Unbekannter Fehler - - - - + + + + Error Fehler @@ -1248,80 +1259,80 @@ Dies wurde vermutlich durch einen Wechsel der Cppcheck-Version hervorgerufen. Bi Laden von %1 fehlgeschlagen. Ihre Cppcheck-Installation ist defekt. Sie können --data-dir=<Verzeichnis> als Kommandozeilenparameter verwenden, um anzugeben, wo die Datei sich befindet. Bitte beachten Sie, dass --data-dir in Installationsroutinen genutzt werden soll, und die GUI bei dessen Nutzung nicht startet, sondern die Einstellungen konfiguriert. - + Open the report file Berichtdatei öffnen - + Text files (*.txt) Textdateien (*.txt) - + CSV files (*.csv) CSV-Dateien (*.csv) - + Project files (*.cppcheck);;All files(*.*) Projektdateien (*.cppcheck);;Alle Dateien(*.*) - + Select Project File Projektdatei auswählen - - - - + + + + Project: Projekt: - + No suitable files found to analyze! Keine passenden Dateien für Analyse gefunden! - + C/C++ Source C/C++-Quellcode - + Compile database Compilerdatenbank - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++-Builder 6 - + Select files to analyze Dateien für Analyse auswählen - + Select directory to analyze Verzeichnis für Analyse auswählen - + Select the configuration that will be analyzed Zu analysierende Konfiguration auswählen - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1330,7 +1341,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1341,7 +1352,7 @@ Eine neue XML-Datei zu öffnen wird die aktuellen Ergebnisse löschen Möchten sie fortfahren? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1350,109 +1361,109 @@ Do you want to stop the analysis and exit Cppcheck? Wollen sie die Analyse abbrechen und Cppcheck beenden? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML-Dateien (*.xml);;Textdateien (*.txt);;CSV-Dateien (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? Erstellungsverzeichnis '%1' existiert nicht. Erstellen? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1461,22 +1472,22 @@ Analysis is stopped. Import von '%1' fehlgeschlagen; Analyse wurde abgebrochen. - + Project files (*.cppcheck) Projektdateien (*.cppcheck) - + Select Project Filename Projektnamen auswählen - + No project file loaded Keine Projektdatei geladen - + The project file %1 @@ -1493,12 +1504,12 @@ Do you want to remove the file from the recently used projects -list? Möchten Sie die Datei von der Liste der zuletzt benutzten Projekte entfernen? - + Install - + New version available: %1. %2 @@ -1847,12 +1858,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools Externe Werkzeuge @@ -1974,17 +1990,17 @@ Options: Cert C++ - + Bug hunting (Premium) - + Clang analyzer Clang-Analyzer - + Clang-tidy Clang-Tidy @@ -1997,82 +2013,82 @@ Options: ProjectFileDialog - + Project file: %1 Projektdatei: %1 - + Select Cppcheck build dir Wähle Cppcheck-Erstellungsverzeichnis - + Select include directory Wähle Include-Verzeichnisse - + Select a directory to check Wähle zu prüfendes Verzeichnis - + Note: Open source Cppcheck does not fully implement Misra C 2012 Hinweis: Open-Source Cppcheck implementiert Misra C 2012 nicht vollständig - + Clang-tidy (not found) Clang-tidy (nicht gefunden) - + Visual Studio Visual Studio - + Compile database Compilerdatenbank - + Borland C++ Builder 6 Borland C++-Builder 6 - + Import Project Projekt importieren - + Select directory to ignore Wähle zu ignorierendes Verzeichnis - + Source files Quelltext-Dateien - + All files Alle Dateien - + Exclude file Datei ausschließen - + Select MISRA rule texts file Wähle MISRA-Regeltext-Datei - + MISRA rule texts file (%1) MISRA-Regeltext-Datei (%1) @@ -2105,7 +2121,7 @@ Options: - + (Not found) (nicht gefunden) @@ -2155,157 +2171,157 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Klassen-Vordergrundfarbe - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File Datei - + Line Zeile - + Severity Schweregrad - + Classification - + Level - + Inconclusive Unklar - + Summary Zusammenfassung - + Id Id - + Guideline - + Rule - + Since date Seit Datum - + Tags - + CWE @@ -2356,88 +2372,88 @@ Options: Undefinierte Datei - + Copy Kopieren - + Could not find file: Kann Datei nicht finden: - + Please select the folder '%1' Bitte wählen Sie den Ordner '%1' - + Select Directory '%1' Wähle Verzeichnis '%1' - + Please select the directory where file is located. Bitte wählen Sie das Verzeichnis, in dem sich die Datei befindet. - + debug Debug - + note Anmerkung - + Hide all with id Verstecke alle mit gleicher ID - + Suppress selected id(s) Ausgewählte ID(s) unterdrücken - + Open containing folder Übergeordneten Ordner öffnen - + internal Intern - + Recheck %1 file(s) Erneut %1 Datei(en) prüfen - + Hide %1 result(s) Verstecke %1 Ergebnis(se) - + Tag Tag - + No tag Kein Tag - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2446,7 +2462,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2455,12 +2471,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! Datei konnte nicht gefunden werden! - + Could not start %1 Please check the application path and parameters are correct. @@ -2469,37 +2485,37 @@ Please check the application path and parameters are correct. Bitte überprüfen Sie ob der Pfad und die Parameter der Anwendung richtig eingestellt sind. - + Select Directory Wähle Verzeichnis - + style Stil - + error Fehler - + warning Warnung - + performance Performance - + portability Portabilität - + information Information @@ -3166,10 +3182,18 @@ Legen Sie unter dem Menü Ansicht fest, welche Arten von Fehlern angezeigt werde Informationsmeldungen + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %1 von %2 Dateien geprüft diff --git a/gui/cppcheck_es.ts b/gui/cppcheck_es.ts index 2283e346285..927a56e05e5 100644 --- a/gui/cppcheck_es.ts +++ b/gui/cppcheck_es.ts @@ -322,42 +322,42 @@ Parameters: -l(line) (file) Editar - - + + Library files (*.cfg) Archivos de biblioteca (*.cfg) - + Open library file Abrir archivo de biblioteca - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. - + Failed to load %1. %2. - + Cannot save file %1. Can not save file %1. - + Save the library as @@ -476,20 +476,20 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck @@ -509,238 +509,238 @@ Parameters: -l(line) (file) &Herramientas - + &Help &Ayuda - + C++ standard C++ estándar - + &C standard C standard C estándar - + &Edit &Editar - + Standard Estándar - + Categories Categorías - + &License... &Licencia... - + A&uthors... A&utores... - + &About... &Acerca de... - + &Files... &Ficheros... - - + + Analyze files Check files Comprobar archivos - + Ctrl+F Ctrl+F - + &Directory... &Carpeta... - - + + Analyze directory Check directory Comprobar carpeta - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop &Detener - - + + Stop analysis Stop checking Detener comprobación - + Esc Esc - + &Save results to file... &Guardar los resultados en el fichero... - + Ctrl+S Ctrl+S - + &Quit &Salir - + &Clear results &Limpiar resultados - + &Preferences &Preferencias - - + + Show style warnings Mostrar advertencias de estilo - - - + + + Show errors Mostrar errores - + Information Información - + Show information messages Mostrar mensajes de información - + Show portability warnings Mostrar advertencias de portabilidad - + Show Cppcheck results - + Clang - + Show Clang results - + &Filter &Filtro - + Filter results Resultados del filtro - + Windows 32-bit ANSI Windows 32-bit ANSI - + Windows 32-bit Unicode Windows 32-bit Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... Im&primir... - + Print the Current Report Imprimir el informe actual - + Print Pre&view... Pre&visualización de impresión... - + Open a Print Preview Dialog for the Current Results Abre el diálogo de previsualización de impresión para el informe actual - + Open library editor Abrir el editor de bibliotecas - + &Check all &Seleccionar todo @@ -756,363 +756,373 @@ Parameters: -l(line) (file) - + Report - + A&nalyze - + Filter Filtro - + &Reanalyze modified files &Recheck modified files - + Reanal&yze all files - + Ctrl+Q - + Style war&nings - + E&rrors - + &Uncheck all &Deseleccionar todo - + Collapse &all Contraer &todo - + &Expand all &Expandir todo - + &Standard &Estándar - + Standard items Elementos estándar - + &Contents &Contenidos - + Open the help contents Abrir la ayuda de contenidos - + F1 F1 - + Toolbar Barra de herramientas - + &Categories &Categorías - + Error categories Categorías de error - + &Open XML... &Abrir XML... - + Open P&roject File... Abrir P&royecto... - + Ctrl+Shift+O - + Sh&ow Scratchpad... - + &New Project File... &Nuevo Proyecto... - + Ctrl+Shift+N - + &Log View &Visor del log - + Log View Visor del log - + C&lose Project File C&errar Proyecto - + &Edit Project File... &Editar Proyecto... - + &Statistics &Estadísticas - + &Warnings - + Per&formance warnings - + &Information - + &Portability - + P&latforms - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... - + &Auto-detect language - + &Enforce C++ - + E&nforce C - + C++14 C++14 - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - - - + + Thread Details + + + + + Show thread details + + + + + + Show warnings Mostrar advertencias - - + + Show performance warnings Mostrar advertencias de rendimiento - + Show &hidden Mostrar &ocultos - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. - + You must close the project file before selecting new files or directories! ¡Tienes que cerrar el proyecto antes de seleccionar nuevos ficheros o carpetas! - + Select configuration - + File not found Archivo no encontrado - + Bad XML XML malformado - + Missing attribute Falta el atributo - + Bad attribute value - + Unsupported format Formato no soportado - + Duplicate define @@ -1133,61 +1143,61 @@ This is probably because the settings were changed between the Cppcheck versions - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - - + + XML files (*.xml) Archivos XML (*.xml) - + Open the report file Abrir informe - + License Licencia - + Authors Autores - + Save the report file Guardar informe - - + + Quick Filter: Filtro rápido: - + Found project file: %1 Do you want to load this project file instead? @@ -1196,117 +1206,118 @@ Do you want to load this project file instead? ¿Quiere cargar este fichero de proyecto en su lugar? - + The library '%1' contains unknown elements: %2 La biblioteca '%1' contiene elementos deconocidos: %2 - + Duplicate platform type - + Platform type redefined - + Unknown element - Unknown issue + Unknown element + Unknown issue - - - - + + + + Error Error - + Text files (*.txt) Ficheros de texto (*.txt) - + CSV files (*.csv) Ficheros CVS (*.cvs) - + Project files (*.cppcheck);;All files(*.*) Ficheros de proyecto (*.cppcheck;;Todos los ficheros (*.*) - + Select Project File Selecciona el archivo de proyecto - - - - + + + + Project: Proyecto: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1314,81 +1325,81 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename Selecciona el nombre del proyecto - + No project file loaded No hay ningún proyecto cargado - + The project file %1 @@ -1405,67 +1416,67 @@ Do you want to remove the file from the recently used projects -list? ¿Quiere eliminar el fichero de la lista de proyectos recientes? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1822,12 +1833,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools @@ -1938,17 +1954,17 @@ Options: - + Bug hunting (Premium) - + Clang analyzer - + Clang-tidy @@ -1961,82 +1977,82 @@ Options: ProjectFileDialog - + Project file: %1 Archivo de proyecto: %1 - + Select Cppcheck build dir - + Select include directory Selecciona una carpeta para incluir - + Select a directory to check Selecciona la carpeta a comprobar - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) - + Visual Studio - + Compile database - + Borland C++ Builder 6 - + Import Project - + Select directory to ignore Selecciona la carpeta a ignorar - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) @@ -2069,7 +2085,7 @@ Options: - + (Not found) @@ -2119,158 +2135,158 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Class ForegroundColor - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File Archivo - + Line Línea - + Severity Severidad - + Classification - + Level - + Inconclusive - + Summary Resumen - + Id Id - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2321,47 +2337,47 @@ Options: Fichero no definido - + Copy - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + portability portabilidad - + note - + information información - + debug depuración @@ -2370,53 +2386,53 @@ Options: Ocultar - + Hide all with id Ocultar todos con el mismo id - + Suppress selected id(s) - + Open containing folder Abrir carpeta contenedora - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag - + No tag - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2426,7 +2442,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2435,12 +2451,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! ¡No se ha encontrado el fichero! - + Could not start %1 Please check the application path and parameters are correct. @@ -2449,7 +2465,7 @@ Please check the application path and parameters are correct. Por favor comprueba que la ruta a la aplicación y los parámetros son correctos. - + Select Directory Selecciona carpeta @@ -2458,22 +2474,22 @@ Por favor comprueba que la ruta a la aplicación y los parámetros son correctos Id - + style estilo - + error error - + warning advertencia - + performance ajuste @@ -3140,10 +3156,18 @@ Para cambiar el tipo de comportamiento, abra el menú Ver. Mensajes de información + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %1 de %2 archivos comprobados diff --git a/gui/cppcheck_fi.ts b/gui/cppcheck_fi.ts index d6ad561fd33..f6c959aa099 100644 --- a/gui/cppcheck_fi.ts +++ b/gui/cppcheck_fi.ts @@ -325,42 +325,42 @@ Parameters: -l(line) (file) - - + + Library files (*.cfg) - + Open library file - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. - + Failed to load %1. %2. - + Cannot save file %1. Can not save file %1. - + Save the library as @@ -479,30 +479,30 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + A&nalyze - + Standard Vakio @@ -522,235 +522,235 @@ Parameters: -l(line) (file) - + C++ standard - + &C standard C standard - + &Edit &Muokkaa - + &License... &Lisenssi... - + A&uthors... &Tekijät... - + &About... &Tietoa ohjelmasta Cppcheck... - + &Files... &Tiedostot... - - + + Analyze files Check files - + Ctrl+F Ctrl+F - + &Directory... &Hakemisto... - - + + Analyze directory Check directory - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop &Pysäytä - - + + Stop analysis Stop checking - + Esc Esc - + &Save results to file... &Tallenna tulokset tiedostoon... - + Ctrl+S Ctrl+S - + &Quit &Lopeta - + &Clear results &Tyhjennä tulokset - + &Preferences &Asetukset - - - + + + Show errors - - - + + + Show warnings - - + + Show performance warnings - + Show &hidden - + Information - + Show information messages - + Show portability warnings - + Show Cppcheck results - + Clang - + Show Clang results - + &Filter - + Filter results - + Windows 32-bit ANSI - + Windows 32-bit Unicode - + Unix 32-bit - + Unix 64-bit - + Windows 64-bit - + &Print... - + Print the Current Report - + Print Pre&view... - + Open a Print Preview Dialog for the Current Results - + Open library editor - + &Check all &Valitse kaikki @@ -766,352 +766,362 @@ Parameters: -l(line) (file) - + Report - + Filter - + &Reanalyze modified files &Recheck modified files - + Reanal&yze all files - + Ctrl+Q - + Style war&nings - + E&rrors - + &Uncheck all &Poista kaikista valinta - + Collapse &all &Pienennä kaikki - + &Expand all &Laajenna kaikki - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + Ctrl+Shift+O - + Sh&ow Scratchpad... - + &New Project File... - + Ctrl+Shift+N - + &Log View - + Log View - + C&lose Project File - + &Edit Project File... - + &Statistics - + &Warnings - + Per&formance warnings - + &Information - + &Portability - + P&latforms - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... - + &Auto-detect language - + &Enforce C++ - + E&nforce C - + C++14 - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 - + C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents - + Categories - - + + Show style warnings - + Open the help contents - + F1 - + &Help &Ohje - - + + Quick Filter: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Duplicate define @@ -1132,181 +1142,182 @@ Do you want to load this project file instead? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Lisenssi - + Authors Tekijät - + Save the report file Tallenna raportti - - + + XML files (*.xml) XML-tiedostot (*xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. - + You must close the project file before selecting new files or directories! - + The library '%1' contains unknown elements: %2 - + Unsupported format - + Duplicate platform type - + Platform type redefined - + Unknown element - Unknown issue + Unknown element + Unknown issue - - - - + + + + Error - + Open the report file - + Text files (*.txt) Tekstitiedostot (*.txt) - + CSV files (*.csv) - + Project files (*.cppcheck);;All files(*.*) - + Select Project File - - - - + + + + Project: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1314,81 +1325,81 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename - + No project file loaded - + The project file %1 @@ -1399,67 +1410,67 @@ Do you want to remove the file from the recently used projects -list? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1805,12 +1816,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools @@ -1932,17 +1948,17 @@ Options: - + Bug hunting (Premium) - + Clang analyzer - + Clang-tidy @@ -1955,82 +1971,82 @@ Options: ProjectFileDialog - + Project file: %1 - + Select Cppcheck build dir - + Select include directory - + Select a directory to check - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) - + Visual Studio - + Compile database - + Borland C++ Builder 6 - + Import Project - + Select directory to ignore - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) @@ -2065,7 +2081,7 @@ Options: - + (Not found) @@ -2115,158 +2131,158 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Class ForegroundColor - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File Tiedosto - + Line Rivi - + Severity Tyyppi - + Classification - + Level - + Inconclusive - + Summary - + Id - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2313,88 +2329,88 @@ Options: Määrittelemätön tiedosto - + Copy - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + debug - + note - + Hide all with id - + Suppress selected id(s) - + Open containing folder - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag - + No tag - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2402,19 +2418,19 @@ Configure the editor application for Cppcheck in preferences/Applications.Voit asetuksista määritellä muita ohjelmia joilla avata tämän virheen sisältävän tiedoston. - + No default editor application selected. Please select the default editor application in preferences/Applications. - + Could not find the file! - + Could not start %1 Please check the application path and parameters are correct. @@ -2423,37 +2439,37 @@ Please check the application path and parameters are correct. Tarkista että ohjelman polku ja parametrit ovat oikeat. - + Select Directory - + style Tyyli - + error Yleinen - + warning - + performance - + portability - + information @@ -3113,10 +3129,18 @@ Määrittääksesi minkä tyyppisiä virheitä näytetään, avaa näkymä valik + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked diff --git a/gui/cppcheck_fr.ts b/gui/cppcheck_fr.ts index 45ee1549a62..82e0ea2bf74 100644 --- a/gui/cppcheck_fr.ts +++ b/gui/cppcheck_fr.ts @@ -313,13 +313,13 @@ Paramètres : -l(ligne) (fichier) Editer - - + + Library files (*.cfg) - + Open library file @@ -344,29 +344,29 @@ Paramètres : -l(ligne) (fichier) - - - + + + Cppcheck - + Save the library as - + Failed to load %1. %2. - + Cannot open file %1. - + Cannot save file %1. @@ -485,20 +485,20 @@ Paramètres : -l(ligne) (fichier) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck @@ -524,213 +524,223 @@ Paramètres : -l(ligne) (fichier) - + Report - + &Help &Aide - + &Edit &Édition - + Standard Standard - + &License... &Licence... - + A&uthors... A&uteurs... - + &About... À &Propos... - + &Files... &Fichiers... - + Ctrl+F - + &Directory... &Répertoires... - + Ctrl+D - + Ctrl+R - + &Stop &Arrêter - + Esc - + &Save results to file... &Sauvegarder les résultats dans un fichier... - + Ctrl+S - + &Quit &Quitter - + &Clear results &Effacer les résultats - + &Preferences &Préférences - + &Check all &Tout cocher - + &Uncheck all &Tout décocher - + Collapse &all &Tout réduire - + &Expand all &Tout dérouler - + &Contents &Contenus - + Open the help contents Ouvir l'aide - + F1 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + License Licence - + Authors Auteurs - + Save the report file Sauvegarder le rapport - - + + XML files (*.xml) Fichiers XML (*.xml) - + About - + Text files (*.txt) Fichiers Texte (*.txt) - + CSV files (*.csv) Fichiers CSV (*.csv) @@ -740,294 +750,294 @@ Paramètres : -l(ligne) (fichier) &Boite à outils - + Categories Catégories - - + + Show style warnings Afficher les avertissements de style - - - + + + Show errors Afficher les erreurs - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... &Ouvrir un fichier XML... - + Open P&roject File... Ouvrir un P&rojet... - + &New Project File... &Nouveau Projet... - + &Log View &Journal - + Log View Journal - + C&lose Project File F&ermer le projet - + &Edit Project File... &Editer le projet - + &Statistics Statistiques - - - + + + Show warnings Afficher les avertissements - - + + Show performance warnings Afficher les avertissements de performance - + Show &hidden - + Information Information - + Show information messages Afficher les messages d'information - + Show portability warnings Afficher les problèmes de portabilité - + You must close the project file before selecting new files or directories! Vous devez d'abord fermer le projet avant de choisir des fichiers/répertoires - + Open the report file Ouvrir le rapport - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Select Project Filename - + No project file loaded - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. - + &Filter &Filtre - + Filter results - - + + Quick Filter: Filtre rapide : - + Found project file: %1 Do you want to load this project file instead? - - - - + + + + Project: Projet : - + The project file %1 @@ -1038,32 +1048,32 @@ Do you want to remove the file from the recently used projects -list? - + Filter Filtre - + Windows 32-bit ANSI - + Windows 32-bit Unicode - + Unix 32-bit - + Unix 64-bit - + Windows 64-bit @@ -1073,35 +1083,35 @@ Do you want to remove the file from the recently used projects -list? - + C++ standard - - - - + + + + Error Erreur - + File not found Fichier introuvable - + Bad XML Mauvais fichier XML - + Missing attribute Attribut manquant - + Bad attribute value Mauvaise valeur d'attribut @@ -1113,64 +1123,65 @@ Do you want to remove the file from the recently used projects -list? %2 - + Unsupported format Format non supporté - + The library '%1' contains unknown elements: %2 La bibliothèque '%1' contient des éléments inconnus: %2 - + Duplicate platform type - + Platform type redefined - + &Print... &Imprimer... - + Print the Current Report Imprimer le rapport - + Print Pre&view... Apercu d'impression... - + Open a Print Preview Dialog for the Current Results - + Open library editor - + Unknown element - Unknown issue + Unknown element + Unknown issue - + Select configuration @@ -1193,67 +1204,67 @@ Options: - + Build dir '%1' does not exist, create it? - - + + Analyze files - - + + Analyze directory - + &Reanalyze modified files - - + + Stop analysis - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + No suitable files found to analyze! - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Duplicate define @@ -1268,221 +1279,221 @@ Do you want to proceed analysis without using any of these project files? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + A&nalyze - + &C standard - + Reanal&yze all files - + Ctrl+Q - + Style war&nings - + E&rrors - + Ctrl+Shift+O - + Sh&ow Scratchpad... - + Ctrl+Shift+N - + &Warnings - + Per&formance warnings - + &Information - + &Portability - + Show Cppcheck results - + Clang - + Show Clang results - + P&latforms - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... - + &Auto-detect language - + &Enforce C++ - + E&nforce C - + C++14 - + Project files (*.cppcheck) - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 - + C++20 - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1736,17 +1747,17 @@ Do you want to proceed? - + Bug hunting - + Clang analyzer - + Clang-tidy @@ -1899,12 +1910,17 @@ Do you want to proceed? - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting (Premium) - + External tools @@ -1944,82 +1960,82 @@ Do you want to proceed? ProjectFileDialog - + Project file: %1 Fichier projet : %1 - + Select include directory Selectionner un répertoire à inclure - + Select directory to ignore Selectionner un répertoire à ignorer - + Select a directory to check Selectionner un répertoire à vérifier - + Select Cppcheck build dir - + Import Project - + Clang-tidy (not found) - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) - + Visual Studio - + Compile database - + Borland C++ Builder 6 @@ -2052,7 +2068,7 @@ Do you want to proceed? - + (Not found) @@ -2102,157 +2118,157 @@ Do you want to proceed? - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + Class Foreground Color - + File Fichier - + Line Ligne - + Severity Sévérité - + Classification - + Level - + Inconclusive - + Summary Résumé - + Id Id - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2299,13 +2315,13 @@ Do you want to proceed? Fichier indéterminé - - + + Cppcheck - + Could not start %1 Please check the application path and parameters are correct. @@ -2314,12 +2330,12 @@ Please check the application path and parameters are correct. Merci de vérifier que le chemin de l'application et que les paramètres sont corrects. - + style erreur de style - + error erreur @@ -2332,64 +2348,64 @@ Merci de vérifier que le chemin de l'application et que les paramètres so Cacher - + Could not find the file! Fichier introuvable ! - + Select Directory Selectionner dossier - + warning avertissement - + performance performance - + portability portabilité - + information information - + debug débogage - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2400,12 +2416,12 @@ Please select the default editor application in preferences/Applications.Id - + Hide all with id - + Open containing folder Ouvrir l'emplacement du fichier @@ -2414,47 +2430,47 @@ Please select the default editor application in preferences/Applications.Revérifier - + note - + Suppress selected id(s) - + Tag - + No tag - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + Copy @@ -3113,10 +3129,18 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked diff --git a/gui/cppcheck_it.ts b/gui/cppcheck_it.ts index 811150c9257..1c8829bb198 100644 --- a/gui/cppcheck_it.ts +++ b/gui/cppcheck_it.ts @@ -334,42 +334,42 @@ Parametri: -l(line) (file) Modifica - - + + Library files (*.cfg) - + Open library file - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. - + Failed to load %1. %2. - + Cannot save file %1. Can not save file %1. - + Save the library as @@ -488,30 +488,30 @@ Parametri: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + A&nalyze - + Standard Standard @@ -531,235 +531,235 @@ Parametri: -l(line) (file) &Barre degli strumenti - + C++ standard - + &C standard C standard - + &Edit &Modifica - + &License... &Licenza... - + A&uthors... A&utori... - + &About... I&nformazioni su... - + &Files... &File... - - + + Analyze files Check files Scansiona i file - + Ctrl+F Ctrl+F - + &Directory... &Cartella... - - + + Analyze directory Check directory Scansiona la cartella - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop &Ferma - - + + Stop analysis Stop checking Ferma la scansione - + Esc Esc - + &Save results to file... &Salva i risultati nel file... - + Ctrl+S Ctrl+S - + &Quit &Esci - + &Clear results &Cancella i risultati - + &Preferences &Preferenze - - - + + + Show errors Mostra gli errori - - - + + + Show warnings Mostra gli avvisi - - + + Show performance warnings Mostra gli avvisi sulle prestazioni - + Show &hidden Mostra &i nascosti - + Information Informazione - + Show information messages Mostra messaggi di informazione - + Show portability warnings Mostra gli avvisi sulla portabilità - + Show Cppcheck results - + Clang - + Show Clang results - + &Filter &Filtro - + Filter results Filtra i risultati - + Windows 32-bit ANSI Windows 32-bit, ANSI - + Windows 32-bit Unicode Windows 32-bit, Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... - + Print the Current Report - + Print Pre&view... - + Open a Print Preview Dialog for the Current Results - + Open library editor - + &Check all &Seleziona tutto @@ -775,325 +775,335 @@ Parametri: -l(line) (file) - + Report - + Filter Filtro - + &Reanalyze modified files &Recheck modified files - + Reanal&yze all files - + Ctrl+Q - + Style war&nings - + E&rrors - + &Uncheck all &Deseleziona tutto - + Collapse &all Riduci &tutto - + &Expand all &Espandi tutto - + &Standard &Standard - + Standard items Oggetti standard - + Toolbar Barra degli strumenti - + &Categories &Categorie - + Error categories Categorie di errore - + &Open XML... &Apri XML... - + Open P&roject File... Apri file di p&rogetto... - + Ctrl+Shift+O - + Sh&ow Scratchpad... - + &New Project File... &Nuovo file di progetto... - + Ctrl+Shift+N - + &Log View &Visualizza il rapporto - + Log View Visualizza il rapporto - + C&lose Project File C&hiudi il file di progetto - + &Edit Project File... &Modifica il file di progetto... - + &Statistics &Statistiche - + &Warnings - + Per&formance warnings - + &Information - + &Portability - + P&latforms - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... - + &Auto-detect language - + &Enforce C++ - + E&nforce C - + C++14 C++14 - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents &Contenuti - + Categories Categorie - - + + Show style warnings Mostra gli avvisi sullo stile - + Open the help contents Apri i contenuti di aiuto - + F1 F1 - + &Help &Aiuto - - + + Quick Filter: Rapido filtro: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? @@ -1102,32 +1112,32 @@ Do you want to load this project file instead? Vuoi piuttosto caricare questo file di progetto? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Unsupported format - + Duplicate define @@ -1148,50 +1158,50 @@ Vuoi piuttosto caricare questo file di progetto? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Licenza - + Authors Autori - + Save the report file Salva il file di rapporto - - + + XML files (*.xml) File XML (*.xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -1200,126 +1210,127 @@ This is probably because the settings were changed between the Cppcheck versions Probabilmente ciò è avvenuto perché le impostazioni sono state modificate tra le versioni di Cppcheck. Per favore controlla (e sistema) le impostazioni delle applicazioni editor, altrimenti il programma editor può non partire correttamente. - + You must close the project file before selecting new files or directories! Devi chiudere il file di progetto prima di selezionare nuovi file o cartelle! - + The library '%1' contains unknown elements: %2 - + Duplicate platform type - + Platform type redefined - + Unknown element - Unknown issue + Unknown element + Unknown issue - - - - + + + + Error - + Open the report file Apri il file di rapporto - + Text files (*.txt) File di testo (*.txt) - + CSV files (*.csv) Files CSV (*.csv) - + Project files (*.cppcheck);;All files(*.*) Files di progetto (*.cppcheck);;Tutti i files(*.*) - + Select Project File Seleziona il file di progetto - - - - + + + + Project: Progetto: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1327,81 +1338,81 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename Seleziona il nome del file di progetto - + No project file loaded Nessun file di progetto caricato - + The project file %1 @@ -1418,67 +1429,67 @@ Do you want to remove the file from the recently used projects -list? Vuoi rimuovere il file dalla lista dei progetti recentemente usati? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1835,12 +1846,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools @@ -1951,17 +1967,17 @@ Options: - + Bug hunting (Premium) - + Clang analyzer - + Clang-tidy @@ -1974,82 +1990,82 @@ Options: ProjectFileDialog - + Project file: %1 File di progetto: %1 - + Select Cppcheck build dir - + Select include directory Seleziona la cartella da includere - + Select a directory to check Seleziona una cartella da scansionare - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) - + Visual Studio - + Compile database - + Borland C++ Builder 6 - + Import Project - + Select directory to ignore Seleziona la cartella da ignorare - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) @@ -2082,7 +2098,7 @@ Options: - + (Not found) @@ -2132,158 +2148,158 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Class ForegroundColor - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File File - + Line Linea - + Severity Severità - + Classification - + Level - + Inconclusive - + Summary Riassunto - + Id Id - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2334,37 +2350,37 @@ Options: File indefinito - + Copy - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + debug debug - + note @@ -2373,53 +2389,53 @@ Options: Nascondi - + Hide all with id - + Suppress selected id(s) - + Open containing folder - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag - + No tag - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2428,7 +2444,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2437,12 +2453,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! Non è stato possibile trovare il file! - + Could not start %1 Please check the application path and parameters are correct. @@ -2451,7 +2467,7 @@ Please check the application path and parameters are correct. Per favore verifica che il percorso dell'applicazione e i parametri siano corretti. - + Select Directory Seleziona Cartella @@ -2460,32 +2476,32 @@ Per favore verifica che il percorso dell'applicazione e i parametri siano c Id - + style stile - + error errore - + warning avviso - + performance performance - + portability portabilità - + information Informazione @@ -3152,10 +3168,18 @@ Per vedere il tipo di errori che sono mostrati, apri il menu Visualizza.Messaggi di informazione + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %1 su %2 file scansionati diff --git a/gui/cppcheck_ja.ts b/gui/cppcheck_ja.ts index 461f1ef3f07..3e486f416dd 100644 --- a/gui/cppcheck_ja.ts +++ b/gui/cppcheck_ja.ts @@ -337,42 +337,42 @@ Parameters: -l(line) (file) 編集 - - + + Library files (*.cfg) ライブラリファイル(*.cfg) - + Open library file ライブラリファイルを開く - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. ファイルが見つかりません %1。 - + Failed to load %1. %2. 読み込みに失敗しました(%1.%2)。 - + Cannot save file %1. Can not save file %1. ファイルが保存できません %1。 - + Save the library as このライブラリに名前をつけて保存する @@ -502,20 +502,20 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck @@ -535,271 +535,271 @@ Parameters: -l(line) (file) ツールバー(&T) - + &Help ヘルプ(&H) - + C++ standard C++標準 - + &C standard C standard &C標準 - + &Edit 編集(&E) - + Standard 言語規格 - + Categories カテゴリ - + &License... ライセンス(&L)... - + A&uthors... 作者(&u)... - + &About... Cppcheckについて(&A)... - + &Files... ファイル選択(&F)... - - + + Analyze files Check files ファイルをチェックする - + Ctrl+F Ctrl+F - + &Directory... ディレクトリ選択(&D)... - - + + Analyze directory Check directory ディレクトリをチェックする - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop 停止(&S) - - + + Stop analysis Stop checking チェックを停止する - + Esc Esc - + &Save results to file... 結果をファイルに保存(&S)... - + Ctrl+S Ctrl+S - + &Quit 終了(&Q) - + &Clear results 結果をクリア(&C) - + &Preferences 設定(&P) - - + + Show style warnings スタイル警告を表示 - - - + + + Show errors エラーを表示 - + Information 情報 - + Show information messages 情報メッセージを表示 - + Show portability warnings 移植可能性の問題を表示 - + Show Cppcheck results Cppcheck結果を表示する - + Clang Clang - + Show Clang results Clangの結果を表示 - + &Filter フィルター(&F) - + Filter results フィルタ結果 - + Windows 32-bit ANSI Windows 32-bit ANSIエンコード - + Windows 32-bit Unicode Windows 32-bit Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... 印刷(&P)... - + Print the Current Report 現在のレポートを印刷 - + Print Pre&view... 印刷プレビュー(&v)... - + Open a Print Preview Dialog for the Current Results 現在のレポートをプレビュー表示 - + Open library editor ライブラリエディタを開く - + C&lose Project File プロジェクトを閉じる(&l) - + &Edit Project File... プロジェクトの編集(&E)... - + &Statistics 統計情報(&S) - - - + + + Show warnings 警告を表示 - - + + Show performance warnings パフォーマンス警告を表示 - + Show &hidden 非表示を表示(&h) - + &Check all すべてのエラーを表示(&C) @@ -815,288 +815,298 @@ Parameters: -l(line) (file) - + Report レポート - + A&nalyze チェック(&n) - + Filter フィルター - + &Reanalyze modified files &Recheck modified files 変更ありファイルを再解析(&R) - + Reanal&yze all files 全ファイル再解析(&y) - + Ctrl+Q Ctrl+Q - + Style war&nings スタイル警告(&n) - + E&rrors エラー(&r) - + &Uncheck all すべてのエラーを非表示(&U) - + Collapse &all ツリーを折り畳む(&a) - + &Expand all ツリーを展開(&E) - + &Standard 言語規格(&S) - + Standard items 標準項目 - + &Contents コンテンツ(&C) - + Open the help contents ヘルプファイルを開く - + F1 F1 - + Toolbar ツールバー - + &Categories カテゴリ(&C) - + Error categories エラーカテゴリ - + &Open XML... XMLを開く(&O)... - + Open P&roject File... プロジェクトを開く(&R)... - + Ctrl+Shift+O Ctrl+Shift+O - + Sh&ow Scratchpad... スクラッチパッドを表示(&o)... - + &New Project File... 新規プロジェクト(&N)... - + Ctrl+Shift+N Ctrl+Shift+N - + &Log View ログを表示(&L) - + Log View ログ表示 - + &Warnings 警告(&W) - + Per&formance warnings パフォーマンス警告(&f) - + &Information 情報(&I) - + &Portability 移植可能性(&P) - + P&latforms プラットフォーム(&l) - + C++&11 C++11(&1) - + C&99 C99(&9) - + &Posix Posix(&P) - + C&11 C11(&1) - + &C89 C89(&C) - + &C++03 C++03(&C) - + &Library Editor... ライブラリエディタ(&L)... - + &Auto-detect language 自動言語検出(&A) - + &Enforce C++ C++ 強制(&E) - + E&nforce C C 強制(&n) - + C++14 C++14 - + Reanalyze and check library ライブラリを再チェックする - + Check configuration (defines, includes) チェックの設定(define、インクルード) - + C++17 C++17 - + C++20 C++20 - + Compliance report... コンプライアンスレポート... - + Normal ノーマル - + Misra C MISRA C - + Misra C++ 2008 MISRA C++ 2008 - + Cert C CERT C - + Cert C++ Cert C++ - + Misra C++ 2023 MISRA C++ 2023 - + Autosar AUTOSAR - + EULA... EULA... - + + Thread Details + スレッド詳細 + + + + Show thread details + スレッド詳細を表示 + + + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -1105,23 +1115,23 @@ This is probably because the settings were changed between the Cppcheck versions Cppcheckの古いバージョンの設定には互換性がありません。エディタアプリケーションの設定を確認して修正してください、そうしないと正しく起動できないかもしれません。 - + You must close the project file before selecting new files or directories! 新しいファイル/ディレクトリをチェックするには現在のプロジェクトを閉じてください! - - + + Quick Filter: クイックフィルタ: - + Select configuration コンフィグレーションの選択 - + Found project file: %1 Do you want to load this project file instead? @@ -1130,57 +1140,52 @@ Do you want to load this project file instead? 現在のプロジェクトの代わりにこのプロジェクトファイルを読み込んでもかまいませんか? - + The library '%1' contains unknown elements: %2 このライブラリ '%1' には次の不明な要素が含まれています。 %2 - + File not found ファイルがありません - + Bad XML 不正なXML - + Missing attribute 属性がありません - + Bad attribute value 不正な属性があります - + Unsupported format サポートされていないフォーマット - + Duplicate platform type プラットフォームの種類が重複しています - + Platform type redefined プラットフォームの種類が再定義されました - + Unknown element 不明な要素 - - - Unknown issue - 不明な課題 - Failed to load the selected library '%1'. @@ -1189,10 +1194,10 @@ Do you want to load this project file instead? %2 - - - - + + + + Error エラー @@ -1205,73 +1210,73 @@ Do you want to load this project file instead? %1 - %2 の読み込みに失敗 - - + + XML files (*.xml) XML ファイル (*.xml) - + Open the report file レポートを開く - + License ライセンス - + Authors 作者 - + Save the report file レポートを保存 - + Text files (*.txt) テキストファイル (*.txt) - + CSV files (*.csv) CSV形式ファイル (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. コンプライアンスレポートをすぐに生成できません。解析が完了し成功していなければなりません。コードを再解析して、致命的なエラーがないことを確認してください。 - + Project files (*.cppcheck);;All files(*.*) プロジェクトファイル (*.cppcheck);;すべてのファイル(*.*) - + Select Project File プロジェクトファイルを選択 - + Failed to open file ファイルを開くのに失敗しました - + Unknown project file format プロジェクトファイルの形式が不明です - + Failed to import project file プロジェクトファイルのインポートに失敗しました - + Failed to import '%1': %2 Analysis is stopped. @@ -1280,70 +1285,70 @@ Analysis is stopped. 解析を停止しました。 - + Failed to import '%1' (%2), analysis is stopped '%1' (%2) のインポートに失敗しました。解析は停止 - + Install インストール - + New version available: %1. %2 新しいバージョンが利用可能です。: %1. %2 - - - - + + + + Project: プロジェクト: - + No suitable files found to analyze! チェック対象のファイルがみつかりません! - + C/C++ Source C/C++のソースコード - + Compile database コンパイルデータベース - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze チェック対象のファイルを選択 - + Select directory to analyze チェックするディレクトリを選択してください - + Select the configuration that will be analyzed チェックの設定を選択 - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1352,7 +1357,7 @@ Do you want to proceed analysis without using any of these project files? - + Duplicate define 重複した定義 @@ -1367,22 +1372,22 @@ Do you want to proceed analysis without using any of these project files?アドオンの読み込みまたは設定に失敗 %1 - %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. %1のロードに失敗しました。あなたの Cppcheck は正しくインストールされていません。あなたは --data-dir=<directory> コマンドラインオプションを使ってこのファイルの場所を指定できます。ただし、この --data-dir はインストールスクリプトによって使用されていなければなりません。またGUI版はこれを使用しません。さらに、全ての設定は調整済みでなければなりません。 - + Failed to load %1 - %2 Analysis is aborted. 読み込みに失敗 %1 - %2 - - + + %1 Analysis is aborted. @@ -1391,7 +1396,7 @@ Analysis is aborted. 解析は中止した。 - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1401,7 +1406,7 @@ Do you want to proceed? 新しくXMLファイルを開くと現在の結果が削除されます。実行しますか? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1410,77 +1415,77 @@ Do you want to stop the analysis and exit Cppcheck? チェックを中断して、Cppcheckを終了しますか? - + About CppCheckについて - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML ファイル (*.xml);;テキストファイル (*.txt);;CSVファイル (*.csv) - + Build dir '%1' does not exist, create it? ビルドディレクトリ'%1'がありません。作成しますか? - + To check the project using addons, you need a build directory. アドオンを使用してプロジェクトをチェックするためには、ビルドディレクトリが必要です。 - + Show Mandatory 必須を表示 - + Show Required 要求を表示 - + Show Advisory 推奨を表示 - + Show Document ドキュメントを表示 - + Show L1 L1を表示 - + Show L2 L2を表示 - + Show L3 L3を表示 - + Show style スタイルを表示 - + Show portability 移植可能性を表示 - + Show performance パフォーマンスを表示 - + Show information 情報を表示 @@ -1489,22 +1494,22 @@ Do you want to stop the analysis and exit Cppcheck? '%1'のインポートに失敗しました。(チェック中断) - + Project files (*.cppcheck) プロジェクトファイル (*.cppcheck) - + Select Project Filename プロジェクトファイル名を選択 - + No project file loaded プロジェクトファイルが読み込まれていません - + The project file %1 @@ -1878,12 +1883,17 @@ Options: Cert C++ - + + Safety profiles (defined in C++ core guidelines) + 安全性プロファイル(C++コアガイドラインで定義) + + + Bug hunting (Premium) バグハンティング(プレミアム) - + External tools 外部ツール @@ -2007,17 +2017,17 @@ Options: AUTOSAR - + Bug hunting バグハント - + Clang analyzer Clang Analyzer - + Clang-tidy Clang-tidy @@ -2030,82 +2040,82 @@ Options: ProjectFileDialog - + Project file: %1 プロジェクトファイル:%1 - + Select Cppcheck build dir Cppcheckビルドディレクトリ - + Select include directory includeディレクトリを選択 - + Select a directory to check チェックするディレクトリを選択してください - + Note: Open source Cppcheck does not fully implement Misra C 2012 注意: オープンソースのCppcheckはMisra C 2012を完全にサポートしていません。 - + Clang-tidy (not found) Clang-tidy (みつかりません) - + Visual Studio Visual Studio - + Compile database コンパイルデータベース - + Borland C++ Builder 6 Borland C++ Builder 6 - + Import Project プロジェクトのインポート - + Select directory to ignore 除外するディレクトリを選択してください - + Source files ソースファイル - + All files 全ファイル - + Exclude file 除外ファイル - + Select MISRA rule texts file MISRAルールテキストファイルを選択 - + MISRA rule texts file (%1) MISRAルールテキストファイル (%1) @@ -2146,7 +2156,7 @@ Options: 行 %1: 必須の属性 '%2' が '%3'にない - + (Not found) (見つかりません) @@ -2196,158 +2206,158 @@ Options: - + Editor Foreground Color エディタの前景色 - + Editor Background Color エディタの背景色 - + Highlight Background Color ハイライトの背景色 - + Line Number Foreground Color 行番号の前景色 - + Line Number Background Color 行番号の背景色 - + Keyword Foreground Color キーワードの前景色 - + Keyword Font Weight キーワードのフォントのウェイト - + Class Foreground Color Class ForegroundColor クラスの前景色 - + Class Font Weight クラスフォントのウェイト - + Quote Foreground Color クォートの前景色 - + Quote Font Weight クォートのフォントウェイト - + Comment Foreground Color コメントの前景色 - + Comment Font Weight コメントフォントのウェイト - + Symbol Foreground Color シンボルの前景色 - + Symbol Background Color シンボルの背景色 - + Symbol Font Weight シンボルのフォントウェイト - + Set to Default Light デフォルトをライトに設定 - + Set to Default Dark デフォルトをダークに設定 - + File ファイル - + Line - + Severity 警告の種別 - + Classification 分類 - + Level レベル - + Inconclusive 結論のでない - + Summary 要約 - + Id Id - + Guideline ガイドライン - + Rule ルール - + Since date 日付 - + Tags タグ - + CWE CWE @@ -2398,37 +2408,37 @@ Options: 未定義ファイル - + Copy コピー - + Could not find file: ファイルが見つかりません: - + Please select the folder '%1' フォルダ '%1' を選択してください - + Select Directory '%1' ディレクトリ '%1' 選択 - + Please select the directory where file is located. ファイルのあるディレクトリを選択してください。 - + debug デバッグ - + note 注意 @@ -2441,53 +2451,53 @@ Options: 非表示 - + Hide all with id IDで非表示を指定 - + Suppress selected id(s) 選択したidを抑制 - + Open containing folder 含まれるフォルダを開く - + internal 内部 - + Recheck %1 file(s) - 再チェック %1 件のファイル + 再チェック %1 件のファイル - + Hide %1 result(s) 非表示 %1 件の結果 - + Tag タグ - + No tag タグなし - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2497,7 +2507,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2506,12 +2516,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! ファイルが見つかりません! - + Could not start %1 Please check the application path and parameters are correct. @@ -2520,7 +2530,7 @@ Please check the application path and parameters are correct. 実行ファイルパスや引数の設定を確認してください。 - + Select Directory ディレクトリを選択 @@ -2537,32 +2547,32 @@ Please check the application path and parameters are correct. 日付 - + style スタイル - + error エラー - + warning 警告 - + performance パフォーマンス - + portability 移植可能性 - + information 情報 @@ -3233,10 +3243,18 @@ To toggle what kind of errors are shown, open view menu. 情報メッセージ + + ThreadDetails + + + Thread Details + スレッド詳細 + + ThreadResult - + %1 of %2 files checked チェック: %1 / %2 (ファイル数) diff --git a/gui/cppcheck_ka.ts b/gui/cppcheck_ka.ts index 306308fced3..ecc47d7d090 100644 --- a/gui/cppcheck_ka.ts +++ b/gui/cppcheck_ka.ts @@ -325,41 +325,41 @@ Parameters: -l(line) (file) ჩასწორება - - + + Library files (*.cfg) ბიბლიოთეკის ფაილები (*.cfg) - + Open library file ბიბლიოთეკის ფაილის გახსნა - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. ფაილის '%1' გახსნის შეცდომა. - + Failed to load %1. %2. %1-ის ჩატვირთვის შეცდომა. %2. - + Cannot save file %1. ფაილის შენახვის შეცდომა: %1 . - + Save the library as ბიბლიოთეკის შენახვა, როგორც @@ -478,30 +478,30 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + A&nalyze ა&ნალიზი - + Standard სტანდარტული @@ -521,235 +521,235 @@ Parameters: -l(line) (file) &ხელსაწყოთა ზოლები - + C++ standard C++-ის სტანდარტი - + &C standard C standard &C-ის სტანდარტი - + &Edit &ჩასწორება - + &License... &ლიცენზია... - + A&uthors... &ავტორები... - + &About... &შესახებ... - + &Files... ფაილ&ები... - - + + Analyze files Check files ფაილების ანალიზი - + Ctrl+F Ctrl+F - + &Directory... &საქაღალდე.... - - + + Analyze directory Check directory საქაღალდის ანალიზი - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop &გაჩერება - - + + Stop analysis Stop checking ანალიზის გაჩერება - + Esc Esc - + &Save results to file... შედეგები&ს შენახვა ფაილში.... - + Ctrl+S Ctrl+S - + &Quit გამოსვლა - + &Clear results შედეგების &გასუფთავება - + &Preferences &გამართვა - - - + + + Show errors შეცდომების ჩვენება - - - + + + Show warnings გაფრთხილების ჩვენება - - + + Show performance warnings წარმადობის გაფრთხილებების ჩვენება - + Show &hidden დამალულის &ჩვენება - + Information ინფორმაცია - + Show information messages ინფორმაციის შეტყობინებების ჩვენება - + Show portability warnings გადატანადობის გაფრთხილებების ჩვენება - + Show Cppcheck results Cppcheck-ის შედეგები ჩვენება - + Clang Clang - + Show Clang results Clang-ის შედეგები ჩვენება - + &Filter &ფილტრი - + Filter results შედეგების გაფილტვრა - + Windows 32-bit ANSI Windows 32-bit ANSI - + Windows 32-bit Unicode Windows 32-bit Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... &ბეჭდვა… - + Print the Current Report მიმდინარე ანგარიშის დაბეჭდვა - + Print Pre&view... საბეჭდის &გადახედვა... - + Open a Print Preview Dialog for the Current Results მიმდინარე შედეგების დაბეჭდვის მინიატურის დიალოგის ჩვენება - + Open library editor ბიბლიოთეკის რედაქტორის გახსნა - + &Check all &ყველას ჩართვა @@ -765,325 +765,335 @@ Parameters: -l(line) (file) - + Report - + Filter ფილტრი - + &Reanalyze modified files &Recheck modified files ყველა შეცვლილი ფაილის თავიდან ანალი&ზი - + Reanal&yze all files &ყველა ფაილის თავიდან ანალიზი - + Ctrl+Q Ctrl+Q - + Style war&nings ს&ტილის გაფრთხილებები - + E&rrors &შეცდომები - + &Uncheck all ყველას ჩამოყ&რა - + Collapse &all ყველას ჩაკეცვ&ა - + &Expand all &ყველას ამოკეცვა - + &Standard &სტანდარტული - + Standard items სტანდარტული ელემენტები - + Toolbar ხელსაწყოთა ზოლი - + &Categories &კატეგორიები - + Error categories შეცდომის კატეგორიები - + &Open XML... &XML-ის გახსნა... - + Open P&roject File... პ&პროექტის ფაილის გახსნა... - + Ctrl+Shift+O Ctrl+Shift+O - + Sh&ow Scratchpad... ბლ&ოკნოტის ჩვენება... - + &New Project File... &ახალი პროექტის ფაილი... - + Ctrl+Shift+N Ctrl+Shift+N - + &Log View ჟურნა&ლის ხედი - + Log View ჟურნალის ხედი - + C&lose Project File პროექტის ფაი&ლის დახურვა - + &Edit Project File... პროექტის ფაილის ჩასწორ&ება... - + &Statistics &სტატისტიკა - + &Warnings &გაფრთხილებები - + Per&formance warnings წარმატების გა&ფრთხილებები - + &Information &ინფორმაცია - + &Portability &გადატანადობა - + P&latforms პ&ლატფორმები - + C++&11 C++&11 - + C&99 C&99 - + &Posix &Posix - + C&11 C&11 - + &C89 &C89 - + &C++03 &C++03 - + &Library Editor... ბიბ&ლიოთეკის რედაქტორი... - + &Auto-detect language ენის &ავტოდადგენა - + &Enforce C++ ძ&ალით C++ - + E&nforce C ძა&ლით C - + C++14 C++14 - + Reanalyze and check library ბიბლიოთეკის თავიდან ანალიზი და შემოწმება - + Check configuration (defines, includes) კონფიგურაციის შემოწმება (defines, includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... შესაბამისობის ანგარიში... - + Normal ნორმალური - + Misra C Misra C - + Misra C++ 2008 - + Cert C Cert C - + Cert C++ Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents &შემცველობა - + Categories კატეგორიები - - + + Show style warnings სტილის გაფრთხილების ჩვენება - + Open the help contents დახმარების შემცველობის გახსნა - + F1 F1 - + &Help &დახმარება - - + + Quick Filter: სწრაფი ფილტრი: - + Select configuration აირჩიეთ კონფიგურაცია - + Found project file: %1 Do you want to load this project file instead? @@ -1092,32 +1102,32 @@ Do you want to load this project file instead? გნებავთ, სამაგიეროდ, ეს პროექტის ფაილი ჩატვირთოთ? - + File not found ფაილი ნაპოვნი არაა - + Bad XML არასწორი XML - + Missing attribute აკლია ატრიბუტი - + Bad attribute value არასწორი ატრიბუტის მნიშვნელობა - + Unsupported format მხარდაუჭერელი ფორმატი - + Duplicate define გამეორებული აღწერა @@ -1139,14 +1149,14 @@ Do you want to load this project file instead? დამატების (%1) ჩატვირთვა/მორგება ჩავარდა: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. @@ -1155,8 +1165,8 @@ Analysis is aborted. ანალიზი შეწყდა. - - + + %1 Analysis is aborted. @@ -1165,148 +1175,149 @@ Analysis is aborted. ანალიზი შეწყვეტილია. - + License ლიცენზია - + Authors ავტორები - + Save the report file ანგარიშის ფაილში ჩაწერა - - + + XML files (*.xml) XML ფაილები (*.xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. - + You must close the project file before selecting new files or directories! ახალი ფაილების ან საქაღალდეების არჩევამდე პრორექტის ფაილი უნდა დახუროთ! - + The library '%1' contains unknown elements: %2 ბიბლიოთეკა '%1' უცნობ ელემენტებს შეიცავს: %2 - + Duplicate platform type გამეორებული პლატფორმის ტიპი - + Platform type redefined პლატფორმის ტიპი თავდან აღიწერა - + Unknown element უცნობი ელემენტი - Unknown issue - უცნობი პრობლემა + Unknown element + Unknown issue + უცნობი პრობლემა - - - - + + + + Error შეცდომა - + Open the report file ანგარიშის ფაილის გახსნა - + Text files (*.txt) ტექსტური ფაილები (*.txt) - + CSV files (*.csv) CSV ფაილები (*.csv) - + Project files (*.cppcheck);;All files(*.*) პროექტის ფაილები (*.cppcheck);;ყველა ფაილი(*.*) - + Select Project File აირჩიეთ პროექტის ფაილი - - - - + + + + Project: პროექტი: - + No suitable files found to analyze! ანალიზისათვის შესაფერისი ფაილები აღმოჩენილი არაა! - + C/C++ Source C/C++ საწყისი კოდი - + Compile database მონაცემთა ბაზის კომპილაცია - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze აირჩეთ ფაილები ანალიზისთვის - + Select directory to analyze აირჩიეთ საქაღალდე ანალიზისთვის - + Select the configuration that will be analyzed აირჩიეთ კონფიგურაცია ანალიზისთვის - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1315,7 +1326,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1326,7 +1337,7 @@ Do you want to proceed? გნებავთ, გააგრძელოთ? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1335,47 +1346,47 @@ Do you want to stop the analysis and exit Cppcheck? გნებავთ, გააჩეროთ ანალიზი და გახვიდეთ Cppcheck-დან? - + About შესახებ - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML ფაილები (*.xml);;ტექსტური ფაილები (*.txt);;CSV ფაილები (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. შესაბამისობის ანგარიშის გენერაცია ახლა შეუძლებელია, რადგან ჯერ ანალიზი წარმატებით უნდა დასრულდეს. სცადეთ, კოდის ანალიზი თავიდან გაუშვათ და დარწმუნდეთ, რომ კრიტიკული შეცდომები არ არსებობს. - + Build dir '%1' does not exist, create it? აგების საქაღალდე (%1) არ არსებობს. შევქმნა? - + To check the project using addons, you need a build directory. პროექტის დამატებებით შესამოწმებლად აგების საქაღალდე გჭირდებათ. - + Failed to open file ფაილის გახსნის შეცდომა - + Unknown project file format უცნობი პროექტის ფაილის ფორმატი - + Failed to import project file პროექტის ფაილის შემოტანა ჩავარდა - + Failed to import '%1': %2 Analysis is stopped. @@ -1384,27 +1395,27 @@ Analysis is stopped. ანალიზი შეწყდა. - + Failed to import '%1' (%2), analysis is stopped '%1'-ის (%2) შემოტანა ჩავარდა. ანალიზი შეწყდა - + Project files (*.cppcheck) პროექტის ფაილები (*.cppcheck) - + Select Project Filename აირჩიეთ პროექტის ფაილის სახელი - + No project file loaded პროექტის ფაილი ჩატვირთული არაა - + The project file %1 @@ -1421,67 +1432,67 @@ Do you want to remove the file from the recently used projects -list? გნებავთ წაშალოთ ეს ფაილი ახლახან გამოყენებული პროექტების სიიდან? - + Install დაყენება - + New version available: %1. %2 ხელმისაწვდომია ახალი ვერსია: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1860,12 +1871,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting შეცდომებზე ნადირობა - + External tools გარე ხელსაწყოები @@ -1967,17 +1983,17 @@ Options: Cert C++ - + Bug hunting (Premium) შეცდომებზე ნადირობა (ფასიანი) - + Clang analyzer Clang-ის ანალიზატორი - + Clang-tidy Clang-tidy @@ -1990,82 +2006,82 @@ Options: ProjectFileDialog - + Project file: %1 პროექტის ფაილი: %1 - + Select Cppcheck build dir აირჩიეთ Cppcheck-ის აგების საქაღალდე - + Select include directory აირჩიეთ ჩასასმელი საქაღალდე - + Select a directory to check აირჩიეთ შესამოწმებელი საქაღალდე - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) Clang-tidy (ვერ ვიპოვე) - + Visual Studio Visual Studio - + Compile database მონაცემთა ბაზის კომპილაცია - + Borland C++ Builder 6 Borland C++ Builder 6 - + Import Project პროექტის შემოტანა - + Select directory to ignore აირჩიეთ გამოსატოვებელი საქაღალდე - + Source files კოდის ფაილები - + All files ყველა ფაილი - + Exclude file ფაილის ამოღება - + Select MISRA rule texts file აირჩიეთ MISRA-ის წესების ტექსტის ფაილი - + MISRA rule texts file (%1) MISRA-ის წესის ტექსტების ფაილი (%1) @@ -2100,7 +2116,7 @@ Options: ხაზი %1: აუცილებელი ატრიბუტი '%2' '%3'-ში აღმოჩენილი არაა - + (Not found) (ვერ ვიპოვე) @@ -2150,158 +2166,158 @@ Options: შავი - + Editor Foreground Color რედაქტორის წინა პლანის ფერი - + Editor Background Color რედაქტორის ფონის ფერი - + Highlight Background Color ფონის ფერის გაოკვეთა - + Line Number Foreground Color ხაზის ნომრის წინა პლანის ფერი - + Line Number Background Color ხაზის ნომრის ფონის ფერი - + Keyword Foreground Color საკვანძო სიტყვის წინა პლანის ფერი - + Keyword Font Weight საკვანძო სიტყვის ფონტის სიმძიმე - + Class Foreground Color Class ForegroundColor კლასის წინა პლანის ფერი - + Class Font Weight კლასის ფონტის სიმძიმე - + Quote Foreground Color ციტატის წინა პლანის ფერი - + Quote Font Weight ციტატის ფონტის სიმძიმე - + Comment Foreground Color კომენტარის წინა პლანს ფერი - + Comment Font Weight კომენტარის ფონტის სიმძიმე - + Symbol Foreground Color სიმბოლოს წინა პლანის ფერი - + Symbol Background Color სიმბოლოს ფონის ფერი - + Symbol Font Weight სიმბოლოს ფონტის სიმძიმე - + Set to Default Light ნაგულისხმევად ღიას დაყენება - + Set to Default Dark ნაგულისხმევად მუქის დაყენება - + File ფაილი - + Line ხაზი - + Severity სიმძიმე - + Classification - + Level - + Inconclusive არადამაჯერებელი - + Summary შეჯამება - + Id Id - + Guideline - + Rule - + Since date თარიღიდან - + Tags - + CWE @@ -2352,37 +2368,37 @@ Options: გაურკვეველი ფაილი - + Copy კოპირება - + Could not find file: ვერ ვიპოვე ფაილი: - + Please select the folder '%1' აირჩიეთ საქაღალდე '%1' - + Select Directory '%1' აირჩიეთ საქაღალდე '%1' - + Please select the directory where file is located. აირჩიეთ საქაღალდე, სადაც ფაილია მოთავსებული. - + debug შეცდომების მოძებნა - + note ნოტა @@ -2395,53 +2411,53 @@ Options: დამალვა - + Hide all with id დამალვა ყველასი id-ით - + Suppress selected id(s) მონიშნული id(ებ)-ის ჩახშობა - + Open containing folder შემცველი საქაღალდის გახსნა - + internal შიდა - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag იარლიყი - + No tag ჭდის გარეშე - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2451,7 +2467,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2460,12 +2476,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! ფაილი ვერ ვიპოვე! - + Could not start %1 Please check the application path and parameters are correct. @@ -2474,7 +2490,7 @@ Please check the application path and parameters are correct. შეამოწმეთ, სწორია, თუ არა აპლიკაციის ბილიკი და მისი პარამეტრები. - + Select Directory აირჩიეთ საქაღალდე @@ -2491,32 +2507,32 @@ Please check the application path and parameters are correct. თარიღიდან - + style სტილი - + error შეცდომა - + warning გაფრთხილება - + performance წარმადობა - + portability გადატანადობა - + information ინფორმაცია @@ -3188,10 +3204,18 @@ To toggle what kind of errors are shown, open view menu. საინფორმაციო შეტყობინებები + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked შემოწმებულია %1 ფაილი %2-დან diff --git a/gui/cppcheck_ko.ts b/gui/cppcheck_ko.ts index 972a54bd889..da6bac85bb7 100644 --- a/gui/cppcheck_ko.ts +++ b/gui/cppcheck_ko.ts @@ -313,13 +313,13 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: 편집 - - + + Library files (*.cfg) - + Open library file @@ -344,29 +344,29 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - - - + + + Cppcheck Cppcheck - + Save the library as - + Failed to load %1. %2. - + Cannot open file %1. - + Cannot save file %1. @@ -485,20 +485,20 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck @@ -529,345 +529,355 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - + Report - + &Help 도움말(&H) - + &Edit 편집(&E) - + Standard 표준 도구 - + Categories 분류 도구 - + Filter 필터 도구 - + &License... 저작권(&L)... - + A&uthors... 제작자(&u)... - + &About... 정보(&A)... - + &Files... 파일(&F)... - + Ctrl+F Ctrl+F - + &Directory... 디렉토리(&D)... - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop 중지(&S) - + Esc Esc - + &Save results to file... 결과를 파일에 저장(&S)... - + Ctrl+S Ctrl+S - + &Quit 종료(&Q) - + &Clear results 결과 지우기(&C) - + &Preferences 설정(&P) - - + + Show style warnings 스타일 경고 표시 - - - + + + Show errors 애러 표시 - + &Check all 전체 선택(&C) - + &Uncheck all 전체 해제(&U) - + Collapse &all 전체 접기(&A) - + &Expand all 전체 펼치기(&E) - + &Standard 표준 도구(&S) - + Standard items 표준 아이템 - + &Contents 내용(&C) - + Open the help contents 도움말을 엽니다 - + F1 F1 - + Toolbar 도구바 - + &Categories 분류 도구(&C) - + Error categories 에러 종류 - + &Open XML... XML 열기(&O)... - + Open P&roject File... 프로젝트 파일 열기(&R)... - + &New Project File... 새 프로젝트 파일(&N)... - + &Log View 로그 보기(&L) - + Log View 로그 보기 - + C&lose Project File 프로젝트 파일 닫기(&L) - + &Edit Project File... 프로젝트 파일 편집(&E)... - + &Statistics 통계 보기(&S) - - - + + + Show warnings 경고 표시 - - + + Show performance warnings 성능 경고 표시 - + Show &hidden 숨기기 보기(&H) - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + Information 정보 - + Show information messages 정보 표시 - + Show portability warnings 이식성 경고 표시 - + &Filter 필터 도구(&F) - + Filter results 필터링 결과 - + Windows 32-bit ANSI Windows 32-bit ANSI - + Windows 32-bit Unicode Windows 32-bit Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - - + + Quick Filter: 빠른 필터: - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -876,12 +886,12 @@ This is probably because the settings were changed between the Cppcheck versions Cppcheck 버전간 설정 방법 차이때문인 것으로 보입니다. 편집기 설정을 검사(및 수정)해주세요, 그렇지 않으면 편집기가 제대로 시작하지 않습니다. - + You must close the project file before selecting new files or directories! 새로운 파일이나 디렉토리를 선택하기 전에 프로젝트 파일을 닫으세요! - + Found project file: %1 Do you want to load this project file instead? @@ -890,158 +900,158 @@ Do you want to load this project file instead? 이 프로젝트 파일을 불러오겠습니까? - - + + XML files (*.xml) XML 파일 (*.xml) - + Open the report file 보고서 파일 열기 - + License 저작권 - + Authors 제작자 - + Save the report file 보고서 파일 저장 - + Text files (*.txt) 텍스트 파일 (*.txt) - + CSV files (*.csv) CSV 파일 (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Project files (*.cppcheck);;All files(*.*) 프로젝트 파일 (*.cppcheck);;모든 파일(*.*) - + Select Project File 프로젝트 파일 선택 - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information - - - - + + + + Project: 프로젝트: - + Duplicate define @@ -1056,49 +1066,49 @@ Analysis is stopped. - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + About - + To check the project using addons, you need a build directory. - + Select Project Filename 프로젝트 파일이름 선택 - + No project file loaded 프로젝트 파일 불러오기 실패 - + The project file %1 @@ -1120,35 +1130,35 @@ Do you want to remove the file from the recently used projects -list? - + C++ standard - - - - + + + + Error - + File not found - + Bad XML - + Missing attribute - + Bad attribute value @@ -1159,63 +1169,64 @@ Do you want to remove the file from the recently used projects -list? - + Unsupported format - + The library '%1' contains unknown elements: %2 - + Duplicate platform type - + Platform type redefined - + &Print... - + Print the Current Report - + Print Pre&view... - + Open a Print Preview Dialog for the Current Results - + Open library editor - + Unknown element - Unknown issue + Unknown element + Unknown issue - + Select configuration @@ -1238,259 +1249,259 @@ Options: - + Build dir '%1' does not exist, create it? - - + + Analyze files - - + + Analyze directory - + &Reanalyze modified files - - + + Stop analysis - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + No suitable files found to analyze! - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + A&nalyze - + &C standard - + Reanal&yze all files - + Ctrl+Q - + Style war&nings - + E&rrors - + Ctrl+Shift+O - + Sh&ow Scratchpad... - + Ctrl+Shift+N - + &Warnings - + Per&formance warnings - + &Information - + &Portability - + Show Cppcheck results - + Clang - + Show Clang results - + P&latforms - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... - + &Auto-detect language - + &Enforce C++ - + E&nforce C - + C++14 C++14 - + Project files (*.cppcheck) - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 C++17 - + C++20 C++20 - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1744,17 +1755,17 @@ Do you want to proceed? - + Bug hunting - + Clang analyzer - + Clang-tidy @@ -1907,12 +1918,17 @@ Do you want to proceed? - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting (Premium) - + External tools @@ -1952,82 +1968,82 @@ Do you want to proceed? ProjectFileDialog - + Project file: %1 프로젝트 파일: %1 - + Select include directory Include 디렉토리 선택 - + Select a directory to check 검사할 디렉토리 선택 - + Select directory to ignore 무시할 디렉토리 선택 - + Select Cppcheck build dir - + Import Project - + Clang-tidy (not found) - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) - + Visual Studio - + Compile database - + Borland C++ Builder 6 @@ -2060,7 +2076,7 @@ Do you want to proceed? - + (Not found) @@ -2110,157 +2126,157 @@ Do you want to proceed? - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + Class Foreground Color - + File 파일 - + Line - + Severity 분류 - + Classification - + Level - + Inconclusive - + Summary 요약 - + Id - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2311,42 +2327,42 @@ Do you want to proceed? 미정의된 파일 - + style 스타일 - + error 에러 - + warning 경고 - + performance 성능 - + portability 이식성 - + information 정보 - + debug 디버그 - + internal @@ -2355,13 +2371,13 @@ Do you want to proceed? 숨기기 - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2370,7 +2386,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2379,12 +2395,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! 파일을 찾을 수 없습니다! - + Could not start %1 Please check the application path and parameters are correct. @@ -2393,72 +2409,72 @@ Please check the application path and parameters are correct. 경로와 인자가 정확한지 확인하세요. - + Select Directory 디렉토리 선택 - + Hide all with id - + Open containing folder - + note - + Recheck %1 file(s) - + Hide %1 result(s) - + Suppress selected id(s) - + Tag - + No tag - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + Copy @@ -3125,10 +3141,18 @@ To toggle what kind of errors are shown, open view menu. + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %2 중 %1 파일 검사됨 diff --git a/gui/cppcheck_nl.ts b/gui/cppcheck_nl.ts index 732073d404a..2d3149d2f0a 100644 --- a/gui/cppcheck_nl.ts +++ b/gui/cppcheck_nl.ts @@ -335,42 +335,42 @@ Parameters: -l(lijn) (bestand) Bewerk - - + + Library files (*.cfg) - + Open library file - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. - + Failed to load %1. %2. - + Cannot save file %1. Can not save file %1. - + Save the library as @@ -489,30 +489,30 @@ Parameters: -l(lijn) (bestand) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + A&nalyze - + Standard Standaard @@ -532,235 +532,235 @@ Parameters: -l(lijn) (bestand) &Werkbalken - + C++ standard C++standaard - + &C standard C standard C standaard - + &Edit Be&werken - + &License... &Licentie... - + A&uthors... A&uteurs... - + &About... &Over... - + &Files... &Bestanden... - - + + Analyze files Check files Controleer bestanden - + Ctrl+F Ctrl+F - + &Directory... &Mappen... - - + + Analyze directory Check directory Controleer Map - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop &Stop - - + + Stop analysis Stop checking Stop controle - + Esc Esc - + &Save results to file... &Resultaten opslaan... - + Ctrl+S Ctrl+S - + &Quit &Afsluiten - + &Clear results &Resultaten wissen - + &Preferences &Voorkeuren - - - + + + Show errors Toon fouten - - - + + + Show warnings Toon waarschuwingen - - + + Show performance warnings Toon presentatie waarschuwingen - + Show &hidden Toon &verborgen - + Information Informatie - + Show information messages Toon informatie bericht - + Show portability warnings Toon portabiliteit waarschuwingen - + Show Cppcheck results - + Clang - + Show Clang results - + &Filter &Filter - + Filter results Filter resultaten - + Windows 32-bit ANSI Windows 32-bit ANSI - + Windows 32-bit Unicode - + Unix 32-bit - + Unix 64-bit - + Windows 64-bit - + &Print... - + Print the Current Report - + Print Pre&view... - + Open a Print Preview Dialog for the Current Results - + Open library editor - + &Check all &Controleer alles @@ -776,325 +776,335 @@ Parameters: -l(lijn) (bestand) - + Report - + Filter - + &Reanalyze modified files &Recheck modified files - + Reanal&yze all files - + Ctrl+Q - + Style war&nings - + E&rrors - + &Uncheck all Selecteer &niets - + Collapse &all Alles Inkl&appen - + &Expand all Alles &Uitklappen - + &Standard &Standaard - + Standard items Standaard items - + Toolbar Werkbalk - + &Categories &Categorieën - + Error categories Foute Categorieën - + &Open XML... - + Open P&roject File... Open P&oject bestand... - + Ctrl+Shift+O - + Sh&ow Scratchpad... - + &New Project File... &Nieuw Project Bestand... - + Ctrl+Shift+N - + &Log View &Log weergave - + Log View Log weergave - + C&lose Project File &Sluit Project Bestand - + &Edit Project File... &Bewerk Project Bestand... - + &Statistics &Statistieken - + &Warnings - + Per&formance warnings - + &Information - + &Portability - + P&latforms - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... - + &Auto-detect language - + &Enforce C++ - + E&nforce C - + C++14 - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 - + C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents &Inhoud - + Categories Categorieën - - + + Show style warnings Toon stijl waarschuwingen - + Open the help contents Open de help inhoud - + F1 - + &Help &Help - - + + Quick Filter: Snel Filter: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? @@ -1102,27 +1112,27 @@ Do you want to load this project file instead? Wilt u dit project laden in plaats van? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Duplicate define @@ -1143,50 +1153,50 @@ Wilt u dit project laden in plaats van? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Licentie - + Authors Auteurs - + Save the report file Rapport opslaan - - + + XML files (*.xml) XML bestanden (*.xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -1195,131 +1205,132 @@ This is probably because the settings were changed between the Cppcheck versions Dit is waarschijnlijk omdat de instellingen zijn gewijzigd tussen de versies van cppcheck. Controleer (en maak) de bewerker instellingen, anders zal de bewerker niet correct starten. - + You must close the project file before selecting new files or directories! Je moet project bestanden sluiten voordat je nieuwe bestanden of mappen selekteerd! - + The library '%1' contains unknown elements: %2 - + Unsupported format - + Duplicate platform type - + Platform type redefined - + Unknown element - Unknown issue + Unknown element + Unknown issue - - - - + + + + Error - + Open the report file Open het rapport bestand - + Text files (*.txt) Tekst bestanden (*.txt) - + CSV files (*.csv) CSV bestanden (*.csv) - + Project files (*.cppcheck);;All files(*.*) Project bestanden (*.cppcheck);;Alle bestanden(*.*) - + Select Project File Selecteer project bestand - - - - + + + + Project: Project: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1327,81 +1338,81 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename Selecteer project bestandsnaam - + No project file loaded Geen project bestand geladen - + The project file %1 @@ -1417,67 +1428,67 @@ Kan niet worden gevonden! Wilt u het bestand van de onlangs gebruikte project verwijderen -lijst? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1834,12 +1845,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools @@ -1950,17 +1966,17 @@ Options: - + Bug hunting (Premium) - + Clang analyzer - + Clang-tidy @@ -1973,82 +1989,82 @@ Options: ProjectFileDialog - + Project file: %1 Project Bestand %1 - + Select Cppcheck build dir - + Select include directory Selecteer include map - + Select a directory to check Selecteer een map om te controleren - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) - + Visual Studio - + Compile database - + Borland C++ Builder 6 - + Import Project - + Select directory to ignore Selecteer een map om te negeren - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) @@ -2083,7 +2099,7 @@ Options: - + (Not found) @@ -2133,158 +2149,158 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Class ForegroundColor - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File Bestand - + Line Regel - + Severity Ernst - + Classification - + Level - + Inconclusive - + Summary Overzicht - + Id Id - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2335,37 +2351,37 @@ Options: Niet gedefinieerd bestand - + Copy - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + debug - + note @@ -2374,53 +2390,53 @@ Options: Verberg - + Hide all with id Verberg alles met id - + Suppress selected id(s) - + Open containing folder - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag - + No tag - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2430,7 +2446,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2438,12 +2454,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! Kon het bestand niet vinden! - + Could not start %1 Please check the application path and parameters are correct. @@ -2452,7 +2468,7 @@ Please check the application path and parameters are correct. Gelieve te controleren of de het pad en de parameters correct zijn. - + Select Directory Selecteer map @@ -2461,32 +2477,32 @@ Gelieve te controleren of de het pad en de parameters correct zijn.Id - + style Stijlfouten - + error Fouten - + warning Waarschuwing - + performance Presentatie - + portability Portabiliteit - + information Informatie @@ -3150,10 +3166,18 @@ Gebruik het uitzicht menu om te selecteren welke fouten getoond worden.Informatie bericht + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %1 van %2 bestanden gecontroleerd diff --git a/gui/cppcheck_ru.ts b/gui/cppcheck_ru.ts index 3256348229a..124e4d783aa 100644 --- a/gui/cppcheck_ru.ts +++ b/gui/cppcheck_ru.ts @@ -335,42 +335,42 @@ Parameters: -l(line) (file) Изменить - - + + Library files (*.cfg) Файлы библиотек (*.cfg) - + Open library file Открыть файл библиотеки - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. Невозможно открыть файл %1. - + Failed to load %1. %2. Ошибка загрузки %1. %2. - + Cannot save file %1. Can not save file %1. Невозможно сохранить файл %1. - + Save the library as Сохранить библиотеку как @@ -489,30 +489,30 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + A&nalyze Анализ - + Standard Стандартные @@ -532,235 +532,235 @@ Parameters: -l(line) (file) &Панель инструментов - + C++ standard Стандарт C++ - + &C standard C standard &Стандарт C - + &Edit &Правка - + &License... &Лицензия... - + A&uthors... &Авторы... - + &About... &О программе... - + &Files... &Файлы... - - + + Analyze files Check files Проверить файлы - + Ctrl+F Ctrl+F - + &Directory... &Каталог... - - + + Analyze directory Check directory Проверка каталога - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop Остановить - - + + Stop analysis Stop checking Остановить проверку - + Esc Esc - + &Save results to file... Сохранить отчёт в файл... - + Ctrl+S Ctrl+S - + &Quit Выход - + &Clear results Очистить отчёт - + &Preferences Параметры - - - + + + Show errors Показать ошибки - - - + + + Show warnings Показать предупреждения - - + + Show performance warnings Показать предупреждения производительности - + Show &hidden Показать скрытые - + Information Информационные сообщения - + Show information messages Показать информационные сообщения - + Show portability warnings Показать предупреждения переносимости - + Show Cppcheck results Просмотр результатов Cppcheck - + Clang Clang - + Show Clang results Просмотр результатов Clang - + &Filter Фильтр - + Filter results Результаты фильтрации - + Windows 32-bit ANSI Windows 32-bit ANSI - + Windows 32-bit Unicode Windows 32-bit Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... Печать... - + Print the Current Report Напечатать текущий отчет - + Print Pre&view... Предварительный просмотр... - + Open a Print Preview Dialog for the Current Results Открыть диалог печати для текущих результатов - + Open library editor Открыть редактор библиотек - + &Check all Отметить все @@ -776,325 +776,335 @@ Parameters: -l(line) (file) - + Report - + Filter Фильтр - + &Reanalyze modified files &Recheck modified files Заново проверить измененные файлы - + Reanal&yze all files Заново проверить все файлы - + Ctrl+Q - + Style war&nings Стилистические предупреждения - + E&rrors Ошибки - + &Uncheck all Сбросить все - + Collapse &all Свернуть все - + &Expand all Развернуть все - + &Standard Стандартные - + Standard items Стандартные элементы - + Toolbar Панель инструментов - + &Categories Категории - + Error categories Категории ошибок - + &Open XML... &Открыть XML... - + Open P&roject File... Открыть файл &проекта... - + Ctrl+Shift+O - + Sh&ow Scratchpad... Показать Блокнот - + &New Project File... &Новый файл проекта... - + Ctrl+Shift+N - + &Log View Посмотреть &лог - + Log View Посмотреть лог - + C&lose Project File &Закрыть файл проекта - + &Edit Project File... &Изменить файл проекта... - + &Statistics &Статистика - + &Warnings Предупреждения - + Per&formance warnings Предупреждения производительности - + &Information Информационные предупреждения - + &Portability Предупреждения переносимости - + P&latforms Платформы - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... Редактор библиотеки - + &Auto-detect language Автоматическое определение языка - + &Enforce C++ Принудительно C++ - + E&nforce C Принудительно C - + C++14 C++14 - + Reanalyze and check library Повторный анализ библиотеки - + Check configuration (defines, includes) Проверить конфигурацию (defines, includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents Помощь - + Categories Категории - - + + Show style warnings Показать стилистические предупреждения - + Open the help contents Открыть помощь - + F1 F1 - + &Help Помощь - - + + Quick Filter: Быстрый фильтр: - + Select configuration Выбор конфигурации - + Found project file: %1 Do you want to load this project file instead? @@ -1103,32 +1113,32 @@ Do you want to load this project file instead? Вы хотите загрузить этот проект? - + File not found Файл не найден - + Bad XML Некорректный XML - + Missing attribute Пропущен атрибут - + Bad attribute value Некорректное значение атрибута - + Unsupported format Неподдерживаемый формат - + Duplicate define @@ -1150,50 +1160,50 @@ Do you want to load this project file instead? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Лицензия - + Authors Авторы - + Save the report file Сохранить файл с отчетом - - + + XML files (*.xml) XML-файлы (*.xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -1202,42 +1212,43 @@ This is probably because the settings were changed between the Cppcheck versions Возможно, это связано с изменениями в версии программы. Пожалуйста, проверьте (и исправьте) настройки приложения. - + You must close the project file before selecting new files or directories! Вы должны закрыть проект перед выбором новых файлов или каталогов! - + The library '%1' contains unknown elements: %2 Библиотека '%1' содержит неизвестные элементы: %2 - + Duplicate platform type Дубликат типа платформы - + Platform type redefined Переобъявление типа платформы - + Unknown element Неизвестный элемент - Unknown issue - Неизвестная проблема + Unknown element + Unknown issue + Неизвестная проблема - - - - + + + + Error Ошибка @@ -1246,80 +1257,80 @@ This is probably because the settings were changed between the Cppcheck versions Невозможно загрузить %1. Cppcheck установлен некорректно. Вы можете использовать --data-dir=<directory> в командной строке для указания расположения файлов конфигурации. Обратите внимание, что --data-dir предназначен для использования сценариями установки. При включении данной опции, графический интерфейс пользователя не запускается. - + Open the report file Открыть файл с отчетом - + Text files (*.txt) Текстовые файлы (*.txt) - + CSV files (*.csv) CSV файлы(*.csv) - + Project files (*.cppcheck);;All files(*.*) Файлы проекта (*.cppcheck);;Все файлы(*.*) - + Select Project File Выберите файл проекта - - - - + + + + Project: Проект: - + No suitable files found to analyze! Не найдено подходящих файлов для анализа - + C/C++ Source Исходный код C/C++ - + Compile database - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze Выбор файлов для анализа - + Select directory to analyze Выбор каталога для анализа - + Select the configuration that will be analyzed Выбор используемой конфигурации - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1328,7 +1339,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1339,7 +1350,7 @@ Do you want to proceed? Вы хотите продолжить? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1348,109 +1359,109 @@ Do you want to stop the analysis and exit Cppcheck? Вы хотите остановить анализ и выйти из Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML файлы (*.xml);;Текстовые файлы (*.txt);;CSV файлы (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? Директория для сборки '%1' не существует, создать? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1459,22 +1470,22 @@ Analysis is stopped. Невозможно импортировать '%1', анализ остановлен - + Project files (*.cppcheck) Файлы проекта (*.cppcheck) - + Select Project Filename Выберите имя файла для проекта - + No project file loaded Файл с проектом не загружен - + The project file %1 @@ -1490,12 +1501,12 @@ Do you want to remove the file from the recently used projects -list? Хотите удалить его из списка проектов? - + Install - + New version available: %1. %2 @@ -1878,12 +1889,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools Внешние инструменты @@ -1985,17 +2001,17 @@ Options: - + Bug hunting (Premium) - + Clang analyzer - + Clang-tidy @@ -2008,82 +2024,82 @@ Options: ProjectFileDialog - + Project file: %1 Файл проекта: %1 - + Select Cppcheck build dir Выбрать директорию сборки Cppcheck - + Select include directory Выберите директорию для поиска заголовочных файлов - + Select a directory to check Выберите директорию для проверки - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) Clang-tidy (не найден) - + Visual Studio Visual Studio - + Compile database - + Borland C++ Builder 6 Borland C++ Builder 6 - + Import Project Импорт проекта - + Select directory to ignore Выберите директорию, которую надо проигнорировать - + Source files - + All files - + Exclude file - + Select MISRA rule texts file Выбрать файл текстов правил MISRA - + MISRA rule texts file (%1) Файл текстов правил MISRA (%1) @@ -2118,7 +2134,7 @@ Options: - + (Not found) (Недоступно) @@ -2168,158 +2184,158 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Class ForegroundColor - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File Файл - + Line Строка - + Severity Важность - + Classification - + Level - + Inconclusive Спорное - + Summary Кратко - + Id Id - + Guideline - + Rule - + Since date Начиная с даты - + Tags - + CWE @@ -2370,37 +2386,37 @@ Options: Неопределенный файл - + Copy Копировать - + Could not find file: Невозможно найти файл: - + Please select the folder '%1' Выберите каталог '%1' - + Select Directory '%1' Выбрать каталог '%1' - + Please select the directory where file is located. Укажите каталог с расположением файла. - + debug отлаживать - + note заметка @@ -2413,53 +2429,53 @@ Options: Скрыть - + Hide all with id Скрыть все с id - + Suppress selected id(s) Подавить выбранные id - + Open containing folder Открыть содержащую папку - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag Тег - + No tag Тег отсутствует - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2468,7 +2484,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2476,12 +2492,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! Не удается найти файл! - + Could not start %1 Please check the application path and parameters are correct. @@ -2489,7 +2505,7 @@ Please check the application path and parameters are correct. Пожалуйста, проверьте путь приложения, и верны ли параметры. - + Select Directory Выберите директорию @@ -2506,32 +2522,32 @@ Please check the application path and parameters are correct. Начиная с даты - + style стиль - + error ошибка - + warning предупреждение - + performance производительность - + portability переносимость - + information информация @@ -3199,10 +3215,18 @@ To toggle what kind of errors are shown, open view menu. Информационные сообщения + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %1 из %2 файлов проверены diff --git a/gui/cppcheck_sr.ts b/gui/cppcheck_sr.ts index 093d6846612..70b04dd196f 100644 --- a/gui/cppcheck_sr.ts +++ b/gui/cppcheck_sr.ts @@ -323,42 +323,42 @@ Parameters: -l(line) (file) - - + + Library files (*.cfg) - + Open library file - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. - + Failed to load %1. %2. - + Cannot save file %1. Can not save file %1. - + Save the library as @@ -477,30 +477,30 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + A&nalyze - + Standard Standard @@ -520,235 +520,235 @@ Parameters: -l(line) (file) - + C++ standard - + &C standard C standard - + &Edit &Edit - + &License... &License... - + A&uthors... A&uthors... - + &About... &About... - + &Files... &Files... - - + + Analyze files Check files - + Ctrl+F Ctrl+F - + &Directory... &Directory... - - + + Analyze directory Check directory - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop &Stop - - + + Stop analysis Stop checking - + Esc Esc - + &Save results to file... &Save results to file... - + Ctrl+S Ctrl+S - + &Quit &Quit - + &Clear results &Clear results - + &Preferences &Preferences - - - + + + Show errors - - - + + + Show warnings - - + + Show performance warnings - + Show &hidden - + Information - + Show information messages - + Show portability warnings - + Show Cppcheck results - + Clang - + Show Clang results - + &Filter - + Filter results - + Windows 32-bit ANSI Windows 32-bit ANSI - + Windows 32-bit Unicode Windows 32-bit Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... - + Print the Current Report - + Print Pre&view... - + Open a Print Preview Dialog for the Current Results - + Open library editor - + &Check all &Check all @@ -764,352 +764,362 @@ Parameters: -l(line) (file) - + Report - + Filter - + &Reanalyze modified files &Recheck modified files - + Reanal&yze all files - + Ctrl+Q - + Style war&nings - + E&rrors - + &Uncheck all &Uncheck all - + Collapse &all Collapse &all - + &Expand all &Expand all - + &Standard - + Standard items - + Toolbar - + &Categories - + Error categories - + &Open XML... - + Open P&roject File... - + Ctrl+Shift+O - + Sh&ow Scratchpad... - + &New Project File... - + Ctrl+Shift+N - + &Log View - + Log View - + C&lose Project File - + &Edit Project File... - + &Statistics - + &Warnings - + Per&formance warnings - + &Information - + &Portability - + P&latforms - + C++&11 - + C&99 - + &Posix - + C&11 - + &C89 - + &C++03 - + &Library Editor... - + &Auto-detect language - + &Enforce C++ - + E&nforce C - + C++14 C++14 - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents - + Categories - - + + Show style warnings - + Open the help contents - + F1 F1 - + &Help &Help - - + + Quick Filter: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Duplicate define @@ -1130,181 +1140,182 @@ Do you want to load this project file instead? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License License - + Authors Authors - + Save the report file Save the report file - - + + XML files (*.xml) XML files (*.xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. - + You must close the project file before selecting new files or directories! - + The library '%1' contains unknown elements: %2 - + Unsupported format - + Duplicate platform type - + Platform type redefined - + Unknown element - Unknown issue + Unknown element + Unknown issue - - - - + + + + Error - + Open the report file - + Text files (*.txt) Text files (*.txt) - + CSV files (*.csv) - + Project files (*.cppcheck);;All files(*.*) - + Select Project File - - - - + + + + Project: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1312,81 +1323,81 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename - + No project file loaded - + The project file %1 @@ -1397,67 +1408,67 @@ Do you want to remove the file from the recently used projects -list? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1803,12 +1814,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools @@ -1930,17 +1946,17 @@ Options: - + Bug hunting (Premium) - + Clang analyzer - + Clang-tidy @@ -1953,82 +1969,82 @@ Options: ProjectFileDialog - + Project file: %1 - + Select Cppcheck build dir - + Select include directory - + Select a directory to check - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) - + Visual Studio - + Compile database - + Borland C++ Builder 6 - + Import Project - + Select directory to ignore - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) @@ -2061,7 +2077,7 @@ Options: - + (Not found) @@ -2111,158 +2127,158 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Class ForegroundColor - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File File - + Line Line - + Severity Severity - + Classification - + Level - + Inconclusive - + Summary - + Id - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2309,107 +2325,107 @@ Options: Undefined file - + Copy - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + debug - + note - + Hide all with id - + Suppress selected id(s) - + Open containing folder - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag - + No tag - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. You can open this error by specifying applications in program's settings. - + No default editor application selected. Please select the default editor application in preferences/Applications. - + Could not find the file! - + Could not start %1 Please check the application path and parameters are correct. @@ -2418,37 +2434,37 @@ Please check the application path and parameters are correct. Please check the application path and parameters are correct. - + Select Directory - + style Style - + error Error - + warning - + performance - + portability - + information @@ -3107,10 +3123,18 @@ To toggle what kind of errors are shown, open view menu. + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked diff --git a/gui/cppcheck_sv.ts b/gui/cppcheck_sv.ts index 8070d7ee1ea..f37121c2f2f 100644 --- a/gui/cppcheck_sv.ts +++ b/gui/cppcheck_sv.ts @@ -335,42 +335,42 @@ Parametrar: -l(line) (file) Redigera - - + + Library files (*.cfg) Library fil (*.cfg) - + Open library file Öppna Library fil - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. Kunde ej öppna filen %1. - + Failed to load %1. %2. - + Cannot save file %1. Can not save file %1. Kunde ej spara filen %1. - + Save the library as Spara library som @@ -495,30 +495,30 @@ Exempel: MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck - + A&nalyze Analysera - + Standard Standard @@ -538,235 +538,235 @@ Exempel: Verktygsfält - + C++ standard C++ standard - + &C standard C standard C standard - + &Edit &Redigera - + &License... &Licens... - + A&uthors... &Utvecklat av... - + &About... &Om... - + &Files... &Filer... - - + + Analyze files Check files Analysera filer - + Ctrl+F Ctrl+F - + &Directory... &Katalog... - - + + Analyze directory Check directory Analysera mapp - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop &Stoppa - - + + Stop analysis Stop checking Stoppa analys - + Esc Esc - + &Save results to file... &Spara resultat till fil... - + Ctrl+S Ctrl+S - + &Quit &Avsluta - + &Clear results &Töm resultat - + &Preferences &Inställningar - - - + + + Show errors Visa fel - - - + + + Show warnings Visa varningar - - + + Show performance warnings Visa prestanda varningar - + Show &hidden Visa dolda - + Information Information - + Show information messages Visa informations meddelanden - + Show portability warnings Visa portabilitets varningar - + Show Cppcheck results Visa Cppcheck resultat - + Clang Clang - + Show Clang results Visa Clang resultat - + &Filter &Filter - + Filter results Filtrera resultat - + Windows 32-bit ANSI Windows 32-bit ANSI - + Windows 32-bit Unicode Windows 32-bit Unicode - + Unix 32-bit Unix 32-bit - + Unix 64-bit Unix 64-bit - + Windows 64-bit Windows 64-bit - + &Print... Skriv ut... - + Print the Current Report Skriv ut aktuell rapport - + Print Pre&view... Förhandsgranska utskrift... - + Open a Print Preview Dialog for the Current Results Öppnar förhandsgranskning för nuvarande resultat - + Open library editor Öppna library editor - + &Check all &Kryssa alla @@ -782,326 +782,336 @@ Exempel: - + Report - + Filter Filter - + &Reanalyze modified files &Recheck modified files Analysera om ändrade filer - + Reanal&yze all files Analysera om alla filer - + Ctrl+Q - + Style war&nings Style varningar - + E&rrors Fel - + &Uncheck all Kryssa &ur alla - + Collapse &all Ingen bra översättning! &Fäll ihop alla - + &Expand all &Expandera alla - + &Standard &Standard - + Standard items Standard poster - + Toolbar Verktygsfält - + &Categories &Kategorier - + Error categories Fel kategorier - + &Open XML... &Öppna XML... - + Open P&roject File... Öppna Projektfil... - + Ctrl+Shift+O - + Sh&ow Scratchpad... Visa Scratchpad... - + &New Project File... Ny projektfil... - + Ctrl+Shift+N - + &Log View - + Log View Logg vy - + C&lose Project File Stäng projektfil - + &Edit Project File... Redigera projektfil... - + &Statistics Statistik - + &Warnings Varningar - + Per&formance warnings Optimerings varningar - + &Information Information - + &Portability Portabilitet - + P&latforms Plattformar - + C++&11 C++11 - + C&99 C99 - + &Posix Posix - + C&11 C11 - + &C89 C89 - + &C++03 C++03 - + &Library Editor... Library Editor... - + &Auto-detect language Detektera språk automatiskt - + &Enforce C++ Tvinga C++ - + E&nforce C Tvinga C - + C++14 C++14 - + Reanalyze and check library - + Check configuration (defines, includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + &Contents &Innehåll - + Categories Kategorier - - + + Show style warnings Visa stil varningar - + Open the help contents Öppna hjälp - + F1 F1 - + &Help &Hjälp - - + + Quick Filter: Snabbfilter: - + Select configuration Välj konfiguration - + Found project file: %1 Do you want to load this project file instead? @@ -1110,32 +1120,32 @@ Do you want to load this project file instead? Vill du ladda denna projektfil istället? - + File not found Filen hittades ej - + Bad XML Ogiltig XML - + Missing attribute Attribut finns ej - + Bad attribute value Ogiltigt attribut värde - + Unsupported format Format stöds ej - + Duplicate define @@ -1157,50 +1167,50 @@ Vill du ladda denna projektfil istället? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Licens - + Authors Utvecklare - + Save the report file Spara rapport - - + + XML files (*.xml) XML filer (*.xml) - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -1209,42 +1219,43 @@ This is probably because the settings were changed between the Cppcheck versions En trolig orsak är att inställningarna ändrats för olika Cppcheck versioner. Kontrollera programinställningarna. - + You must close the project file before selecting new files or directories! Du måste stänga projektfilen innan nya filer eller sökvägar kan väljas! - + The library '%1' contains unknown elements: %2 Library filen '%1' har element som ej hanteras: %2 - + Duplicate platform type Dubbel plattformstyp - + Platform type redefined Plattformstyp definieras igen - + Unknown element Element hanteras ej - Unknown issue - Något problem + Unknown element + Unknown issue + Något problem - - - - + + + + Error Fel @@ -1253,80 +1264,80 @@ En trolig orsak är att inställningarna ändrats för olika Cppcheck versioner. Misslyckades att ladda %1. Din Cppcheck installation är ej komplett. Du kan använda --data-dir<directory> på kommandoraden för att specificera var denna fil finns. Det är meningen att --data-dir kommandot skall köras under installationen,så GUIt kommer ej visas när --data-dir används allt som händer är att en inställning görs. - + Open the report file Öppna rapportfilen - + Text files (*.txt) Text filer (*.txt) - + CSV files (*.csv) CSV filer (*.csv) - + Project files (*.cppcheck);;All files(*.*) Projektfiler (*.cppcheck);;Alla filer(*.*) - + Select Project File Välj projektfil - - - - + + + + Project: Projekt: - + No suitable files found to analyze! Inga filer hittades att analysera! - + C/C++ Source - + Compile database - + Visual Studio Visual Studio - + Borland C++ Builder 6 - + Select files to analyze Välj filer att analysera - + Select directory to analyze Välj mapp att analysera - + Select the configuration that will be analyzed Välj konfiguration som kommer analyseras - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1335,7 +1346,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1343,7 +1354,7 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1352,109 +1363,109 @@ Do you want to stop the analysis and exit Cppcheck? Vill du stoppa analysen och avsluta Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML filer (*.xml);;Text filer (*.txt);;CSV filer (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Build dir '%1' does not exist, create it? Build dir '%1' existerar ej, skapa den? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1463,22 +1474,22 @@ Analysis is stopped. Misslyckades att importera '%1', analysen stoppas - + Project files (*.cppcheck) Projekt filer (*.cppcheck) - + Select Project Filename Välj Projektfil - + No project file loaded Inget projekt laddat - + The project file %1 @@ -1495,12 +1506,12 @@ Do you want to remove the file from the recently used projects -list? Vill du ta bort filen från 'senast använda projekt'-listan? - + Install - + New version available: %1. %2 @@ -1843,12 +1854,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting (Premium) - + External tools @@ -1986,17 +2002,17 @@ Options: - + Bug hunting - + Clang analyzer Clang analyzer - + Clang-tidy Clang-tidy @@ -2009,82 +2025,82 @@ Options: ProjectFileDialog - + Project file: %1 Projektfil: %1 - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) - + Select Cppcheck build dir Välj Cppcheck build dir - + Select include directory Välj include sökväg - + Source files - + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) - + Select a directory to check Välj mapp att analysera - + Visual Studio Visual Studio - + Compile database - + Borland C++ Builder 6 - + Import Project Importera Projekt - + Select directory to ignore Välj sökväg att ignorera @@ -2119,7 +2135,7 @@ Options: - + (Not found) @@ -2169,158 +2185,158 @@ Options: - + Editor Foreground Color - + Editor Background Color - + Highlight Background Color - + Line Number Foreground Color - + Line Number Background Color - + Keyword Foreground Color - + Keyword Font Weight - + Class Foreground Color Class ForegroundColor - + Class Font Weight - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color - + Symbol Background Color - + Symbol Font Weight - + Set to Default Light - + Set to Default Dark - + File Fil - + Line Rad - + Severity Typ - + Classification - + Level - + Inconclusive Inconclusive - + Summary Sammanfattning - + Id Id - + Guideline - + Rule - + Since date Sedan datum - + Tags - + CWE @@ -2371,37 +2387,37 @@ Options: Odefinierad fil - + Copy - + Could not find file: - + Please select the folder '%1' - + Select Directory '%1' - + Please select the directory where file is located. - + debug debug - + note note @@ -2414,53 +2430,53 @@ Options: Dölj - + Hide all with id Dölj alla med id - + Suppress selected id(s) Stäng av valda id - + Open containing folder Öppna mapp - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag Tag - + No tag Ingen tag - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2470,7 +2486,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2479,12 +2495,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! Kunde inte hitta filen! - + Could not start %1 Please check the application path and parameters are correct. @@ -2493,7 +2509,7 @@ Please check the application path and parameters are correct. Kontrollera att sökvägen och parametrarna är korrekta. - + Select Directory Välj mapp @@ -2510,32 +2526,32 @@ Kontrollera att sökvägen och parametrarna är korrekta. Sedan datum - + style stil - + error fel - + warning varning - + performance prestanda - + portability portabilitet - + information information @@ -3203,10 +3219,18 @@ För att ställa in vilka fel som skall visas använd visa menyn. Informationsmeddelanden + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %1 av %2 filer analyserade diff --git a/gui/cppcheck_zh_CN.ts b/gui/cppcheck_zh_CN.ts index 5e329d74f3c..02477e72e81 100644 --- a/gui/cppcheck_zh_CN.ts +++ b/gui/cppcheck_zh_CN.ts @@ -332,42 +332,42 @@ Parameters: -l(line) (file) 编辑 - - + + Library files (*.cfg) 库文件 (*.cfg) - + Open library file 打开库文件 - - - + + + Cppcheck Cppcheck - + Cannot open file %1. Can not open file %1. 无法打开文件 %1。 - + Failed to load %1. %2. 加载文件 %1 失败。%2。 - + Cannot save file %1. Can not save file %1. 无法保存文件 %1。 - + Save the library as 库另存为 @@ -496,20 +496,20 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck @@ -529,271 +529,271 @@ Parameters: -l(line) (file) 工具栏(&T) - + &Help 帮助(&H) - + C++ standard C++ 标准 - + &C standard C standard &C 标准 - + &Edit 编辑(&E) - + Standard 标准 - + Categories 分类 - + &License... 许可证(&L)... - + A&uthors... 作者(&U)... - + &About... 关于(&A)... - + &Files... 文件(&F)... - - + + Analyze files Check files 分析文件 - + Ctrl+F Ctrl+F - + &Directory... 目录(&D)... - - + + Analyze directory Check directory 分析目录 - + Ctrl+D Ctrl+D - + Ctrl+R Ctrl+R - + &Stop 停止(&S) - - + + Stop analysis Stop checking 停止分析 - + Esc Esc - + &Save results to file... 保存结果到文件(&S)... - + Ctrl+S Ctrl+S - + &Quit 退出(&Q) - + &Clear results 清空结果(&C) - + &Preferences 首选项(&P) - - + + Show style warnings 显示风格警告 - - - + + + Show errors 显示错误 - + Information 信息 - + Show information messages 显示信息消息 - + Show portability warnings 显示可移植性警告 - + Show Cppcheck results 显示 Cppcheck 结果 - + Clang Clang - + Show Clang results 显示 Clang 结果 - + &Filter 滤器(&F) - + Filter results 过滤结果 - + Windows 32-bit ANSI - + Windows 32-bit Unicode - + Unix 32-bit - + Unix 64-bit - + Windows 64-bit - + &Print... 打印(&P)... - + Print the Current Report 打印当前报告 - + Print Pre&view... 打印预览(&v)... - + Open a Print Preview Dialog for the Current Results 打开当前结果的打印预览窗口 - + Open library editor 打开库编辑器 - + C&lose Project File 关闭项目文件(&L) - + &Edit Project File... 编辑项目文件(&E)... - + &Statistics 统计(&S) - - - + + + Show warnings 显示警告 - - + + Show performance warnings 显示性能警告 - + Show &hidden 显示隐藏项(&H) - + &Check all 全部选中(&C) @@ -809,288 +809,298 @@ Parameters: -l(line) (file) - + Report - + A&nalyze 分析(&A) - + Filter 滤器 - + &Reanalyze modified files &Recheck modified files 重新分析已修改的文件(&R) - + Reanal&yze all files 重新分析全部文件(&y) - + Ctrl+Q Ctrl+Q - + Style war&nings 风格警告(&n) - + E&rrors 编辑(&r) - + &Uncheck all 全部取消选中(&U) - + Collapse &all 全部折叠(&A) - + &Expand all 全部展开(&E) - + &Standard 标准(&S) - + Standard items 标准项 - + &Contents 内容(&C) - + Open the help contents 打开帮助内容 - + F1 F1 - + Toolbar 工具栏 - + &Categories 分类(&C) - + Error categories 错误分类 - + &Open XML... 打开 XML (&O)... - + Open P&roject File... 打开项目文件(&R)... - + Ctrl+Shift+O Ctrl+Shift+O - + Sh&ow Scratchpad... 显示便条(&o)... - + &New Project File... 新建项目文件(&N)... - + Ctrl+Shift+N Ctrl+Shift+N - + &Log View 日志视图(&L) - + Log View 日志视图 - + &Warnings 警告(&W) - + Per&formance warnings 性能警告(&f) - + &Information 信息(&I) - + &Portability 可移植性(&P) - + P&latforms 平台(&l) - + C++&11 C++&11 - + C&99 C&99 - + &Posix &Posix - + C&11 C&11 - + &C89 &C89 - + &C++03 &C++03 - + &Library Editor... 库编辑器(&L)... - + &Auto-detect language 自动检测语言(&A) - + &Enforce C++ &Enforce C++ - + E&nforce C E&nforce C - + C++14 C++14 - + Reanalyze and check library 重新分析并检查库 - + Check configuration (defines, includes) 检查配置(defines, includes) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal 常规 - + Misra C - + Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 - + Autosar - + EULA... - + + Thread Details + + + + + Show thread details + + + + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. @@ -1099,23 +1109,23 @@ This is probably because the settings were changed between the Cppcheck versions 这可能是因为 Cppcheck 不同版本间的设置有所不同。请检查(并修复)编辑器应用程序设置,否则编辑器程序可能不会正确启动。 - + You must close the project file before selecting new files or directories! 在选择新的文件或目录之前,你必须先关闭此项目文件! - - + + Quick Filter: 快速滤器: - + Select configuration 选择配置 - + Found project file: %1 Do you want to load this project file instead? @@ -1124,56 +1134,57 @@ Do you want to load this project file instead? 你是否想加载该项目文件? - + The library '%1' contains unknown elements: %2 库 '%1' 包含未知元素: %2 - + File not found 文件未找到 - + Bad XML 无效的 XML - + Missing attribute 缺失属性 - + Bad attribute value 无效的属性值 - + Unsupported format 不支持的格式 - + Duplicate platform type 重复的平台类型 - + Platform type redefined 平台类型重定义 - + Unknown element 位置元素 - Unknown issue - 未知问题 + Unknown element + Unknown issue + 未知问题 @@ -1183,10 +1194,10 @@ Do you want to load this project file instead? %2 - - - - + + + + Error 错误 @@ -1195,143 +1206,143 @@ Do you want to load this project file instead? 加载 %1 失败。您的 Cppcheck 安装已损坏。您可以在命令行添加 --data-dir=<目录> 参数来指定文件位置。请注意,'--data-dir' 参数应当由安装脚本使用,因此,当使用此参数时,GUI不会启动,所发生的一切只是配置了设置。 - - + + XML files (*.xml) XML 文件(*.xml) - + Open the report file 打开报告文件 - + License 许可证 - + Authors 作者 - + Save the report file 保存报告文件 - + Text files (*.txt) 文本文件(*.txt) - + CSV files (*.csv) CSV 文件(*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Project files (*.cppcheck);;All files(*.*) 项目文件(*.cppcheck);;所有文件(*.*) - + Select Project File 选择项目文件 - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Install - + New version available: %1. %2 - - - - + + + + Project: 项目: - + No suitable files found to analyze! 没有找到合适的文件来分析! - + C/C++ Source C/C++ 源码 - + Compile database Compile database - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze 选择要分析的文件 - + Select directory to analyze 选择要分析的目录 - + Select the configuration that will be analyzed 选择要分析的配置 - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1340,7 +1351,7 @@ Do you want to proceed analysis without using any of these project files? - + Duplicate define @@ -1355,29 +1366,29 @@ Do you want to proceed analysis without using any of these project files? - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1388,7 +1399,7 @@ Do you want to proceed? 你想继续吗? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1397,77 +1408,77 @@ Do you want to stop the analysis and exit Cppcheck? 您想停止分析并退出 Cppcheck 吗? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML 文件 (*.xml);;文本文件 (*.txt);;CSV 文件 (*.csv) - + Build dir '%1' does not exist, create it? 构建文件夹 '%1' 不能存在,创建它吗? - + To check the project using addons, you need a build directory. 要使用插件检查项目,您需要一个构建目录。 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1476,22 +1487,22 @@ Do you want to stop the analysis and exit Cppcheck? 导入 '%1' 失败,分析已停止 - + Project files (*.cppcheck) 项目文件 (*.cppcheck) - + Select Project Filename 选择项目文件名 - + No project file loaded 项目文件未加载 - + The project file %1 @@ -1860,12 +1871,17 @@ Options: - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting - + External tools 外部工具 @@ -1992,17 +2008,17 @@ Options: - + Bug hunting (Premium) - + Clang analyzer Clang analyzer - + Clang-tidy Clang-tidy @@ -2015,82 +2031,82 @@ Options: ProjectFileDialog - + Project file: %1 项目文件: %1 - + Select Cppcheck build dir 选择 Cppcheck 构建目录 - + Select include directory 选择 Include 目录 - + Select a directory to check 选择一个检查目录 - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) Clang-tidy (未找到) - + Visual Studio Visual Studio - + Compile database Compile database - + Borland C++ Builder 6 Borland C++ Builder 6 - + Import Project 导入项目 - + Select directory to ignore 选择忽略的目录 - + Source files 源文件 - + All files 全部文件 - + Exclude file 排除文件 - + Select MISRA rule texts file 选择 MISRA 规则文本文件 - + MISRA rule texts file (%1) MISRA 规则文本文件 (%1) @@ -2123,7 +2139,7 @@ Options: 第%1行:在 "%3" 中缺失的必选属性 "%2" - + (Not found) (未找到) @@ -2173,158 +2189,158 @@ Options: 极粗 - + Editor Foreground Color 编辑器前景色 - + Editor Background Color 编辑器背景色 - + Highlight Background Color 高亮背景色 - + Line Number Foreground Color 行号前景色 - + Line Number Background Color 行号背景色 - + Keyword Foreground Color 关键字前景色 - + Keyword Font Weight 关键字字体大小 - + Class Foreground Color Class ForegroundColor 类前景色 - + Class Font Weight 类字体大小 - + Quote Foreground Color 引用前景色 - + Quote Font Weight 引用字体大小 - + Comment Foreground Color 注释前景色 - + Comment Font Weight 注释字体大小 - + Symbol Foreground Color 符号前景色 - + Symbol Background Color 符号背景色 - + Symbol Font Weight 符号字体大小 - + Set to Default Light 设置为默认亮色 - + Set to Default Dark 设置为默认暗色 - + File 文件 - + Line - + Severity 严重性 - + Classification - + Level - + Inconclusive 不确定的 - + Summary 概要 - + Id Id - + Guideline - + Rule - + Since date 日期 - + Tags - + CWE @@ -2375,37 +2391,37 @@ Options: 未定义文件 - + Copy 复制 - + Could not find file: 找不到文件: - + Please select the folder '%1' 请选择文件夹 '%1' - + Select Directory '%1' 选择目录 '%1' - + Please select the directory where file is located. 请选择文件所在的目录。 - + debug 调试 - + note 注意 @@ -2418,53 +2434,53 @@ Options: 隐藏 - + Hide all with id 隐藏全部 ID - + Suppress selected id(s) 抑制选择的 ID - + Open containing folder 打开包含的文件夹 - + internal - + Recheck %1 file(s) - + Hide %1 result(s) - + Tag 标记 - + No tag 取消标记 - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. @@ -2474,7 +2490,7 @@ Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. @@ -2483,12 +2499,12 @@ Please select the default editor application in preferences/Applications. - + Could not find the file! 找不到文件! - + Could not start %1 Please check the application path and parameters are correct. @@ -2497,7 +2513,7 @@ Please check the application path and parameters are correct. 请检查此应用程序的路径与参数是否正确。 - + Select Directory 选择目录 @@ -2514,32 +2530,32 @@ Please check the application path and parameters are correct. 日期 - + style 风格 - + error 错误 - + warning 警告 - + performance 性能 - + portability 移植可能性 - + information 信息 @@ -3211,10 +3227,18 @@ To toggle what kind of errors are shown, open view menu. 信息 + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked %2 个文件已检查 %1 个 diff --git a/gui/cppcheck_zh_TW.ts b/gui/cppcheck_zh_TW.ts index c7c220899e8..644e92e7b49 100644 --- a/gui/cppcheck_zh_TW.ts +++ b/gui/cppcheck_zh_TW.ts @@ -322,40 +322,40 @@ Parameters: -l(line) (file) 編輯 - - + + Library files (*.cfg) 程式庫檔案 (*.cfg) - + Open library file 開啟程式庫檔案 - - - + + + Cppcheck Cppcheck - + Cannot open file %1. 無法開啟檔案 %1。 - + Failed to load %1. %2. 無法載入 %1. %2。 - + Cannot save file %1. 無法儲存檔案 %1。 - + Save the library as 另存程式庫為 @@ -474,20 +474,20 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - + + + + + + + + + + + + + + Cppcheck Cppcheck @@ -518,545 +518,555 @@ Parameters: -l(line) (file) - + Report - + &Help 幫助(&H) - + A&nalyze 分析(&N) - + C++ standard C++ 標準 - + &C standard C 標準(&C) - + &Edit 編輯(&E) - + Standard 標準 - + Categories 分類 - + Filter 篩選 - + &License... 授權(&L)... - + A&uthors... 作者(&U)... - + &About... 關於(&A)... - + &Files... 檔案(&F)... - - + + Analyze files 分析檔案 - + Ctrl+F Ctrl+F - + &Directory... 目錄(&D)... - - + + Analyze directory 分析目錄 - + Ctrl+D Ctrl+D - + &Reanalyze modified files 重新分析已修改的檔案(&R) - + Ctrl+R Ctrl+R - + Reanal&yze all files 重新分析所有檔案(&Y) - + &Stop 停止(&S) - - + + Stop analysis 停止分析 - + Esc Esc - + &Save results to file... 儲存結果為檔案(&S)... - + Ctrl+S Ctrl+S - + &Quit 退出(&Q) - + Ctrl+Q Ctrl+Q - + &Clear results 清除結果(&C) - + &Preferences 偏好設定(&P) - + Style war&nings 樣式警告(&N) - - + + Show style warnings 顯示樣式警告 - + E&rrors 錯誤(&R) - - - + + + Show errors 顯示錯誤 - + &Check all 全部檢查(&C) - + &Uncheck all - + Collapse &all 全部摺疊(&A) - + &Expand all 全部展開(&E) - + &Standard 標準(&S) - + Standard items 標準項目 - + &Contents 內容(&C) - + Open the help contents 開啟幫助內容 - + F1 F1 - + Toolbar 工具條 - + &Categories 分類(&C) - + Error categories 錯誤分類 - + &Open XML... 開啟 XML(&O)... - + Open P&roject File... 開啟專案檔(&R)... - + Ctrl+Shift+O Ctrl+Shift+O - + Sh&ow Scratchpad... - + &New Project File... 新增專案檔(&N)... - + Ctrl+Shift+N Ctrl+Shift+N - + &Log View 日誌檢視(&L) - + Log View 日誌檢視 - + C&lose Project File 關閉專案檔(&L) - + &Edit Project File... 編輯專案檔(&E)... - + &Statistics 統計資料(&S) - + &Warnings 警告(&W) - - - + + + Show warnings 顯示警告 - + Per&formance warnings 效能警告(&F) - - + + Show performance warnings 顯示下效能警告 - + Show &hidden 顯示隱藏項目(&H) - + &Information 資訊(&I) - + Show information messages 顯示資訊訊息 - + &Portability 可移植性(&P) - + Show portability warnings 顯示可移植性警告 - + Show Cppcheck results 顯示 Cppcheck 結果 - + Clang Clang - + Show Clang results 顯示 Clang 結果 - + &Filter 篩選(&F) - + Filter results 篩選結果 - + Windows 32-bit ANSI Windows 32 位元 ANSI - + Windows 32-bit Unicode Windows 32 位元 Unicode - + Unix 32-bit Unix 32 位元 - + Unix 64-bit Unix 64 位元 - + Windows 64-bit Windows 64 位元 - + P&latforms 平臺(&L) - + C++&11 C++&11 - + C&99 C&99 - + &Posix - + C&11 C&11 - + &C89 &C89 - + &C++03 &C++03 - + &Print... 列印(&P)... - + Print the Current Report 列印當前報告 - + Print Pre&view... 列印預覽(&V)... - + Open a Print Preview Dialog for the Current Results 開啟當前結果的列印預覽視窗 - + &Library Editor... 程式庫編輯器(&L)... - + Open library editor 開啟程式庫編輯器 - + &Auto-detect language 自動偵測語言(&A) - + &Enforce C++ - + E&nforce C - + C++14 C++14 - + Reanalyze and check library 重新分析並檢查程式庫 - + Check configuration (defines, includes) 檢查組態 (定義、包含) - + C++17 C++17 - + C++20 C++20 - + Compliance report... - + Normal - + Misra C - + Misra C++ 2008 Misra C++ 2008 - + Cert C - + Cert C++ - + Misra C++ 2023 Misra C++ 2023 - + Autosar - + EULA... + + + Thread Details + + + + + Show thread details + + Cppcheck GUI. @@ -1081,151 +1091,152 @@ Options: Cppcheck GUI - 命令行參數 - - + + Quick Filter: 快速篩選: - - - - + + + + Project: 專案: - + There was a problem with loading the editor application settings. This is probably because the settings were changed between the Cppcheck versions. Please check (and fix) the editor application settings, otherwise the editor program might not start correctly. - + No suitable files found to analyze! 找不到適合的檔案來分析! - + You must close the project file before selecting new files or directories! 您必須在選取新檔案或目錄之前關閉該專案檔! - + C/C++ Source C/C++ 來源檔 - + Compile database 編譯資料庫 - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze 選取要分析的檔案 - + Select directory to analyze 選取要分析的目錄 - + Select configuration 選取組態 - + Select the configuration that will be analyzed 選取要分析的組態 - + Found project file: %1 Do you want to load this project file instead? - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Information 資訊 - + The library '%1' contains unknown elements: %2 - + File not found 找不到檔案 - + Bad XML - + Missing attribute - + Bad attribute value - + Unsupported format 未支援的格式 - + Duplicate platform type 重複的平臺型別 - + Platform type redefined 平臺型別重定義 - + Duplicate define - + Unknown element 未知的元素 - Unknown issue - 未知的議題 + Unknown element + Unknown issue + 未知的議題 @@ -1245,37 +1256,37 @@ Do you want to proceed analysis without using any of these project files? - - - - + + + + Error 錯誤 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1283,18 +1294,18 @@ Do you want to proceed? - - + + XML files (*.xml) XML 檔案 (*.xml) - + Open the report file 開啟報告檔 - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1303,82 +1314,82 @@ Do you want to stop the analysis and exit Cppcheck? 您想停止分析並離開 Cppcheck 嗎? - + About 關於 - + License 授權 - + Authors 作者 - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML 檔案 (*.xml);;文字檔 (*.txt);;CSV 檔案 (*.csv) - + Save the report file 儲存報告檔 - + Text files (*.txt) 文字檔 (*.txt) - + CSV files (*.csv) CSV 檔案 (*.csv) - + Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors. - + Project files (*.cppcheck);;All files(*.*) 專案檔 (*.cppcheck);;所有檔案 (*.*) - + Select Project File 選取專案檔 - + Build dir '%1' does not exist, create it? 建置目錄 '%1' 不存在,是否建立它? - + To check the project using addons, you need a build directory. - + Failed to open file 無法開啟檔案 - + Unknown project file format 未知的專案檔格式 - + Failed to import project file 無法匯入專案檔 - + Failed to import '%1': %2 Analysis is stopped. @@ -1387,62 +1398,62 @@ Analysis is stopped. 停止分析。 - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1451,22 +1462,22 @@ Analysis is stopped. 無法匯入 '%1',停止分析 - + Project files (*.cppcheck) 專案檔 (*.cppcheck) - + Select Project Filename 選取專案檔案名稱 - + No project file loaded - + The project file %1 @@ -1483,12 +1494,12 @@ Do you want to remove the file from the recently used projects -list? 您要從最近使用的專案列表中移除該檔案嗎? - + Install 安章 - + New version available: %1. %2 可用的新版本: %1. %2 @@ -1926,27 +1937,32 @@ Do you want to remove the file from the recently used projects -list? - + + Safety profiles (defined in C++ core guidelines) + + + + Bug hunting (Premium) - + Bug hunting - + External tools 外部工具 - + Clang-tidy Clang-tidy - + Clang analyzer Clang 分析器 @@ -1954,82 +1970,82 @@ Do you want to remove the file from the recently used projects -list? ProjectFileDialog - + Project file: %1 專案檔: %1 - + Note: Open source Cppcheck does not fully implement Misra C 2012 - + Clang-tidy (not found) Clang-tidy (找不到) - + Select Cppcheck build dir 選取 Cppcheck 建置目錄 - + Visual Studio Visual Studio - + Compile database 編譯資料庫 - + Borland C++ Builder 6 Borland C++ Builder 6 - + Import Project 匯入專案 - + Select a directory to check 選取要檢查的目錄 - + Select include directory 選取包含目錄 - + Select directory to ignore 選取要忽略的目錄 - + Source files 來源檔 - + All files 所有檔案 - + Exclude file 排除檔案 - + Select MISRA rule texts file 選取 MISRA 規則文字檔 - + MISRA rule texts file (%1) MISRA 規則文字檔 (%1) @@ -2082,92 +2098,92 @@ Do you want to remove the file from the recently used projects -list? - + Editor Foreground Color 編輯器前景色 - + Editor Background Color 編輯器背景色 - + Highlight Background Color 標明背景色 - + Line Number Foreground Color 行號前景色 - + Line Number Background Color 行號背景色 - + Keyword Foreground Color 關鍵字前景色 - + Keyword Font Weight - + Class Foreground Color 類別前景色 - + Class Font Weight 類別字型粗細 - + Quote Foreground Color - + Quote Font Weight - + Comment Foreground Color - + Comment Font Weight - + Symbol Foreground Color 符號前景色 - + Symbol Background Color 符號被景色 - + Symbol Font Weight 符號字型粗細 - + Set to Default Light - + Set to Default Dark @@ -2182,7 +2198,7 @@ Do you want to remove the file from the recently used projects -list? - + (Not found) (找不到) @@ -2202,67 +2218,67 @@ Do you want to remove the file from the recently used projects -list? - + File 檔案 - + Line 行號 - + Severity 安全性 - + Classification - + Level - + Inconclusive - + Summary - + Id 識別號 - + Guideline - + Rule - + Since date - + Tags - + CWE @@ -2297,52 +2313,52 @@ Do you want to remove the file from the recently used projects -list? 未定義的檔案 - + note - + style 樣式 - + error 錯誤 - + warning 警告 - + performance 效能 - + portability - + information 資訊 - + debug - + internal - + Copy 複製 @@ -2351,94 +2367,94 @@ Do you want to remove the file from the recently used projects -list? 隱藏 - + Recheck %1 file(s) - + Hide %1 result(s) - + Hide all with id - + Open containing folder - + Suppress selected id(s) - + Tag 標記 - + No tag 取消標記 - - + + Cppcheck Cppcheck - + No editor application configured. Configure the editor application for Cppcheck in preferences/Applications. - + No default editor application selected. Please select the default editor application in preferences/Applications. - + Could not find the file! 找不到該檔案! - + Could not start %1 Please check the application path and parameters are correct. - + Could not find file: - + Please select the folder '%1' 請選取資料夾 '%1' - + Select Directory '%1' 選取目錄 '%1' - + Please select the directory where file is located. 請選取資料夾所在的目錄。 - + Select Directory 選取目錄 @@ -3112,10 +3128,18 @@ To toggle what kind of errors are shown, open view menu. 掃描時間 + + ThreadDetails + + + Thread Details + + + ThreadResult - + %1 of %2 files checked diff --git a/gui/cppchecklibrarydata.h b/gui/cppchecklibrarydata.h index afe39df5050..ddccf3b6534 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.h @@ -19,8 +19,6 @@ #ifndef CPPCHECKLIBRARYDATA_H #define CPPCHECKLIBRARYDATA_H -#include "config.h" - #include #include @@ -230,7 +228,7 @@ class CppcheckLibraryData { entrypoints.clear(); } - void swap(CppcheckLibraryData &other) NOEXCEPT { + void swap(CppcheckLibraryData &other) noexcept { containers.swap(other.containers); defines.swap(other.defines); undefines.swap(other.undefines); diff --git a/gui/erroritem.h b/gui/erroritem.h index 554052ccba9..54c5a32a7f3 100644 --- a/gui/erroritem.h +++ b/gui/erroritem.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +23,6 @@ #include "errortypes.h" #include -#include #include /// @addtogroup GUI diff --git a/gui/gui.pro b/gui/gui.pro index 132f113d270..37c70471b9a 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -58,7 +58,6 @@ win32 { RESOURCES = gui.qrc FORMS = about.ui \ applicationdialog.ui \ - compliancereportdialog.ui \ fileview.ui \ helpdialog.ui \ mainwindow.ui \ @@ -70,7 +69,8 @@ FORMS = about.ui \ librarydialog.ui \ libraryaddfunctiondialog.ui \ libraryeditargdialog.ui \ - newsuppressiondialog.ui + newsuppressiondialog.ui \ + threaddetails.ui TRANSLATIONS = cppcheck_de.ts \ cppcheck_es.ts \ @@ -137,7 +137,6 @@ HEADERS += aboutdialog.h \ codeeditstyledialog.h \ codeeditor.h \ common.h \ - compliancereportdialog.h \ csvreport.h \ erroritem.h \ filelist.h \ @@ -156,6 +155,7 @@ HEADERS += aboutdialog.h \ settingsdialog.h \ showtypes.h \ statsdialog.h \ + threaddetails.h \ threadhandler.h \ threadresult.h \ translationhandler.h \ @@ -179,7 +179,6 @@ SOURCES += aboutdialog.cpp \ codeeditstyledialog.cpp \ codeeditor.cpp \ common.cpp \ - compliancereportdialog.cpp \ csvreport.cpp \ erroritem.cpp \ filelist.cpp \ @@ -199,6 +198,7 @@ SOURCES += aboutdialog.cpp \ settingsdialog.cpp \ showtypes.cpp \ statsdialog.cpp \ + threaddetails.cpp \ threadhandler.cpp \ threadresult.cpp \ translationhandler.cpp \ diff --git a/gui/helpdialog.cpp b/gui/helpdialog.cpp index db1125339b9..0768318531c 100644 --- a/gui/helpdialog.cpp +++ b/gui/helpdialog.cpp @@ -19,6 +19,7 @@ #include "helpdialog.h" #include "common.h" +#include "utils.h" #include "ui_helpdialog.h" @@ -65,7 +66,7 @@ static QString getHelpFile() paths << (filesdir + "/help") << filesdir; #endif - for (const QString &p: paths) { + for (const QString &p: utils::as_const(paths)) { QString filename = p + "/online-help.qhc"; if (QFileInfo::exists(filename)) return filename; diff --git a/gui/helpdialog.h b/gui/helpdialog.h index da80f61ca02..4f592f5c7f6 100644 --- a/gui/helpdialog.h +++ b/gui/helpdialog.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +22,6 @@ #include #include #include -#include class QHelpEngine; class QWidget; diff --git a/gui/librarydialog.cpp b/gui/librarydialog.cpp index 15a2c7f10fe..3199af9a975 100644 --- a/gui/librarydialog.cpp +++ b/gui/librarydialog.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -168,7 +167,7 @@ void LibraryDialog::saveCfg() void LibraryDialog::saveCfgAs() { const QString filter(tr("Library files (*.cfg)")); - const QString path = Path::getPathFromFilename(mFileName.toStdString()).c_str(); + const QString path = QString::fromStdString(Path::getPathFromFilename(mFileName.toStdString())); QString selectedFile = QFileDialog::getSaveFileName(this, tr("Save the library as"), path, @@ -293,11 +292,11 @@ void LibraryDialog::filterFunctions(const QString& filter) QList allItems = mUi->functions->findItems(QString(), Qt::MatchContains); if (filter.isEmpty()) { - for (QListWidgetItem *item : allItems) { + for (QListWidgetItem *item : utils::as_const(allItems)) { item->setHidden(false); } } else { - for (QListWidgetItem *item : allItems) { + for (QListWidgetItem *item : utils::as_const(allItems)) { item->setHidden(!item->text().startsWith(filter)); } } diff --git a/gui/librarydialog.h b/gui/librarydialog.h index 285d36a820a..6737da638c8 100644 --- a/gui/librarydialog.h +++ b/gui/librarydialog.h @@ -47,10 +47,10 @@ private slots: void addFunction(); void changeFunction(); void editArg(); - void editFunctionName(QListWidgetItem* /*item*/); - void filterFunctions(const QString& /*filter*/); + void editFunctionName(QListWidgetItem* item); + void filterFunctions(const QString& filter); void selectFunction(); - void sortFunctions(bool /*sort*/); + void sortFunctions(bool sort); private: Ui::LibraryDialog *mUi; diff --git a/gui/main.cpp b/gui/main.cpp index 830cb29a72d..efdb2a33c72 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -124,7 +124,7 @@ static void ShowUsage() static void ShowVersion() { -// TODO: should only *not* show a dialog when we are on a commnd-line +// TODO: should only *not* show a dialog when we are on a command-line #if defined(_WIN32) AboutDialog *dlg = new AboutDialog(CppCheck::version(), CppCheck::extraVersion(), 0); dlg->exec(); diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 2d71ef5e7c6..ce1b3ef1508 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,6 @@ #include "errortypes.h" #include "filelist.h" #include "filesettings.h" -#include "compliancereportdialog.h" #include "fileviewdialog.h" #include "helpdialog.h" #include "importproject.h" @@ -53,6 +52,7 @@ #include "threadresult.h" #include "translationhandler.h" #include "utils.h" +#include "threaddetails.h" #include "ui_mainwindow.h" @@ -183,6 +183,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) : connect(mUI->mActionShowHidden, &QAction::triggered, mUI->mResults, &ResultsView::showHiddenResults); connect(mUI->mActionViewStats, &QAction::triggered, this, &MainWindow::showStatistics); connect(mUI->mActionLibraryEditor, &QAction::triggered, this, &MainWindow::showLibraryEditor); + connect(mUI->mActionShowThreadDetails, &QAction::triggered, this, &MainWindow::showThreadDetails); connect(mUI->mActionReanalyzeModified, &QAction::triggered, this, &MainWindow::reAnalyzeModified); connect(mUI->mActionReanalyzeAll, &QAction::triggered, this, &MainWindow::reAnalyzeAll); @@ -191,7 +192,6 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) : connect(mUI->mActionStop, &QAction::triggered, this, &MainWindow::stopAnalysis); connect(mUI->mActionSave, &QAction::triggered, this, &MainWindow::save); - connect(mUI->mActionComplianceReport, &QAction::triggered, this, &MainWindow::complianceReport); // About menu connect(mUI->mActionAbout, &QAction::triggered, this, &MainWindow::about); @@ -243,8 +243,6 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) : formatAndSetTitle(); } - mUI->mActionComplianceReport->setVisible(isCppcheckPremium()); - enableCheckButtons(true); mUI->mActionPrint->setShortcut(QKeySequence::Print); @@ -564,7 +562,7 @@ void MainWindow::saveSettings() const mUI->mResults->saveSettings(mSettings); } -void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, const bool checkConfiguration) +void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bool checkConfig) { Settings checkSettings; auto supprs = std::make_shared(); @@ -595,7 +593,6 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons enableProjectActions(false); } - mUI->mResults->clear(true); mUI->mResults->setResultsSource(ResultsTree::ResultsSource::Analysis); mThread->clearFiles(); @@ -609,8 +606,8 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons mUI->mResults->setCheckDirectory(checkPath); checkSettings.force = false; - checkSettings.checkLibrary = checkLibrary; - checkSettings.checkConfiguration = checkConfiguration; + checkSettings.checkLibrary = checkLib; + checkSettings.checkConfiguration = checkConfig; if (mProjectFile) qDebug() << "Checking project file" << mProjectFile->getFilename(); @@ -618,7 +615,7 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons if (!checkSettings.buildDir.empty()) { checkSettings.loadSummaries(); std::list sourcefiles; - AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, checkSettings.userDefines, p.fileSettings); + AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, p.fileSettings); } //mThread->SetanalyzeProject(true); @@ -637,7 +634,7 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons mUI->mResults->setCheckSettings(checkSettings); } -void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrary, const bool checkConfiguration) +void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, const bool checkConfig) { if (files.isEmpty()) return; @@ -678,7 +675,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar // TODO: lock UI here? mUI->mResults->checkingStarted(fdetails.size()); mThread->setFiles(std::move(fdetails)); - if (mProjectFile && !checkConfiguration) + if (mProjectFile && !checkConfig) mThread->setAddonsAndTools(mProjectFile->getAddonsAndTools()); mThread->setSuppressions(mProjectFile ? mProjectFile->getCheckingSuppressions() : QList()); QDir inf(mCurrentDirectory); @@ -688,8 +685,8 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar checkLockDownUI(); // lock UI while checking mUI->mResults->setCheckDirectory(checkPath); - checkSettings.checkLibrary = checkLibrary; - checkSettings.checkConfiguration = checkConfiguration; + checkSettings.checkLibrary = checkLib; + checkSettings.checkConfiguration = checkConfig; if (mProjectFile) qDebug() << "Checking project file" << mProjectFile->getFilename(); @@ -700,7 +697,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar std::transform(fileNames.cbegin(), fileNames.cend(), std::back_inserter(sourcefiles), [](const QString& s) { return s.toStdString(); }); - AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, checkSettings.userDefines, {}); + AnalyzerInformation::writeFilesTxt(checkSettings.buildDir, sourcefiles, {}); } mThread->setCheckFiles(true); @@ -767,7 +764,7 @@ QStringList MainWindow::selectFilesToAnalyze(QFileDialog::FileMode mode) QMap filters; filters[tr("C/C++ Source")] = FileList::getDefaultFilters().join(" "); filters[tr("Compile database")] = compile_commands_json; - filters[tr("Visual Studio")] = "*.sln *.vcxproj"; + filters[tr("Visual Studio")] = "*.sln *.slnx *.vcxproj"; filters[tr("Borland C++ Builder 6")] = "*.bpr"; QString lastFilter = mSettings->value(SETTINGS_LAST_ANALYZE_FILES_FILTER).toString(); selected = QFileDialog::getOpenFileNames(this, @@ -810,13 +807,14 @@ void MainWindow::analyzeFiles() const QString file0 = (!selected.empty() ? selected[0].toLower() : QString()); if (file0.endsWith(".sln") + || file0.endsWith(".slnx") || file0.endsWith(".vcxproj") || file0.endsWith(compile_commands_json) || file0.endsWith(".bpr")) { ImportProject p; p.import(selected[0].toStdString()); - if (file0.endsWith(".sln")) { + if (file0.endsWith(".sln") || file0.endsWith(".slnx")) { QStringList configs; for (auto it = p.fileSettings.cbegin(); it != p.fileSettings.cend(); ++it) { const QString cfg(QString::fromStdString(it->cfg)); @@ -1016,9 +1014,6 @@ bool MainWindow::tryLoadLibrary(Library &library, const QString& filename) case Library::ErrorCode::UNKNOWN_ELEMENT: errmsg = tr("Unknown element"); break; - default: - errmsg = tr("Unknown issue"); - break; } if (!error.reason.empty()) errmsg += " '" + QString::fromStdString(error.reason) + "'"; @@ -1072,6 +1067,7 @@ bool MainWindow::getCppcheckSettings(Settings& settings, Suppressions& supprs) settings.exename = QCoreApplication::applicationFilePath().toStdString(); settings.templateFormat = "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]"; + settings.reportProgress = 10; // default to --check-level=normal for GUI for now settings.setCheckLevel(Settings::CheckLevel::normal); @@ -1126,6 +1122,8 @@ bool MainWindow::getCppcheckSettings(Settings& settings, Suppressions& supprs) for (const QString& undefine : undefines) settings.userUndefs.insert(undefine.toStdString()); + mProjectFile->setSettingsUserIncludes(settings); + const QStringList libraries = mProjectFile->getLibraries(); for (const QString& library : libraries) { settings.libraries.emplace_back(library.toStdString()); @@ -1528,10 +1526,6 @@ void MainWindow::enableCheckButtons(bool enable) } mUI->mActionAnalyzeDirectory->setEnabled(enable); - - if (isCppcheckPremium()) { - mUI->mActionComplianceReport->setEnabled(enable && mProjectFile && (mProjectFile->getAddons().contains("misra") || !mProjectFile->getCodingStandards().empty())); - } } void MainWindow::enableResultsButtons() @@ -1705,28 +1699,6 @@ void MainWindow::save() } } -void MainWindow::complianceReport() -{ - if (!mUI->mResults->isSuccess()) { - QMessageBox m(QMessageBox::Critical, - "Cppcheck", - tr("Cannot generate a compliance report right now, an analysis must finish successfully. Try to reanalyze the code and ensure there are no critical errors."), - QMessageBox::Ok, - this); - m.exec(); - return; - } - - QTemporaryFile tempResults; - (void)tempResults.open(); // TODO: check result - tempResults.close(); - - mUI->mResults->save(tempResults.fileName(), Report::XMLV2, mCppcheckCfgProductName); - - ComplianceReportDialog dlg(mProjectFile, tempResults.fileName(), mUI->mResults->getStatistics()->getCheckersReport()); - dlg.exec(); -} - void MainWindow::resultsAdded() { enableResultsButtons(); @@ -1884,37 +1856,13 @@ bool MainWindow::loadLastResults() return true; } -void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringList& recheckFiles, const bool checkLibrary, const bool checkConfiguration) +void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringList& recheckFiles, const bool checkLib, const bool checkConfig) { Settings::terminate(false); QFileInfo inf(projectFile->getFilename()); const QString& rootpath = projectFile->getRootPath(); - if (isCppcheckPremium() && !projectFile->getLicenseFile().isEmpty()) { - if (rootpath.isEmpty() || rootpath == ".") - QDir::setCurrent(inf.absolutePath()); - else if (QDir(rootpath).isAbsolute()) - QDir::setCurrent(rootpath); - else - QDir::setCurrent(inf.absolutePath() + "/" + rootpath); - - QString licenseFile = projectFile->getLicenseFile(); - if (!QFileInfo(licenseFile).isAbsolute() && !rootpath.isEmpty()) - licenseFile = inf.absolutePath() + "/" + licenseFile; - -#ifdef Q_OS_WIN - const QString premiumaddon = QCoreApplication::applicationDirPath() + "/premiumaddon.exe"; -#else - const QString premiumaddon = QCoreApplication::applicationDirPath() + "/premiumaddon"; -#endif - const std::vector args{"--check-loc-license", licenseFile.toStdString()}; - std::string output; - CheckThread::executeCommand(premiumaddon.toStdString(), args, "", output); - std::ofstream fout(inf.absolutePath().toStdString() + "/cppcheck-premium-loc"); - fout << output; - } - QDir::setCurrent(inf.absolutePath()); mThread->setAddonsAndTools(projectFile->getAddonsAndTools()); @@ -1969,6 +1917,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis switch (result) { case ImportProject::Type::COMPILE_DB: case ImportProject::Type::VS_SLN: + case ImportProject::Type::VS_SLNX: case ImportProject::Type::VS_VCXPROJ: case ImportProject::Type::BORLAND: case ImportProject::Type::CPPCHECK_GUI: @@ -2012,7 +1961,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis msg.exec(); return; } - doAnalyzeProject(p, checkLibrary, checkConfiguration); // TODO: avoid copy + doAnalyzeProject(p, checkLib, checkConfig); // TODO: avoid copy return; } @@ -2025,7 +1974,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis if (paths.isEmpty()) { paths << mCurrentDirectory; } - doAnalyzeFiles(paths, checkLibrary, checkConfiguration); + doAnalyzeFiles(paths, checkLib, checkConfig); } void MainWindow::newProjectFile() @@ -2112,6 +2061,20 @@ void MainWindow::showLibraryEditor() libraryDialog.exec(); } +void MainWindow::showThreadDetails() +{ + if (ThreadDetails::instance()) + return; + auto* threadDetails = new ThreadDetails(this); + connect(mThread, &ThreadHandler::threadDetailsUpdated, + threadDetails, &ThreadDetails::threadDetailsUpdated, Qt::QueuedConnection); + connect(mThread, &ThreadHandler::progress, + threadDetails, &ThreadDetails::progress, Qt::QueuedConnection); + threadDetails->setAttribute(Qt::WA_DeleteOnClose); + threadDetails->show(); + mThread->emitThreadDetailsUpdated(); +} + void MainWindow::filterResults() { mUI->mResults->filterResults(mLineEditFilter->text()); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 76fda4f0de6..febd3a41d4c 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -176,9 +176,6 @@ public slots: /** @brief Slot to save results */ void save(); - /** @brief Slot to generate compliance report */ - void complianceReport(); - /** @brief Slot to create new project file */ void newProjectFile(); @@ -200,6 +197,9 @@ public slots: /** @brief Slot for showing the library editor */ void showLibraryEditor(); + /** @brief Slot for showing the thread details window */ + void showThreadDetails(); + private slots: /** @brief Slot for checkthread's done signal */ @@ -267,10 +267,10 @@ private slots: * @brief Analyze the project. * @param projectFile Pointer to the project to analyze. * @param recheckFiles files to recheck, empty => check all files - * @param checkLibrary Flag to indicate if the library should be checked. - * @param checkConfiguration Flag to indicate if the configuration should be checked. + * @param checkLib Flag to indicate if the library should be checked. + * @param checkConfig Flag to indicate if the configuration should be checked. */ - void analyzeProject(const ProjectFile *projectFile, const QStringList& recheckFiles, bool checkLibrary = false, bool checkConfiguration = false); + void analyzeProject(const ProjectFile *projectFile, const QStringList& recheckFiles, bool checkLib = false, bool checkConfig = false); /** * @brief Set current language @@ -306,19 +306,19 @@ private slots: /** * @brief Analyze project * @param p imported project - * @param checkLibrary Flag to indicate if library should be checked - * @param checkConfiguration Flag to indicate if the configuration should be checked. + * @param checkLib Flag to indicate if library should be checked + * @param checkConfig Flag to indicate if the configuration should be checked. */ - void doAnalyzeProject(ImportProject p, bool checkLibrary = false, bool checkConfiguration = false); + void doAnalyzeProject(ImportProject p, bool checkLib = false, bool checkConfig = false); /** * @brief Analyze all files specified in parameter files * * @param files List of files and/or directories to analyze - * @param checkLibrary Flag to indicate if library should be checked - * @param checkConfiguration Flag to indicate if the configuration should be checked. + * @param checkLib Flag to indicate if library should be checked + * @param checkConfig Flag to indicate if the configuration should be checked. */ - void doAnalyzeFiles(const QStringList &files, bool checkLibrary = false, bool checkConfiguration = false); + void doAnalyzeFiles(const QStringList &files, bool checkLib = false, bool checkConfig = false); /** * @brief Get our default cppcheck settings and read project file. diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index a90949344e2..1f66d1a582a 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -64,7 +64,7 @@ - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint @@ -84,13 +84,13 @@ Checking for updates - Qt::RichText + Qt::TextFormat::RichText true - Qt::TextBrowserInteraction + Qt::TextInteractionFlag::TextBrowserInteraction @@ -104,7 +104,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -124,7 +124,7 @@ 0 0 640 - 22 + 21 @@ -140,7 +140,6 @@ - @@ -192,6 +191,7 @@ + @@ -1040,6 +1040,14 @@ EULA... + + + Thread Details + + + Show thread details + + diff --git a/gui/manualtest/projectfiledialog.md b/gui/manualtest/projectfiledialog.md new file mode 100644 index 00000000000..f11b030f246 --- /dev/null +++ b/gui/manualtest/projectfiledialog.md @@ -0,0 +1,38 @@ + +# Project file dialog + +Some manual testing in the project file dialog interface + + +## Test: Platform file pic8.xml + +Ticket: #14489 + +EXPECTED: In the project file dialog it should be possible to select xml files i.e. pic8.xml + +TODO: can this test be automated + + +## Test: Custom cfg file + +Ticket: #14672 + +1. Copy addons/avr.cfg to a file "aa.cfg" in same folder as a cppcheck GUI project file + +EXPECTED: It should not be possible to activate "aa.cfg" in the project file dialog, it should appear in alphabetical order. + + +## Test: Misra C checkbox + +Ticket: #14488 + +Matrix: Use both open source and premium + +1. Load project file in trac ticket 14488 +1. Goto "Edit project" +1. Goto "Addons" tab + +EXPECTED: The misra c checkbox should be checked + +TODO: can this test be automated + diff --git a/gui/projectfile.cpp b/gui/projectfile.cpp index 3e4e783d7a8..9144f5a6117 100644 --- a/gui/projectfile.cpp +++ b/gui/projectfile.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -62,6 +63,7 @@ void ProjectFile::clear() mIncludeDirs.clear(); mDefines.clear(); mUndefines.clear(); + mUserInclude.clear(); mPaths.clear(); mExcludedPaths.clear(); mLibraries.clear(); @@ -86,7 +88,6 @@ void ProjectFile::clear() mBughunting = false; mCertIntPrecision = 0; mCodingStandards.clear(); - mPremiumLicenseFile.clear(); } bool ProjectFile::read(const QString &filename) @@ -165,6 +166,9 @@ bool ProjectFile::read(const QString &filename) if (xmlReader.name() == QString(CppcheckXml::UndefinesElementName)) readStringList(mUndefines, xmlReader, CppcheckXml::UndefineName); + if (xmlReader.name() == QString(CppcheckXml::UserIncludeElementName)) + mUserInclude = readString(xmlReader); + // Find exclude list from inside project element if (xmlReader.name() == QString(CppcheckXml::ExcludeElementName)) readExcludes(xmlReader); @@ -228,8 +232,6 @@ bool ProjectFile::read(const QString &filename) readStringList(mCodingStandards, xmlReader, CppcheckXml::CodingStandardElementName); if (xmlReader.name() == QString(CppcheckXml::CertIntPrecisionElementName)) mCertIntPrecision = readInt(xmlReader, 0); - if (xmlReader.name() == QString(CppcheckXml::LicenseFileElementName)) - mPremiumLicenseFile = readString(xmlReader); if (xmlReader.name() == QString(CppcheckXml::ProjectNameElementName)) mProjectName = readString(xmlReader); @@ -346,15 +348,13 @@ bool ProjectFile::readBool(QXmlStreamReader &reader) int ProjectFile::readInt(QXmlStreamReader &reader, int defaultValue) { - int ret = defaultValue; do { const QXmlStreamReader::TokenType type = reader.readNext(); switch (type) { case QXmlStreamReader::Characters: - ret = reader.text().toString().toInt(); - FALLTHROUGH; + return reader.text().toString().toInt(); case QXmlStreamReader::EndElement: - return ret; + return defaultValue; // Not handled case QXmlStreamReader::StartElement: case QXmlStreamReader::NoToken: @@ -372,15 +372,13 @@ int ProjectFile::readInt(QXmlStreamReader &reader, int defaultValue) QString ProjectFile::readString(QXmlStreamReader &reader) { - QString ret; do { const QXmlStreamReader::TokenType type = reader.readNext(); switch (type) { case QXmlStreamReader::Characters: - ret = reader.text().toString(); - FALLTHROUGH; + return reader.text().toString(); case QXmlStreamReader::EndElement: - return ret; + return {}; // Not handled case QXmlStreamReader::StartElement: case QXmlStreamReader::NoToken: @@ -891,7 +889,7 @@ bool ProjectFile::write(const QString &filename) if (!mIncludeDirs.isEmpty()) { xmlWriter.writeStartElement(CppcheckXml::IncludeDirElementName); - for (const QString& incdir : mIncludeDirs) { + for (const QString& incdir : utils::as_const(mIncludeDirs)) { xmlWriter.writeStartElement(CppcheckXml::DirElementName); xmlWriter.writeAttribute(CppcheckXml::DirNameAttrib, incdir); xmlWriter.writeEndElement(); @@ -901,7 +899,7 @@ bool ProjectFile::write(const QString &filename) if (!mDefines.isEmpty()) { xmlWriter.writeStartElement(CppcheckXml::DefinesElementName); - for (const QString& define : mDefines) { + for (const QString& define : utils::as_const(mDefines)) { xmlWriter.writeStartElement(CppcheckXml::DefineName); xmlWriter.writeAttribute(CppcheckXml::DefineNameAttrib, define); xmlWriter.writeEndElement(); @@ -909,6 +907,12 @@ bool ProjectFile::write(const QString &filename) xmlWriter.writeEndElement(); } + if (!mUserInclude.isEmpty()) { + xmlWriter.writeStartElement(CppcheckXml::UserIncludeElementName); + xmlWriter.writeCharacters(mUserInclude); + xmlWriter.writeEndElement(); + } + if (!mVsConfigurations.isEmpty()) { writeStringList(xmlWriter, mVsConfigurations, @@ -923,7 +927,7 @@ bool ProjectFile::write(const QString &filename) if (!mPaths.isEmpty()) { xmlWriter.writeStartElement(CppcheckXml::PathsElementName); - for (const QString& path : mPaths) { + for (const QString& path : utils::as_const(mPaths)) { xmlWriter.writeStartElement(CppcheckXml::PathName); xmlWriter.writeAttribute(CppcheckXml::PathNameAttrib, path); xmlWriter.writeEndElement(); @@ -933,7 +937,7 @@ bool ProjectFile::write(const QString &filename) if (!mExcludedPaths.isEmpty()) { xmlWriter.writeStartElement(CppcheckXml::ExcludeElementName); - for (const QString& path : mExcludedPaths) { + for (const QString& path : utils::as_const(mExcludedPaths)) { xmlWriter.writeStartElement(CppcheckXml::ExcludePathName); xmlWriter.writeAttribute(CppcheckXml::ExcludePathNameAttrib, path); xmlWriter.writeEndElement(); @@ -948,7 +952,7 @@ bool ProjectFile::write(const QString &filename) if (!mSuppressions.isEmpty()) { xmlWriter.writeStartElement(CppcheckXml::SuppressionsElementName); - for (const SuppressionList::Suppression &suppression : mSuppressions) { + for (const SuppressionList::Suppression &suppression : utils::as_const(mSuppressions)) { xmlWriter.writeStartElement(CppcheckXml::SuppressionElementName); if (!suppression.fileName.empty()) xmlWriter.writeAttribute("fileName", QString::fromStdString(suppression.fileName)); @@ -1046,12 +1050,6 @@ bool ProjectFile::write(const QString &filename) xmlWriter.writeEndElement(); } - if (!mPremiumLicenseFile.isEmpty()) { - xmlWriter.writeStartElement(CppcheckXml::LicenseFileElementName); - xmlWriter.writeCharacters(mPremiumLicenseFile); - xmlWriter.writeEndElement(); - } - xmlWriter.writeEndDocument(); file.close(); return true; @@ -1071,6 +1069,12 @@ void ProjectFile::writeStringList(QXmlStreamWriter &xmlWriter, const QStringList xmlWriter.writeEndElement(); } +void ProjectFile::setSettingsUserIncludes(Settings &settings) const +{ + if (!mUserInclude.isEmpty()) + settings.userIncludes.push_back(mUserInclude.toStdString()); +} + QStringList ProjectFile::fromNativeSeparators(const QStringList &paths) { QStringList ret; @@ -1168,7 +1172,7 @@ QString ProjectFile::getAddonFilePath(QString filesDir, const QString &addon) #endif ; - for (const QString& path : searchPaths) { + for (const QString& path : utils::as_const(searchPaths)) { QString f = path + addon + ".py"; if (QFile(f).exists()) return f; @@ -1176,3 +1180,23 @@ QString ProjectFile::getAddonFilePath(QString filesDir, const QString &addon) return QString(); } + +QStringList ProjectFile::getSearchPaths(const QString& projectPath, const QString& appPath, const QString& datadir, const QString& dir) { + QStringList ret; + ret << appPath << (appPath + "/" + dir) << projectPath; +#ifdef FILESDIR + if (FILESDIR[0]) + ret << FILESDIR << (FILESDIR "/" + dir); +#endif + if (!datadir.isEmpty()) + ret << datadir << (datadir + "/" + dir); + return ret; +} + +QStringList ProjectFile::getSearchPaths(const QString& dir) const { + const QFileInfo inf(mFilename); + const QString applicationFilePath = QCoreApplication::applicationFilePath(); + const QString appPath = QFileInfo(applicationFilePath).canonicalPath(); + const QString datadir = getDataDir(); + return getSearchPaths(inf.canonicalPath(), appPath, datadir, dir); +} diff --git a/gui/projectfile.h b/gui/projectfile.h index 18503e8d6e1..5a5e0ccb89b 100644 --- a/gui/projectfile.h +++ b/gui/projectfile.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -141,6 +141,14 @@ class ProjectFile : public QObject { return mUndefines; } + const QString& getUserInclude() const { + return mUserInclude; + } + + void setUserInclude(const QString& userInclude) { + mUserInclude = userInclude.trimmed(); + } + /** * @brief Get list of paths to check. * @return list of paths. @@ -181,10 +189,6 @@ class ProjectFile : public QObject { return mPlatform; } - const QString& getProjectName() const { - return mProjectName; - } - void setProjectName(QString projectName) { mProjectName = std::move(projectName); } @@ -400,14 +404,6 @@ class ProjectFile : public QObject { return mCertIntPrecision; } - /** Cppcheck Premium: License file */ - void setLicenseFile(const QString& licenseFile) { - mPremiumLicenseFile = licenseFile; - } - const QString& getLicenseFile() const { - return mPremiumLicenseFile; - } - /** * @brief Write project file (to disk). * @param filename Filename to use. @@ -446,6 +442,15 @@ class ProjectFile : public QObject { /** Use Clang parser */ bool clangParser; + /** Get paths where we should glob for certain files (dir="cfg"/"platforms"/etc */ + QStringList getSearchPaths(const QString& dir) const; + + static QStringList getSearchPaths(const QString& projectPath, const QString& appPath, const QString& datadir, const QString& dir); + + /** Set user includes in settings if non-empty */ + void setSettingsUserIncludes(Settings &settings) const; + + protected: /** @@ -597,6 +602,9 @@ class ProjectFile : public QObject { */ QStringList mUndefines; + /** @brief --include file */ + QString mUserInclude; + /** * @brief List of paths to check. */ @@ -637,9 +645,6 @@ class ProjectFile : public QObject { */ QStringList mCodingStandards; - /** @brief Cppcheck Premium: license file */ - QString mPremiumLicenseFile; - /** @brief Project name, used when generating compliance report */ QString mProjectName; diff --git a/gui/projectfile.ui b/gui/projectfile.ui index 4bd01339d83..84a1d6e40ec 100644 --- a/gui/projectfile.ui +++ b/gui/projectfile.ui @@ -7,7 +7,7 @@ 0 0 940 - 701 + 741 @@ -80,7 +80,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -95,7 +95,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -117,7 +117,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -151,7 +151,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -199,7 +199,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -269,7 +269,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -284,7 +284,7 @@ - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -314,7 +314,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -342,10 +342,38 @@ + + + + + + Include file + + + mEditUserInclude + + + + + + + <html><head/><body><p><span style=" font-family:'monospace'; color:#000000; background-color:#ffffff;">Force inclusion of a header file</span></p></body></html> + + + + + + + Browse.. + + + + + - Qt::Vertical + Qt::Orientation::Vertical @@ -552,7 +580,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -586,7 +614,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -601,25 +629,6 @@ - - - - Premium License - - - - - - - - - Browse... - - - - - - @@ -701,7 +710,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -744,7 +753,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -769,7 +778,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -856,7 +865,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -919,7 +928,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1018,7 +1027,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1035,10 +1044,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index c1d1295f0f0..4e75696484b 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,12 +40,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -113,7 +111,7 @@ static std::string suppressionAsText(const SuppressionList::Suppression& s) QStringList ProjectFileDialog::getProjectConfigs(const QString &fileName) { - if (!fileName.endsWith(".sln") && !fileName.endsWith(".vcxproj")) + if (!fileName.endsWith(".sln") && !fileName.endsWith(".slnx") && !fileName.endsWith(".vcxproj")) return QStringList(); QStringList ret; ImportProject importer; @@ -141,24 +139,10 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi setWindowTitle(title); loadSettings(); - mUI->premiumLicense->setVisible(false); - - // Checkboxes for the libraries.. - const QString applicationFilePath = QCoreApplication::applicationFilePath(); - const QString appPath = QFileInfo(applicationFilePath).canonicalPath(); - const QString datadir = getDataDir(); - QStringList searchPaths; - searchPaths << appPath << appPath + "/cfg" << inf.canonicalPath(); -#ifdef FILESDIR - if (FILESDIR[0]) - searchPaths << FILESDIR << FILESDIR "/cfg"; -#endif - if (!datadir.isEmpty()) - searchPaths << datadir << datadir + "/cfg"; QStringList libs; // Search the std.cfg first since other libraries could depend on it QString stdLibraryFilename; - for (const QString &sp : searchPaths) { + for (const QString &sp : projectFile->getSearchPaths("cfg")) { QDir dir(sp); dir.setSorting(QDir::Name); dir.setNameFilters(QStringList("*.cfg")); @@ -180,7 +164,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi break; } // Search other libraries - for (const QString &sp : searchPaths) { + for (const QString &sp : projectFile->getSearchPaths("cfg")) { QDir dir(sp); dir.setSorting(QDir::Name); dir.setNameFilters(QStringList("*.cfg")); @@ -208,7 +192,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi } libs.sort(); mUI->mLibraries->clear(); - for (const QString &lib : libs) { + for (const QString &lib : utils::as_const(libs)) { auto* item = new QListWidgetItem(lib, mUI->mLibraries); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag item->setCheckState(Qt::Unchecked); // AND initialize check state @@ -219,22 +203,15 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi for (const Platform::Type builtinPlatform : builtinPlatforms) mUI->mComboBoxPlatform->addItem(platforms.get(builtinPlatform).mTitle); QStringList platformFiles; - for (QString sp : searchPaths) { - if (sp.endsWith("/cfg")) - sp = sp.mid(0,sp.length()-3) + "platforms"; + for (const QString& sp : projectFile->getSearchPaths("platforms")) { QDir dir(sp); dir.setSorting(QDir::Name); dir.setNameFilters(QStringList("*.xml")); dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); for (const QFileInfo& item : dir.entryInfoList()) { const QString platformFile = item.fileName(); - - const std::vector paths = { - Path::getCurrentPath(), // TODO: do we want to look in CWD? - applicationFilePath.toStdString(), - }; Platform plat2; - if (!plat2.loadFromFile(paths, platformFile.toStdString())) + if (!plat2.loadFromFile({sp.toStdString()}, platformFile.toStdString())) continue; if (platformFiles.indexOf(platformFile) == -1) @@ -256,6 +233,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi connect(mUI->mBtnBrowseBuildDir, &QPushButton::clicked, this, &ProjectFileDialog::browseBuildDir); connect(mUI->mBtnClearImportProject, &QPushButton::clicked, this, &ProjectFileDialog::clearImportProject); connect(mUI->mBtnBrowseImportProject, &QPushButton::clicked, this, &ProjectFileDialog::browseImportProject); + connect(mUI->mBtnBrowseUserInclude, &QPushButton::clicked, this, &ProjectFileDialog::browseUserInclude); connect(mUI->mBtnAddCheckPath, SIGNAL(clicked()), this, SLOT(addCheckPath())); connect(mUI->mBtnEditCheckPath, &QPushButton::clicked, this, &ProjectFileDialog::editCheckPath); connect(mUI->mBtnRemoveCheckPath, &QPushButton::clicked, this, &ProjectFileDialog::removeCheckPath); @@ -324,6 +302,7 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) setIncludepaths(projectFile->getIncludeDirs()); setDefines(projectFile->getDefines()); setUndefines(projectFile->getUndefines()); + mUI->mEditUserInclude->setText(projectFile->getUserInclude()); setCheckPaths(projectFile->getCheckPaths()); setImportProject(projectFile->getImportProject()); mUI->mChkAllVsConfigs->setChecked(projectFile->getAnalyzeAllVsConfigs()); @@ -415,8 +394,8 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) mUI->mMisraC->setText("Misra C"); else { mUI->mMisraC->setText("Misra C 2012 " + tr("Note: Open source Cppcheck does not fully implement Misra C 2012")); - updateAddonCheckBox(mUI->mMisraC, projectFile, dataDir, ADDON_MISRA); } + updateAddonCheckBox(mUI->mMisraC, projectFile, dataDir, ADDON_MISRA); mUI->mMisraVersion->setEnabled(mUI->mMisraC->isChecked()); connect(mUI->mMisraC, &QCheckBox::toggled, mUI->mMisraVersion, &QComboBox::setEnabled); @@ -483,7 +462,6 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) mUI->mToolClangTidy->setEnabled(false); } mUI->mEditTags->setText(projectFile->getTags().join(';')); - mUI->mEditLicenseFile->setText(projectFile->getLicenseFile()); updatePathsAndDefines(); } @@ -502,6 +480,7 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const projectFile->setIncludes(getIncludePaths()); projectFile->setDefines(getDefines()); projectFile->setUndefines(getUndefines()); + projectFile->setUserInclude(mUI->mEditUserInclude->text()); projectFile->setCheckPaths(getCheckPaths()); projectFile->setExcludedPaths(getExcludedPaths()); projectFile->setLibraries(getLibraries()); @@ -570,7 +549,6 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const projectFile->setBughunting(mUI->mBughunting->isChecked()); projectFile->setClangAnalyzer(mUI->mToolClangAnalyzer->isChecked()); projectFile->setClangTidy(mUI->mToolClangTidy->isChecked()); - projectFile->setLicenseFile(mUI->mEditLicenseFile->text()); projectFile->setTags(mUI->mEditTags->text().split(";", Qt::SkipEmptyParts)); } @@ -617,7 +595,7 @@ void ProjectFileDialog::updatePathsAndDefines() { const QString &fileName = mUI->mEditImportProject->text(); const bool importProject = !fileName.isEmpty(); - const bool hasConfigs = fileName.endsWith(".sln") || fileName.endsWith(".vcxproj"); + const bool hasConfigs = fileName.endsWith(".sln") || fileName.endsWith(".slnx") || fileName.endsWith(".vcxproj"); mUI->mBtnClearImportProject->setEnabled(importProject); mUI->mListCheckPaths->setEnabled(!importProject); mUI->mListIncludeDirs->setEnabled(!importProject); @@ -647,7 +625,7 @@ void ProjectFileDialog::browseImportProject() const QFileInfo inf(mProjectFile->getFilename()); const QDir &dir = inf.absoluteDir(); QMap filters; - filters[tr("Visual Studio")] = "*.sln *.vcxproj"; + filters[tr("Visual Studio")] = "*.sln *.slnx *.vcxproj"; filters[tr("Compile database")] = "compile_commands.json"; filters[tr("Borland C++ Builder 6")] = "*.bpr"; QString fileName = QFileDialog::getOpenFileName(this, tr("Import Project"), @@ -664,6 +642,21 @@ void ProjectFileDialog::browseImportProject() } } +void ProjectFileDialog::browseUserInclude() +{ + const QFileInfo inf(mProjectFile->getFilename()); + const QDir &dir = inf.absoluteDir(); + QMap filters; + filters[tr("C/C++ header")] = "*.h"; + filters[tr("All files")] = "*.*"; + QString fileName = QFileDialog::getOpenFileName(this, tr("Include file"), + dir.canonicalPath(), + toFilterString(filters)); + if (!fileName.isEmpty()) { + mUI->mEditUserInclude->setText(dir.relativeFilePath(fileName)); + } +} + QStringList ProjectFileDialog::getProjectConfigurations() const { QStringList configs; diff --git a/gui/projectfiledialog.h b/gui/projectfiledialog.h index 68f62ea83e5..af21685b675 100644 --- a/gui/projectfiledialog.h +++ b/gui/projectfiledialog.h @@ -201,6 +201,11 @@ private slots: */ void browseImportProject(); + /** + * @brief Browse for include file + */ + void browseUserInclude(); + /** * @brief Add new path to check. */ @@ -275,7 +280,7 @@ private slots: /** * @brief Edit suppression (double clicking on suppression) */ - void editSuppression(const QModelIndex &index); + void editSuppression(const QModelIndex& /*index*/); /** * @brief Browse for misra file diff --git a/gui/resultitem.cpp b/gui/resultitem.cpp index 4215115be07..4f8c14fa056 100644 --- a/gui/resultitem.cpp +++ b/gui/resultitem.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/gui/resultitem.h b/gui/resultitem.h index a39606ad23d..e0c212b2138 100644 --- a/gui/resultitem.h +++ b/gui/resultitem.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index 0c8ee2e3101..c553855e99e 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ #include "showtypes.h" #include "suppressions.h" #include "threadhandler.h" +#include "utils.h" #include "xmlreportv2.h" #include @@ -49,9 +50,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -377,9 +376,10 @@ QString ResultsTree::severityToTranslatedString(Severity severity) return tr("internal"); case Severity::none: - default: return QString(); } + + cppcheck::unreachable(); } ResultItem *ResultsTree::findFileItem(const QString &name) const diff --git a/gui/resultstree.h b/gui/resultstree.h index a2b07788f56..23fe5567ed9 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 8336a697878..496c0793157 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -123,6 +123,7 @@ void ResultsView::clear(bool results) } mUI->mDetails->setText(QString()); + mUI->mCode->clear(); mStatistics->clear(); delete mCheckSettings; @@ -134,8 +135,6 @@ void ResultsView::clear(bool results) mUI->mProgress->setFormat("%p%"); mUI->mLabelCriticalErrors->setVisible(false); - - mSuccess = false; } void ResultsView::clear(const QString &filename) @@ -162,7 +161,7 @@ void ResultsView::setResultsSource(ResultsTree::ResultsSource source) mUI->mTree->setResultsSource(source); } -void ResultsView::progress(int value, const QString& description) +void ResultsView::filesCheckedProgress(int value, const QString& description) { mUI->mProgress->setValue(value); mUI->mProgress->setFormat(QString("%p% (%1)").arg(description)); @@ -319,7 +318,6 @@ void ResultsView::setCheckSettings(const Settings &settings) void ResultsView::checkingStarted(int count) { - mSuccess = true; mUI->mProgress->setVisible(true); mUI->mProgress->setMaximum(PROGRESS_MAX); mUI->mProgress->setValue(0); @@ -394,8 +392,6 @@ void ResultsView::translate() void ResultsView::readErrorsXml(const QString &filename) { - mSuccess = false; // Don't know if results come from an aborted analysis - const int version = XmlReport::determineVersion(filename); if (version == 0) { QMessageBox msgBox; @@ -423,7 +419,7 @@ void ResultsView::readErrorsXml(const QString &filename) msgBox.exec(); } - for (const ErrorItem& item : errors) { + for (const ErrorItem& item : utils::as_const(errors)) { handleCriticalError(item); mUI->mTree->addErrorItem(item); } @@ -545,7 +541,6 @@ void ResultsView::on_mListLog_customContextMenuRequested(const QPoint &pos) void ResultsView::stopAnalysis() { - mSuccess = false; mUI->mLabelCriticalErrors->setText(tr("Analysis was stopped")); mUI->mLabelCriticalErrors->setVisible(true); } @@ -568,10 +563,5 @@ void ResultsView::handleCriticalError(const ErrorItem &item) msg += ". " + tr("Analysis was aborted."); mUI->mLabelCriticalErrors->setText(msg); mUI->mLabelCriticalErrors->setVisible(true); - mSuccess = false; } } - -bool ResultsView::isSuccess() const { - return mSuccess; -} diff --git a/gui/resultsview.h b/gui/resultsview.h index 770f9c0c3fa..9ef74666395 100644 --- a/gui/resultsview.h +++ b/gui/resultsview.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -307,7 +307,7 @@ public slots: * @param value Current progress value * @param description Description to accompany the progress */ - void progress(int value, const QString& description); + void filesCheckedProgress(int value, const QString& description); /** * @brief Slot for new error to be displayed @@ -388,11 +388,6 @@ public slots: Settings* mCheckSettings = nullptr; - /** - * Set to true when checking finish successfully. Set to false whenever analysis starts. - */ - bool mSuccess = false; - /** Critical error ids */ QString mCriticalErrors; diff --git a/gui/statsdialog.cpp b/gui/statsdialog.cpp index f16b6cba3b9..d3e15d87ad5 100644 --- a/gui/statsdialog.cpp +++ b/gui/statsdialog.cpp @@ -113,6 +113,7 @@ void StatsDialog::setProject(const ProjectFile* projectFile) if (!statsFile.isEmpty()) { QChartView *chartView = createChart(statsFile, "cppcheck"); mUI->mTabHistory->layout()->addWidget(chartView); + // cppcheck-suppress knownConditionTrueFalse - TODO in getClangAnalyzer() if (projectFile->getClangAnalyzer()) { chartView = createChart(statsFile, CLANG_ANALYZER); mUI->mTabHistory->layout()->addWidget(chartView); diff --git a/gui/test/projectfile/CMakeLists.txt b/gui/test/projectfile/CMakeLists.txt index 2d9c254ec5f..f9bab8ba0c7 100644 --- a/gui/test/projectfile/CMakeLists.txt +++ b/gui/test/projectfile/CMakeLists.txt @@ -4,6 +4,7 @@ add_dependencies(gui-build-deps build-projectfile-deps) add_executable(test-projectfile ${test-projectfile_SRC} testprojectfile.cpp + ${CMAKE_SOURCE_DIR}/gui/common.cpp ${CMAKE_SOURCE_DIR}/gui/projectfile.cpp ) target_include_directories(test-projectfile PRIVATE ${CMAKE_SOURCE_DIR}/gui ${CMAKE_SOURCE_DIR}/lib) diff --git a/gui/test/projectfile/testprojectfile.cpp b/gui/test/projectfile/testprojectfile.cpp index 988d62e8bce..dbc4cb51659 100644 --- a/gui/test/projectfile/testprojectfile.cpp +++ b/gui/test/projectfile/testprojectfile.cpp @@ -136,6 +136,24 @@ void TestProjectFile::getAddonFilePath() const QCOMPARE(ProjectFile::getAddonFilePath(tempdir.path(), filepath), filepath); } +void TestProjectFile::getSearchPaths() const +{ +#ifdef FILESDIR + const QString f(FILESDIR "\n" // example: "/usr/local/share/cppcheck\n" + FILESDIR "/dir\n"); // example: "/usr/local/share/cppcheck/dir\n" +#else + const QString f; +#endif + + QCOMPARE(ProjectFile::getSearchPaths("projectPath", "appPath", "datadir", "dir").join("\n"), + "appPath\n" + "appPath/dir\n" + "projectPath\n" + + f + + "datadir\n" + "datadir/dir"); +} + void TestProjectFile::getInlineSuppressionDefaultValue() const { ProjectFile projectFile; @@ -181,5 +199,14 @@ void TestProjectFile::getCheckingSuppressionsStar() const QCOMPARE(projectFile.getCheckingSuppressions()[0].fileName, "*.cpp"); } +void TestProjectFile::emptyUserInclude() const +{ + ProjectFile projectFile; + Settings settings; + projectFile.setUserInclude(" "); + projectFile.setSettingsUserIncludes(settings); + QCOMPARE(settings.userIncludes.size(), 0); +} + QTEST_MAIN(TestProjectFile) diff --git a/gui/test/projectfile/testprojectfile.h b/gui/test/projectfile/testprojectfile.h index 8f3e54c3008..18f38d0eb39 100644 --- a/gui/test/projectfile/testprojectfile.h +++ b/gui/test/projectfile/testprojectfile.h @@ -28,6 +28,7 @@ private slots: void loadSimpleNoroot() const; void getAddonFilePath() const; + void getSearchPaths() const; void getInlineSuppressionDefaultValue() const; void getInlineSuppression() const; @@ -35,4 +36,6 @@ private slots: void getCheckingSuppressionsRelative() const; void getCheckingSuppressionsAbsolute() const; void getCheckingSuppressionsStar() const; + + void emptyUserInclude() const; }; diff --git a/gui/test/resultstree/CMakeLists.txt b/gui/test/resultstree/CMakeLists.txt index 1bf8a02ffb1..a48b137e349 100644 --- a/gui/test/resultstree/CMakeLists.txt +++ b/gui/test/resultstree/CMakeLists.txt @@ -3,6 +3,7 @@ qt_wrap_cpp(test-resultstree_SRC ${CMAKE_SOURCE_DIR}/gui/resultstree.h ${CMAKE_SOURCE_DIR}/gui/resultitem.h ${CMAKE_SOURCE_DIR}/gui/applicationlist.h + ${CMAKE_SOURCE_DIR}/gui/common.h ${CMAKE_SOURCE_DIR}/gui/projectfile.h ${CMAKE_SOURCE_DIR}/gui/threadhandler.h ${CMAKE_SOURCE_DIR}/gui/threadresult.h @@ -14,6 +15,7 @@ add_executable(test-resultstree testresultstree.cpp ${CMAKE_SOURCE_DIR}/gui/resultstree.cpp ${CMAKE_SOURCE_DIR}/gui/resultitem.cpp + ${CMAKE_SOURCE_DIR}/gui/common.cpp ${CMAKE_SOURCE_DIR}/gui/erroritem.cpp ${CMAKE_SOURCE_DIR}/gui/showtypes.cpp ${CMAKE_SOURCE_DIR}/gui/report.cpp diff --git a/gui/test/resultstree/testresultstree.cpp b/gui/test/resultstree/testresultstree.cpp index ac3ba4ff78c..afda38e0075 100644 --- a/gui/test/resultstree/testresultstree.cpp +++ b/gui/test/resultstree/testresultstree.cpp @@ -93,16 +93,20 @@ void ThreadHandler::stop() { void ThreadHandler::threadDone() { throw 1; } +// NOLINTBEGIN(performance-unnecessary-value-param) +void ThreadHandler::startCheck(CheckThread::Details /*unused*/) { + throw 1; +} +void ThreadHandler::finishCheck(CheckThread::Details /*unused*/) { + throw 1; +} +// NOLINTEND(performance-unnecessary-value-param) Application& ApplicationList::getApplication(const int /*unused*/) { throw 1; } const Application& ApplicationList::getApplication(const int index) const { return mApplications.at(index); } -QString getPath(const QString &type) { - return "/" + type; -} -void setPath(const QString & /*unused*/, const QString & /*unused*/) {} QString XmlReport::quoteMessage(const QString &message) { return message; } @@ -110,7 +114,8 @@ QString XmlReport::unquoteMessage(const QString &message) { return message; } XmlReport::XmlReport(const QString& filename) : Report(filename) {} -void ThreadResult::fileChecked(const QString & /*unused*/) { +// NOLINTNEXTLINE(performance-unnecessary-value-param) +void ThreadResult::finishCheck(CheckThread::Details /*unused*/) { throw 1; } void ThreadResult::reportOut(const std::string & /*unused*/, Color /*unused*/) { @@ -119,6 +124,9 @@ void ThreadResult::reportOut(const std::string & /*unused*/, Color /*unused*/) { void ThreadResult::reportErr(const ErrorMessage & /*unused*/) { throw 1; } +void ThreadResult::reportProgress(const std::string &/*filename*/, const char /*stage*/[], const std::size_t /*value*/) { + throw 1; +} // Test... diff --git a/gui/threaddetails.cpp b/gui/threaddetails.cpp new file mode 100644 index 00000000000..1fcb97772ef --- /dev/null +++ b/gui/threaddetails.cpp @@ -0,0 +1,56 @@ +#include "threaddetails.h" +#include "utils.h" + +#include "ui_threaddetails.h" + +#include + +ThreadDetails* ThreadDetails::mInstance; + +ThreadDetails::ThreadDetails(QWidget *parent) + : QWidget(parent) + , mUi(new Ui::ThreadDetails) +{ + mInstance = this; + setWindowFlags(Qt::Window); + mUi->setupUi(this); + connect(&mTimer, &QTimer::timeout, this, &ThreadDetails::updateUI); + mTimer.start(1000); +} + +ThreadDetails::~ThreadDetails() +{ + mInstance = nullptr; + delete mUi; +} + +// NOLINTNEXTLINE(performance-unnecessary-value-param) - false positive +void ThreadDetails::threadDetailsUpdated(QMap threadDetails) +{ + QMutexLocker locker(&mMutex); + mThreadDetails = threadDetails; + if (threadDetails.empty()) { + mProgress.clear(); + } +} + +// cppcheck-suppress passedByValue +// NOLINTNEXTLINE(performance-unnecessary-value-param) - false positive +void ThreadDetails::progress(QString filename, QString stage, std::size_t value) { + QMutexLocker locker(&mMutex); + mProgress[filename] = {QString(), stage + QString(value > 0 ? ": %1%" : "").arg(value)}; +} + +void ThreadDetails::updateUI() { + QString text("Thread\tStart time\tFile/Progress\n"); + { + QMutexLocker locker(&mMutex); + for (const auto& td: utils::as_const(mThreadDetails)) { + auto& timeProgress = mProgress[td.file]; + if (timeProgress.first.isEmpty() && !timeProgress.second.isEmpty()) + timeProgress.first = QTime::currentTime().toString(Qt::TextDate); + text += QString("%1\t%2\t%3\n\t%4\t%5\n").arg(td.threadIndex).arg(td.startTime.toString(Qt::TextDate)).arg(td.file).arg(timeProgress.first).arg(timeProgress.second); + } + } + mUi->plainTextEdit->setPlainText(text); +} diff --git a/gui/threaddetails.h b/gui/threaddetails.h new file mode 100644 index 00000000000..253b53d5407 --- /dev/null +++ b/gui/threaddetails.h @@ -0,0 +1,44 @@ +#ifndef THREADDETAILS_H +#define THREADDETAILS_H + +#include +#include +#include +#include +#include "checkthread.h" + +namespace Ui { + class ThreadDetails; +} + +class ThreadDetails : public QWidget +{ + Q_OBJECT + +public: + explicit ThreadDetails(QWidget *parent = nullptr); + ~ThreadDetails() override; + + static ThreadDetails* instance() { + return mInstance; + } + +public slots: + void threadDetailsUpdated(QMap threadDetails); + void progress(QString filename, QString stage, std::size_t value); + +private slots: + void updateUI(); + +private: + static ThreadDetails* mInstance; + Ui::ThreadDetails *mUi; + QMap> mProgress; + QMap mThreadDetails; + QTimer mTimer; + + /** accessing mProgress and mThreadDetails in slots that are triggered from different threads */ + QMutex mMutex; +}; + +#endif // THREADDETAILS_H diff --git a/gui/threaddetails.ui b/gui/threaddetails.ui new file mode 100644 index 00000000000..420340cf77d --- /dev/null +++ b/gui/threaddetails.ui @@ -0,0 +1,28 @@ + + + ThreadDetails + + + + 0 + 0 + 640 + 300 + + + + Thread Details + + + + + + true + + + + + + + + diff --git a/gui/threadhandler.cpp b/gui/threadhandler.cpp index ad4d0e2a61d..3f89d58b558 100644 --- a/gui/threadhandler.cpp +++ b/gui/threadhandler.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include "filesettings.h" #include "resultsview.h" #include "settings.h" +#include "utils.h" #include #include @@ -146,26 +147,34 @@ void ThreadHandler::createThreads(const int count) removeThreads(); //Create new threads for (int i = mThreads.size(); i < count; i++) { - mThreads << new CheckThread(mResults); + mThreads << new CheckThread(mResults, i + 1); connect(mThreads.last(), &CheckThread::done, this, &ThreadHandler::threadDone, Qt::QueuedConnection); - connect(mThreads.last(), &CheckThread::fileChecked, - &mResults, &ThreadResult::fileChecked, Qt::QueuedConnection); + connect(mThreads.last(), &CheckThread::finishCheck, + &mResults, &ThreadResult::finishCheck, Qt::QueuedConnection); + connect(mThreads.last(), &CheckThread::startCheck, + this, &ThreadHandler::startCheck, Qt::QueuedConnection); + connect(mThreads.last(), &CheckThread::finishCheck, + this, &ThreadHandler::finishCheck, Qt::QueuedConnection); } } void ThreadHandler::removeThreads() { - for (CheckThread* thread : mThreads) { + for (CheckThread* thread : utils::as_const(mThreads)) { if (thread->isRunning()) { thread->stop(); thread->wait(); } disconnect(thread, &CheckThread::done, this, &ThreadHandler::threadDone); - disconnect(thread, &CheckThread::fileChecked, - &mResults, &ThreadResult::fileChecked); + disconnect(thread, &CheckThread::finishCheck, + &mResults, &ThreadResult::finishCheck); + disconnect(mThreads.last(), &CheckThread::startCheck, + this, &ThreadHandler::startCheck); + disconnect(mThreads.last(), &CheckThread::finishCheck, + this, &ThreadHandler::finishCheck); delete thread; } @@ -208,15 +217,15 @@ void ThreadHandler::stop() mCheckStartTime = QDateTime(); mAnalyseWholeProgram = false; mCtuInfo.clear(); - for (CheckThread* thread : mThreads) { + for (CheckThread* thread : utils::as_const(mThreads)) { thread->stop(); } } void ThreadHandler::initialize(const ResultsView *view) { - connect(&mResults, &ThreadResult::progress, - view, &ResultsView::progress); + connect(&mResults, &ThreadResult::filesCheckedProgress, + view, &ResultsView::filesCheckedProgress); connect(&mResults, &ThreadResult::error, view, &ResultsView::error); @@ -226,6 +235,9 @@ void ThreadHandler::initialize(const ResultsView *view) connect(&mResults, &ThreadResult::debugError, this, &ThreadHandler::debugError); + + connect(&mResults, &ThreadResult::progress, + this, &ThreadHandler::progress); } void ThreadHandler::loadSettings(const QSettings &settings) @@ -317,3 +329,24 @@ void ThreadHandler::setCheckStartTime(QDateTime checkStartTime) { mCheckStartTime = std::move(checkStartTime); } + +// cppcheck-suppress passedByValueCallback +// NOLINTNEXTLINE(performance-unnecessary-value-param) +void ThreadHandler::startCheck(CheckThread::Details details) +{ + mThreadDetails[details.threadIndex] = details; + emitThreadDetailsUpdated(); +} + +// cppcheck-suppress passedByValueCallback +// NOLINTNEXTLINE(performance-unnecessary-value-param) +void ThreadHandler::finishCheck(CheckThread::Details details) +{ + mThreadDetails.remove(details.threadIndex); + emitThreadDetailsUpdated(); +} + +void ThreadHandler::emitThreadDetailsUpdated() +{ + emit threadDetailsUpdated(mThreadDetails); +} diff --git a/gui/threadhandler.h b/gui/threadhandler.h index cc578bd5643..17f011c32ac 100644 --- a/gui/threadhandler.h +++ b/gui/threadhandler.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ #include "suppressions.h" #include "threadresult.h" +#include #include #include #include @@ -178,6 +179,11 @@ class ThreadHandler : public QObject { */ void setCheckStartTime(QDateTime checkStartTime); + /** + * @brief Emit the threadDetailsUpdated signal + */ + void emitThreadDetailsUpdated(); + signals: /** * @brief Signal that all threads are done @@ -191,6 +197,11 @@ class ThreadHandler : public QObject { // NOLINTNEXTLINE(readability-inconsistent-declaration-parameter-name) - caused by generated MOC code void debugError(const ErrorItem &item); + /** + * @brief Emitted when thread details are updated. + */ + void threadDetailsUpdated(QMap threadDetails); + public slots: /** @@ -198,6 +209,22 @@ public slots: * */ void stop(); + + /** + * @brief Slot threads use to signal this class that it started checking a file + * @param details Details about what file is being checked and by what thread + */ + void startCheck(CheckThread::Details details); + + /** + * @brief Slot threads use to signal this class that it finish checking a file + * @param details Details about what file finished being checked and by what thread + */ + void finishCheck(CheckThread::Details details); + +signals: + void progress(QString filename, QString stage, std::size_t value); + protected slots: /** * @brief Slot that a single thread is done @@ -285,6 +312,12 @@ protected slots: Settings mCheckSettings; std::shared_ptr mCheckSuppressions; /// @} + + /** + * @brief Details about currently running threads + */ + QMap mThreadDetails; + private: /** diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp index ea858c92e4a..a3929da7cca 100644 --- a/gui/threadresult.cpp +++ b/gui/threadresult.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,18 +34,19 @@ void ThreadResult::reportOut(const std::string &outmsg, Color /*c*/) emit log(QString::fromStdString(outmsg)); } -void ThreadResult::fileChecked(const QString &file) +// NOLINTNEXTLINE(performance-unnecessary-value-param) +void ThreadResult::finishCheck(CheckThread::Details details) { std::lock_guard locker(mutex); - mProgress += QFile(file).size(); + mCheckedFileSize += QFile(details.file).size(); mFilesChecked++; - if (mMaxProgress > 0) { - const int value = static_cast(PROGRESS_MAX * mProgress / mMaxProgress); + if (mTotalFileSize > 0) { + const int value = static_cast(PROGRESS_MAX * mCheckedFileSize / mTotalFileSize); const QString description = tr("%1 of %2 files checked").arg(mFilesChecked).arg(mTotalFiles); - emit progress(value, description); + emit filesCheckedProgress(value, description); } } @@ -59,6 +60,11 @@ void ThreadResult::reportErr(const ErrorMessage &msg) emit debugError(item); } +// NOLINTNEXTLINE(readability-avoid-const-params-in-decls) - false positive this is an overload +void ThreadResult::reportProgress(const std::string &filename, const char stage[], const std::size_t value) { + emit progress(QString::fromStdString(filename), stage, value); +} + void ThreadResult::getNextFile(const FileWithDetails*& file) { std::lock_guard locker(mutex); @@ -87,7 +93,7 @@ void ThreadResult::setFiles(std::list files) mTotalFiles = files.size(); mFiles = std::move(files); mItNextFile = mFiles.cbegin(); - mProgress = 0; + mCheckedFileSize = 0; mFilesChecked = 0; // Determine the total size of all of the files to check, so that we can @@ -95,7 +101,7 @@ void ThreadResult::setFiles(std::list files) quint64 sizeOfFiles = std::accumulate(mFiles.cbegin(), mFiles.cend(), 0, [](quint64 total, const FileWithDetails& file) { return total + file.size(); }); - mMaxProgress = sizeOfFiles; + mTotalFileSize = sizeOfFiles; } void ThreadResult::setProject(const ImportProject &prj) @@ -105,13 +111,13 @@ void ThreadResult::setProject(const ImportProject &prj) mItNextFile = mFiles.cbegin(); mFileSettings = prj.fileSettings; mItNextFileSettings = mFileSettings.cbegin(); - mProgress = 0; + mCheckedFileSize = 0; mFilesChecked = 0; mTotalFiles = prj.fileSettings.size(); // Determine the total size of all of the files to check, so that we can // show an accurate progress estimate - mMaxProgress = std::accumulate(prj.fileSettings.begin(), prj.fileSettings.end(), quint64{ 0 }, [](quint64 v, const FileSettings& fs) { + mTotalFileSize = std::accumulate(prj.fileSettings.begin(), prj.fileSettings.end(), quint64{ 0 }, [](quint64 v, const FileSettings& fs) { return v + QFile(QString::fromStdString(fs.filename())).size(); }); } diff --git a/gui/threadresult.h b/gui/threadresult.h index dc7b5c0372a..87560e87d78 100644 --- a/gui/threadresult.h +++ b/gui/threadresult.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +23,9 @@ #include "color.h" #include "errorlogger.h" #include "filesettings.h" +#include "checkthread.h" +#include #include #include #include @@ -77,28 +79,31 @@ class ThreadResult : public QObject, public ErrorLogger { /** * ErrorLogger methods */ - void reportOut(const std::string &outmsg, Color c = Color::Reset) override; + void reportOut(const std::string &outmsg, Color /*c*/ = Color::Reset) override; void reportErr(const ErrorMessage &msg) override; void reportMetric(const std::string &metric) override { (void) metric; } + // NOLINTNEXTLINE(readability-avoid-const-params-in-decls) - false positive this is an overload + void reportProgress(const std::string &filename, const char stage[], const std::size_t value) final; public slots: /** - * @brief Slot threads use to signal this class that a specific file is checked - * @param file File that is checked + * @brief Slot threads use to signal this class that it finish checking a file + * @param details Details about what file finished being checked and by what thread */ - void fileChecked(const QString &file); + void finishCheck(CheckThread::Details details); + signals: /** - * @brief Progress signal - * @param value Current progress - * @param description Description of the current stage + * @brief Files checked progress + * @param value Current progress (0 - PROGRESS_MAX) + * @param description Description of the current stage (example: "13/45 files checked") */ // NOLINTNEXTLINE(readability-inconsistent-declaration-parameter-name) - caused by generated MOC code - void progress(int value, const QString& description); + void filesCheckedProgress(int value, const QString& description); /** * @brief Signal of a new error @@ -124,6 +129,8 @@ public slots: // NOLINTNEXTLINE(readability-inconsistent-declaration-parameter-name) - caused by generated MOC code void debugError(const ErrorItem &item); + void progress(QString filename, QString stage, std::size_t value); + protected: /** @@ -142,17 +149,11 @@ public slots: std::list mFileSettings; std::list::const_iterator mItNextFileSettings{mFileSettings.cbegin()}; - /** - * @brief Max progress - * - */ - quint64 mMaxProgress{}; + /** @brief Total file size */ + quint64 mTotalFileSize{}; - /** - * @brief Current progress - * - */ - quint64 mProgress{}; + /** @brief File size of checked files */ + quint64 mCheckedFileSize{}; /** * @brief Current number of files checked diff --git a/gui/translationhandler.h b/gui/translationhandler.h index 8ab5b46b6f7..4cea7d4ce80 100644 --- a/gui/translationhandler.h +++ b/gui/translationhandler.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/gui/xmlreportv2.h b/gui/xmlreportv2.h index 6f5834b3417..58d368c4bc2 100644 --- a/gui/xmlreportv2.h +++ b/gui/xmlreportv2.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +22,6 @@ #include "erroritem.h" #include "xmlreport.h" -#include #include class QXmlStreamReader; diff --git a/htmlreport/cppcheck-htmlreport b/htmlreport/cppcheck-htmlreport index 5044443a0a9..fb263c73d12 100755 --- a/htmlreport/cppcheck-htmlreport +++ b/htmlreport/cppcheck-htmlreport @@ -278,7 +278,7 @@ HTML_HEAD = """ updateFileRows(); } - + function toggleClassification(cb) { cb.parentElement.classList.toggle("unchecked", !cb.checked); var elements = document.querySelectorAll(".class_" + cb.id); @@ -289,7 +289,7 @@ HTML_HEAD = """ updateFileRows(); } - + function toggleTool(cb) { cb.parentElement.classList.toggle("unchecked", !cb.checked); @@ -469,9 +469,9 @@ def filter_button(enabled_filters, id, function): def filter_bar(enabled): severity_bar = ''.join([filter_button(enabled, severity, 'toggleSeverity') for severity in ['error', 'warning', 'portability', 'performance', 'style', 'information']]) + '\n | ' classification_bar = ''.join([filter_button(enabled, _class, 'toggleClassification') for _class in ['Mandatory', 'Required', 'Advisory', 'Document', 'Disapplied', 'L1','L2','L3','']]) + '\n | ' - if "checked/>" not in severity_bar: + if "checked>" not in severity_bar: severity_bar = '' - if "checked/>" not in classification_bar: + if "checked>" not in classification_bar: classification_bar = '' return ''.join([ '
\n' diff --git a/htmlreport/setup.py b/htmlreport/setup.py index 3e049181ce6..9f85000a090 100755 --- a/htmlreport/setup.py +++ b/htmlreport/setup.py @@ -16,7 +16,7 @@ ), long_description=readme, author="Cppcheck Team", - url="https://github.com/danmar/cppcheck", + url="https://github.com/cppcheck-opensource/cppcheck", license="GPL", packages=find_packages(exclude=("tests", "docs")), use_scm_version={"root": ".."}, diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index d7a94de352e..b826bc0b265 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -12,6 +12,8 @@ function(build_src output filename) set(${output} ${${output}} ${outfile} PARENT_SCOPE) if (USE_MATCHCOMPILER_OPT STREQUAL "Verify") set(verify_option "--verify") + else() + set(verify_option "") endif() add_custom_command( OUTPUT ${outfile} @@ -28,6 +30,7 @@ function(build_src output filename) endfunction() if (NOT USE_MATCHCOMPILER_OPT STREQUAL "Off") + set(srcs_build "") foreach(file ${srcs}) build_src(srcs_build ${file}) endforeach() diff --git a/lib/addoninfo.cpp b/lib/addoninfo.cpp index a2426d91999..388484916ea 100644 --- a/lib/addoninfo.cpp +++ b/lib/addoninfo.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,24 +39,36 @@ static std::string getFullPath(const std::string &fileName, const std::string &e return ""; const std::string exepath = Path::getPathFromFilename(exename); - if (debug) - std::cout << "looking for addon '" << (exepath + fileName) << "'" << std::endl; - if (Path::isFile(exepath + fileName)) - return exepath + fileName; - if (debug) - std::cout << "looking for addon '" << (exepath + "addons/" + fileName) << "'" << std::endl; - if (Path::isFile(exepath + "addons/" + fileName)) - return exepath + "addons/" + fileName; + { + std::string p = Path::join(exepath, fileName); + if (debug) + std::cout << "looking for addon '" << p << "'" << std::endl; + if (Path::isFile(p)) + return p; + } + { + std::string p = Path::join(exepath, "addons", fileName); + if (debug) + std::cout << "looking for addon '" << p << "'" << std::endl; + if (Path::isFile(p)) + return p; + } #ifdef FILESDIR - if (debug) - std::cout << "looking for addon '" << (FILESDIR + ("/" + fileName)) << "'" << std::endl; - if (Path::isFile(FILESDIR + ("/" + fileName))) - return FILESDIR + ("/" + fileName); - if (debug) - std::cout << "looking for addon '" << (FILESDIR + ("/addons/" + fileName)) << "'" << std::endl; - if (Path::isFile(FILESDIR + ("/addons/" + fileName))) - return FILESDIR + ("/addons/" + fileName); + { + std::string p = Path::join(FILESDIR, fileName); + if (debug) + std::cout << "looking for addon '" << p << "'" << std::endl; + if (Path::isFile(p)) + return p; + } + { + std::string p = Path::join(FILESDIR, "addons", fileName); + if (debug) + std::cout << "looking for addon '" << p << "'" << std::endl; + if (Path::isFile(p)) + return p; + } #endif return ""; } @@ -114,6 +126,28 @@ static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &j } } + { + const auto it = obj.find("checkers"); + if (it != obj.cend()) { + const auto& val = it->second; + if (!val.is()) + return "Loading " + fileName + " failed. 'checkers' must be an array."; + for (const picojson::value &v : val.get()) { + if (!v.is()) + return "Loading " + fileName + " failed. 'checkers' entry is not an object."; + + const picojson::object& checkerObj = v.get(); + if (checkerObj.size() == 1) { + const std::string c = checkerObj.begin()->first; + if (!checkerObj.begin()->second.is()) + return "Loading " + fileName + " failed. 'checkers' entry requirement is not a string."; + const std::string req = checkerObj.begin()->second.get(); + addoninfo.checkers.emplace(c, req); + } + } + } + } + { const auto it = obj.find("executable"); if (it != obj.cend()) { diff --git a/lib/addoninfo.h b/lib/addoninfo.h index 592833c2162..902a26c2e12 100644 --- a/lib/addoninfo.h +++ b/lib/addoninfo.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include "config.h" #include +#include struct CPPCHECKLIB AddonInfo { std::string name; @@ -31,6 +32,7 @@ struct CPPCHECKLIB AddonInfo { std::string python; // script interpreter bool ctu = false; std::string runScript; + std::map checkers; // checker name and its requirement std::string getAddonInfo(const std::string &fileName, const std::string &exename, bool debug = false); }; diff --git a/lib/analyzerinfo.cpp b/lib/analyzerinfo.cpp index c7045252f3d..6f919ec3651 100644 --- a/lib/analyzerinfo.cpp +++ b/lib/analyzerinfo.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,10 +23,13 @@ #include "path.h" #include "utils.h" +#include #include #include +#include #include #include +#include #include #include "xml.h" @@ -48,14 +51,14 @@ static std::string getFilename(const std::string &fullpath) return fullpath.substr(pos1,pos2); } -void AnalyzerInformation::writeFilesTxt(const std::string &buildDir, const std::list &sourcefiles, const std::string &userDefines, const std::list &fileSettings) +void AnalyzerInformation::writeFilesTxt(const std::string &buildDir, const std::list &sourcefiles, const std::list &fileSettings) { const std::string filesTxt(buildDir + "/files.txt"); std::ofstream fout(filesTxt); - fout << getFilesTxt(sourcefiles, userDefines, fileSettings); + fout << getFilesTxt(sourcefiles, fileSettings); } -std::string AnalyzerInformation::getFilesTxt(const std::list &sourcefiles, const std::string &userDefines, const std::list &fileSettings) { +std::string AnalyzerInformation::getFilesTxt(const std::list &sourcefiles, const std::list &fileSettings) { std::ostringstream ret; std::map fileCount; @@ -63,13 +66,11 @@ std::string AnalyzerInformation::getFilesTxt(const std::list &sourc for (const std::string &f : sourcefiles) { const std::string afile = getFilename(f); ret << afile << ".a" << (++fileCount[afile]) << sep << sep << sep << Path::simplifyPath(f) << '\n'; - if (!userDefines.empty()) - ret << afile << ".a" << (++fileCount[afile]) << sep << userDefines << sep << sep << Path::simplifyPath(f) << '\n'; } for (const FileSettings &fs : fileSettings) { const std::string afile = getFilename(fs.filename()); - const std::string id = fs.fileIndex > 0 ? std::to_string(fs.fileIndex) : ""; + const std::string id = fs.file.fsFileId() > 0 ? std::to_string(fs.file.fsFileId()) : ""; ret << afile << ".a" << (++fileCount[afile]) << sep << fs.cfg << sep << id << sep << Path::simplifyPath(fs.filename()) << std::endl; } @@ -84,54 +85,65 @@ void AnalyzerInformation::close() } } -bool AnalyzerInformation::skipAnalysis(const tinyxml2::XMLDocument &analyzerInfoDoc, std::size_t hash, std::list &errors) +std::string AnalyzerInformation::skipAnalysis(const tinyxml2::XMLDocument &analyzerInfoDoc, std::size_t hash, std::list &errors) { const tinyxml2::XMLElement * const rootNode = analyzerInfoDoc.FirstChildElement(); if (rootNode == nullptr) - return false; + return "no root node found"; - const char *attr = rootNode->Attribute("hash"); - if (!attr || attr != std::to_string(hash)) - return false; + if (strcmp(rootNode->Name(), "analyzerinfo") != 0) + return "unexpected root node"; - // Check for invalid license error or internal error, in which case we should retry analysis - for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) { - if (std::strcmp(e->Name(), "error") == 0 && - (e->Attribute("id", "premium-invalidLicense") || - e->Attribute("id", "premium-internalError") || - e->Attribute("id", "internalError") - )) - return false; - } + const char * const attr = rootNode->Attribute("hash"); + if (!attr) + return "no 'hash' attribute found"; + if (attr != std::to_string(hash)) + return "hash mismatch"; for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) { - if (std::strcmp(e->Name(), "error") == 0) - errors.emplace_back(e); + if (std::strcmp(e->Name(), "error") != 0) + continue; + + // TODO: discarding results on internalError doesn't make sense since that won't fix itself + // Check for invalid license error or internal error, in which case we should retry analysis + static const std::array s_ids{ + "premium-invalidLicense", + "premium-internalError", + "internalError" + }; + for (const auto* id : s_ids) + { + // cppcheck-suppress useStlAlgorithm + if (e->Attribute("id", id)) { + errors.clear(); + return std::string("'") + id + "' encountered"; + } + } + + errors.emplace_back(e); } - return true; + return ""; } -std::string AnalyzerInformation::getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, int fileIndex) +std::string AnalyzerInformation::getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, int fsFileId) { - const std::string id = (fileIndex > 0) ? std::to_string(fileIndex) : ""; std::string line; - const std::string end(sep + cfg + sep + id + sep + Path::simplifyPath(sourcefile)); while (std::getline(filesTxt,line)) { - if (line.size() <= end.size() + 2U) - continue; - if (!endsWith(line, end.c_str(), end.size())) - continue; - return line.substr(0,line.find(sep)); + AnalyzerInformation::Info filesTxtInfo; + if (!filesTxtInfo.parse(line)) + continue; // TODO: report error? + if (endsWith(sourcefile, filesTxtInfo.sourceFile) && filesTxtInfo.cfg == cfg && filesTxtInfo.fsFileId == fsFileId) + return filesTxtInfo.afile; } return ""; } -std::string AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex) +std::string AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId) { std::ifstream fin(Path::join(buildDir, "files.txt")); if (fin.is_open()) { - const std::string& ret = getAnalyzerInfoFileFromFilesTxt(fin, sourcefile, cfg, fileIndex); + const std::string& ret = getAnalyzerInfoFileFromFilesTxt(fin, sourcefile, cfg, fsFileId); if (!ret.empty()) return Path::join(buildDir, ret); } @@ -142,27 +154,47 @@ std::string AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir filename = sourcefile; else filename = sourcefile.substr(pos + 1); + // TODO: is this correct? the above code will return files ending in '.aN'. Also does not consider the ID return Path::join(buildDir, std::move(filename)) + ".analyzerinfo"; } -bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex, std::size_t hash, std::list &errors) +bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId, std::size_t hash, std::list &errors, bool debug) { + if (mOutputStream.is_open()) + throw std::runtime_error("analyzer information file is already open"); + if (buildDir.empty() || sourcefile.empty()) return true; - close(); - - const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg,fileIndex); - tinyxml2::XMLDocument analyzerInfoDoc; - const tinyxml2::XMLError xmlError = analyzerInfoDoc.LoadFile(analyzerInfoFile.c_str()); - if (xmlError == tinyxml2::XML_SUCCESS && skipAnalysis(analyzerInfoDoc, hash, errors)) - return false; + const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg,fsFileId); + + { + tinyxml2::XMLDocument analyzerInfoDoc; + const tinyxml2::XMLError xmlError = analyzerInfoDoc.LoadFile(analyzerInfoFile.c_str()); + if (xmlError == tinyxml2::XML_SUCCESS) { + const std::string err = skipAnalysis(analyzerInfoDoc, hash, errors); + if (err.empty()) { + if (debug) + std::cout << "skipping analysis - loaded " << errors.size() << " cached finding(s) from '" << analyzerInfoFile << "' for '" << sourcefile << "'" << std::endl; + return false; + } + if (debug) { + std::cout << "discarding cached result from '" << analyzerInfoFile << "' for '" << sourcefile << "' - " << err << std::endl; + } + } + else if (xmlError != tinyxml2::XML_ERROR_FILE_NOT_FOUND) { + if (debug) + std::cout << "discarding cached result - failed to load '" << analyzerInfoFile << "' for '" << sourcefile << "' (" << tinyxml2::XMLDocument::ErrorIDToName(xmlError) << ")" << std::endl; + } + else if (debug) + std::cout << "no cached result '" << analyzerInfoFile << "' for '" << sourcefile << "' found" << std::endl; + } mOutputStream.open(analyzerInfoFile); - if (mOutputStream.is_open()) { - mOutputStream << "\n"; - mOutputStream << "\n"; - } + if (!mOutputStream.is_open()) + throw std::runtime_error("failed to open '" + analyzerInfoFile + "'"); + mOutputStream << "\n"; + mOutputStream << "\n"; return true; } @@ -179,6 +211,7 @@ void AnalyzerInformation::setFileInfo(const std::string &check, const std::strin mOutputStream << " \n" << fileInfo << " \n"; } +// TODO: report detailed errors? bool AnalyzerInformation::Info::parse(const std::string& filesTxtLine) { const std::string::size_type sep1 = filesTxtLine.find(sep); if (sep1 == std::string::npos) @@ -191,10 +224,10 @@ bool AnalyzerInformation::Info::parse(const std::string& filesTxtLine) { return false; if (sep3 == sep2 + 1) - fileIndex = 0; + fsFileId = 0; else { try { - fileIndex = std::stoi(filesTxtLine.substr(sep2+1, sep3-sep2-1)); + fsFileId = std::stoi(filesTxtLine.substr(sep2+1, sep3-sep2-1)); } catch (const std::exception&) { return false; } @@ -206,37 +239,78 @@ bool AnalyzerInformation::Info::parse(const std::string& filesTxtLine) { return true; } -// TODO: bail out on unexpected data -void AnalyzerInformation::processFilesTxt(const std::string& buildDir, const std::function& handler) +std::string AnalyzerInformation::processFilesTxt(const std::string& buildDir, const std::function& handler, bool debug) { const std::string filesTxt(buildDir + "/files.txt"); std::ifstream fin(filesTxt.c_str()); std::string filesTxtLine; while (std::getline(fin, filesTxtLine)) { AnalyzerInformation::Info filesTxtInfo; - if (!filesTxtInfo.parse(filesTxtLine)) { - return; - } + if (!filesTxtInfo.parse(filesTxtLine)) + return "failed to parse '" + filesTxtLine + "' from '" + filesTxt + "'"; + + if (filesTxtInfo.afile.empty()) + return "empty afile from '" + filesTxt + "'"; const std::string xmlfile = buildDir + '/' + filesTxtInfo.afile; tinyxml2::XMLDocument doc; const tinyxml2::XMLError error = doc.LoadFile(xmlfile.c_str()); + if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) { + /* FIXME: this can currently not be reported as an error because: + * - --clang does not generate any analyzer information - see #14456 + * - markup files might not generate analyzer information + * - files with preprocessor errors might not generate analyzer information + */ + if (debug) + std::cout << "'" + xmlfile + "' from '" + filesTxt + "' not found"; + continue; + } + if (error != tinyxml2::XML_SUCCESS) - return; + return "failed to load '" + xmlfile + "' from '" + filesTxt + "'"; const tinyxml2::XMLElement * const rootNode = doc.FirstChildElement(); if (rootNode == nullptr) - return; + return "no root node found in '" + xmlfile + "' from '" + filesTxt + "'"; + + if (strcmp(rootNode->Name(), "analyzerinfo") != 0) + return "unexpected root node in '" + xmlfile + "' from '" + filesTxt + "'"; for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) { if (std::strcmp(e->Name(), "FileInfo") != 0) continue; const char *checkattr = e->Attribute("check"); - if (checkattr == nullptr) + if (checkattr == nullptr) { + if (debug) + std::cout << "'check' attribute missing in 'FileInfo' in '" << xmlfile << "' from '" << filesTxt + "'"; continue; + } handler(checkattr, e, filesTxtInfo); } } + + // TODO: error on empty file? + return ""; } +void AnalyzerInformation::reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId) +{ + if (buildDir.empty() || sourcefile.empty()) + return; + + const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg,fsFileId); + std::ifstream ifs(analyzerInfoFile); + if (!ifs.is_open()) + return; + + std::ostringstream iss; + iss << ifs.rdbuf(); + ifs.close(); + + std::string content = iss.str(); + content.resize(content.find("")); + + mOutputStream.open(analyzerInfoFile, std::ios::trunc); + mOutputStream << content; +} diff --git a/lib/analyzerinfo.h b/lib/analyzerinfo.h index 881076c09f4..d2a83c747c3 100644 --- a/lib/analyzerinfo.h +++ b/lib/analyzerinfo.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ struct FileSettings; namespace tinyxml2 { class XMLDocument; class XMLElement; -}; +} /// @addtogroup Core /// @{ @@ -57,14 +57,19 @@ class CPPCHECKLIB AnalyzerInformation { public: ~AnalyzerInformation(); - static void writeFilesTxt(const std::string &buildDir, const std::list &sourcefiles, const std::string &userDefines, const std::list &fileSettings); + static void writeFilesTxt(const std::string &buildDir, const std::list &sourcefiles, const std::list &fileSettings); /** Close current TU.analyzerinfo file */ void close(); - bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex, std::size_t hash, std::list &errors); + /** + * @throws std::runtime_error thrown if the output file is already open or the output file cannot be opened + */ + bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId, std::size_t hash, std::list &errors, bool debug = false); void reportErr(const ErrorMessage &msg); void setFileInfo(const std::string &check, const std::string &fileInfo); - static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex); + static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId); + + void reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId); static const char sep = ':'; @@ -73,18 +78,18 @@ class CPPCHECKLIB AnalyzerInformation { bool parse(const std::string& filesTxtLine); std::string afile; std::string cfg; - int fileIndex = 0; + std::size_t fsFileId = 0; std::string sourceFile; }; - static void processFilesTxt(const std::string& buildDir, const std::function& handler); + static std::string processFilesTxt(const std::string& buildDir, const std::function& handler, bool debug = false); protected: - static std::string getFilesTxt(const std::list &sourcefiles, const std::string &userDefines, const std::list &fileSettings); + static std::string getFilesTxt(const std::list &sourcefiles, const std::list &fileSettings); - static std::string getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, int fileIndex); + static std::string getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, int fsFileId); - static bool skipAnalysis(const tinyxml2::XMLDocument &analyzerInfoDoc, std::size_t hash, std::list &errors); + static std::string skipAnalysis(const tinyxml2::XMLDocument &analyzerInfoDoc, std::size_t hash, std::list &errors); private: std::ofstream mOutputStream; diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 8eac2b777ab..56a9489d00e 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -320,12 +320,12 @@ Library::Container::Yield astContainerYield(const Token* tok, const Library& lib return ftokCont.second->getYield(ftokCont.first->str()); } -Library::Container::Yield astFunctionYield(const Token* tok, const Settings& settings, const Token** ftok) +Library::Container::Yield astFunctionYield(const Token* tok, const Library& library, const Token** ftok) { if (!tok) return Library::Container::Yield::NO_YIELD; - const auto* function = settings.library.getFunction(tok); + const auto* function = library.getFunction(tok); if (!function) return Library::Container::Yield::NO_YIELD; @@ -400,6 +400,8 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp, } while (ret && ret->str() == ".") ret = ret->astOperand2(); + while (ret && ret->isCast()) + ret = ret->astOperand2() ? ret->astOperand2() : ret->astOperand1(); if (ret && ret->str() == "=" && ret->astOperand1() && ret->astOperand1()->varId()) ret = ret->astOperand1(); else if (ret && ret->varId() == 0U) @@ -461,7 +463,7 @@ bool isTemporary(const Token* tok, const Library* library, bool unknown) return false; return !branchTok->astOperand1()->valueType()->isTypeEqual(branchTok->astOperand2()->valueType()); } - if (Token::simpleMatch(tok, "(") && tok->astOperand1() && + if (Token::Match(tok, "(|{") && tok->astOperand1() && (tok->astOperand2() || Token::simpleMatch(tok->next(), ")"))) { if (Token::simpleMatch(tok->astOperand1(), "typeid")) return false; @@ -498,9 +500,6 @@ bool isTemporary(const Token* tok, const Library* library, bool unknown) // Currying a function is unknown in cppcheck if (Token::simpleMatch(tok, "(") && Token::simpleMatch(tok->astOperand1(), "(")) return unknown; - if (Token::simpleMatch(tok, "{") && Token::simpleMatch(tok->astParent(), "return") && tok->astOperand1() && - !tok->astOperand2()) - return isTemporary(tok->astOperand1(), library); return true; } @@ -1084,7 +1083,7 @@ bool isAliasOf(const Token* tok, const Token* expr, nonneg int* indirect) r = findAstNode(expr, [&](const Token* childTok) { if (childTok->exprId() == 0) return false; - if (ref.token != tok && expr->exprId() == childTok->exprId()) { + if (ref.token != tok && expr->exprId() == childTok->exprId() && ref.token->isUnaryOp("*") && expr->exprId() == ref.token->astOperand1()->exprId()) { if (indirect) *indirect = 0; return true; @@ -1810,21 +1809,31 @@ bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Se return commutativeEquals; } -static bool isZeroBoundCond(const Token * const cond) +static bool isZeroBoundCond(const Token * const cond, bool reverse) { - if (cond == nullptr) + if (cond == nullptr || !cond->isBinaryOp()) return false; + + const Token* op = reverse ? cond->astOperand1() : cond->astOperand2(); + if (!op->hasKnownIntValue()) + return true; + // Assume unsigned - // TODO: Handle reverse conditions - const bool isZero = cond->astOperand2()->getValue(0); - if (cond->str() == "==" || cond->str() == ">=") + const bool isZero = op->getKnownIntValue() == 0; + std::string cmp = cond->str(); + if (reverse) { + if (cmp[0] == '>') + cmp[0] = '<'; + else if (cmp[0] == '<') + cmp[0] = '>'; + } + + if (cmp == "==" || cmp == ">=") return isZero; - if (cond->str() == "<=") + if (cmp == "<=") return true; - if (cond->str() == "<") + if (cmp == "<") return !isZero; - if (cond->str() == ">") - return false; return false; } @@ -1888,7 +1897,7 @@ bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const c if (isSameExpression(true, cond1->astOperand2(), cond2->astOperand2(), settings, pure, followVar, errors)) return isDifferentKnownValues(cond1->astOperand1(), cond2->astOperand1()); } - // TODO: Handle reverse conditions + if (Library::isContainerYield(cond1, Library::Container::Yield::EMPTY, "empty") && Library::isContainerYield(cond2->astOperand1(), Library::Container::Yield::SIZE, "size") && isSameExpression(true, @@ -1898,7 +1907,19 @@ bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const c pure, followVar, errors)) { - return !isZeroBoundCond(cond2); + return !isZeroBoundCond(cond2, false); + } + + if (Library::isContainerYield(cond1, Library::Container::Yield::EMPTY, "empty") && + Library::isContainerYield(cond2->astOperand2(), Library::Container::Yield::SIZE, "size") && + isSameExpression(true, + cond1->astOperand1()->astOperand1(), + cond2->astOperand2()->astOperand1()->astOperand1(), + settings, + pure, + followVar, + errors)) { + return !isZeroBoundCond(cond2, true); } if (Library::isContainerYield(cond2, Library::Container::Yield::EMPTY, "empty") && @@ -1910,7 +1931,19 @@ bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const c pure, followVar, errors)) { - return !isZeroBoundCond(cond1); + return !isZeroBoundCond(cond1, false); + } + + if (Library::isContainerYield(cond2, Library::Container::Yield::EMPTY, "empty") && + Library::isContainerYield(cond1->astOperand2(), Library::Container::Yield::SIZE, "size") && + isSameExpression(true, + cond2->astOperand1()->astOperand1(), + cond1->astOperand2()->astOperand1()->astOperand1(), + settings, + pure, + followVar, + errors)) { + return !isZeroBoundCond(cond1, true); } } @@ -2006,9 +2039,7 @@ bool isOppositeExpression(const Token * const tok1, const Token * const tok2, co static bool functionModifiesArguments(const Function* f) { return std::any_of(f->argumentList.cbegin(), f->argumentList.cend(), [](const Variable& var) { - if (var.isReference() || var.isPointer()) - return !var.isConst(); - return true; + return var.isReference() && !var.isConst(); }); } @@ -2089,7 +2120,7 @@ bool isConstFunctionCall(const Token* ftok, const Library& library) return false; }); } - return true; + return false; } bool isConstExpression(const Token *tok, const Library& library) @@ -2125,7 +2156,8 @@ bool isWithoutSideEffects(const Token* tok, bool checkArrayAccess, bool checkRef tok = tok->astOperand2(); if (tok && tok->varId()) { const Variable* var = tok->variable(); - return var && ((!var->isClass() && (checkReference || !var->isReference())) || var->isPointer() || (checkArrayAccess ? var->isStlType() && !var->isStlType(CheckClass::stl_containers_not_const) : var->isStlType())); + return var && ((!var->isClass() && (checkReference || !var->isReference())) || var->isPointer() || + (checkArrayAccess ? var->isArray() || (var->isStlType() && !var->isStlType(CheckClass::stl_containers_not_const)) : var->isStlType())); } return true; } @@ -2471,17 +2503,6 @@ static bool isTrivialConstructor(const Token* tok) return false; } -static bool isArray(const Token* tok) -{ - if (!tok) - return false; - if (tok->variable()) - return tok->variable()->isArray(); - if (Token::simpleMatch(tok, ".")) - return isArray(tok->astOperand2()); - return false; -} - bool isMutableExpression(const Token* tok) { if (!tok) @@ -2499,9 +2520,7 @@ bool isMutableExpression(const Token* tok) if (tok->astOperand1() && Token::simpleMatch(tok, "[")) return isMutableExpression(tok->astOperand1()); if (const Variable* var = tok->variable()) { - if (var->nameToken() == tok) - return false; - if (!var->isPointer() && var->isConst()) + if (var->isConst() && !var->isPointer() && (!var->isArray() || !var->isArgument())) return false; } return true; @@ -2550,17 +2569,10 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(tok, 1 + argnr, indirect); if (argDirection == Library::ArgumentChecks::Direction::DIR_IN) return false; + if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT || argDirection == Library::ArgumentChecks::Direction::DIR_INOUT) + return true; const bool requireNonNull = settings.library.isnullargbad(tok, 1 + argnr); - if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT || - argDirection == Library::ArgumentChecks::Direction::DIR_INOUT) { - if (indirect == 0 && isArray(tok1)) - return true; - const bool requireInit = settings.library.isuninitargbad(tok, 1 + argnr); - // Assume that if the variable must be initialized then the indirection is 1 - if (indirect > 0 && requireInit && requireNonNull) - return true; - } if (Token::simpleMatch(tok->tokAt(-2), "std :: tie")) return true; // if the library says 0 is invalid @@ -2630,7 +2642,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, if (!tok->isMutableExpr()) return false; - if (indirect == 0 && isConstVarExpression(tok)) + if (isConstVarExpression(tok)) return false; const Token *tok2 = tok; @@ -2638,7 +2650,8 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, while ((tok2->astParent() && tok2->astParent()->isUnaryOp("*")) || (Token::simpleMatch(tok2->astParent(), ".") && !Token::Match(tok2->astParent()->astParent(), "[(,]")) || (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->") || - (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1())) { + (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1()) || + (Token::simpleMatch(tok2->astParent(), "(") && tok2->astParent()->isCast())) { if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->" && !hasOverloadedMemberAccess(tok2)))) derefs++; if (derefs > indirect) @@ -2694,7 +2707,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, if (isVariableChanged(tok2->astParent(), indirect + 1, settings, depth - 1)) return true; } else { - // If its already const then it cant be modified + // If its already const then it can't be modified if (vt && vt->isConst(indirect)) return false; } @@ -3088,10 +3101,7 @@ static const Token* findExpressionChangedImpl(const Token* expr, } bool global = false; if (tok->variable()) { - if (tok->variable()->isConst()) - return false; - global = !tok->variable()->isLocal() && !tok->variable()->isArgument() && - !(tok->variable()->isMember() && !tok->variable()->isStatic()); + global = !tok->variable()->isLocal() && !tok->variable()->isArgument(); } else if (tok->isIncompleteVar() && !tok->isIncompleteConstant()) { global = true; } @@ -3104,6 +3114,8 @@ static const Token* findExpressionChangedImpl(const Token* expr, if (vt->type == ValueType::ITERATOR) ++indirect; } + if (indirect == 0 && tok2->astParent() && tok2->astParent()->isUnaryOp("*")) + ++indirect; for (int i = 0; i <= indirect; ++i) { if (isExpressionChangedAt(tok, tok2, i, global, settings, depth)) return true; @@ -3373,7 +3385,7 @@ bool isConstVarExpression(const Token *tok, const std::functionstr() == "?" && tok->astOperand2() && tok->astOperand2()->str() == ":") // ternary operator - return isConstVarExpression(tok->astOperand2()->astOperand1()) && isConstVarExpression(tok->astOperand2()->astOperand2()); // left and right of ":" + return isConstVarExpression(tok->astOperand2()->astOperand1()) || isConstVarExpression(tok->astOperand2()->astOperand2()); // left and right of ":" if (skipPredicate && skipPredicate(tok)) return false; if (Token::simpleMatch(tok->previous(), "sizeof (")) @@ -3423,13 +3435,19 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings // variable init/constructor call? if (!func && ftok->variable() && ftok == ftok->variable()->nameToken()) { // STL types or containers don't initialize external variables - if (ftok->variable()->isStlType() || (ftok->variable()->valueType() && ftok->variable()->valueType()->container)) + if (indirect == 0 && (ftok->variable()->isStlType() || (ftok->variable()->valueType() && ftok->variable()->valueType()->container))) return ExprUsage::Used; // TODO: resolve multiple constructors if (ftok->variable()->type() && ftok->variable()->type()->classScope) { const int nCtor = ftok->variable()->type()->classScope->numConstructors; - if (nCtor == 0) + if (nCtor == 0) { + if (indirect > 0) { + const std::vector argvar = getArgumentVars(ftok->astParent(), argnr); + if (argvar.size() == 1 && argvar[0]->valueType() && argvar[0]->valueType()->pointer == indirect) + return ExprUsage::NotUsed; + } return ExprUsage::Used; + } if (nCtor == 1) { const Scope* scope = ftok->variable()->type()->classScope; auto it = std::find_if(scope->functionList.begin(), scope->functionList.end(), [](const Function& f) { @@ -3474,6 +3492,11 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings const bool isuninitbad = settings.library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect); if (isuninitbad && (!addressOf || isnullbad)) return ExprUsage::Used; + const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(ftok, argnr + 1, indirect); + if (argDirection == Library::ArgumentChecks::Direction::DIR_IN) // TODO: DIR_INOUT? + return ExprUsage::Used; + if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT) + return ExprUsage::NotUsed; } return ExprUsage::Inconclusive; } @@ -3674,21 +3697,27 @@ bool isGlobalData(const Token *expr) globalData = true; return ChildrenToVisit::none; } - if (Token::Match(tok, "[*[]") && tok->astOperand1() && tok->astOperand1()->variable()) { + if (Token::Match(tok, "[*[]") && tok->astOperand1()) { // TODO check if pointer points at local data - const Variable *lhsvar = tok->astOperand1()->variable(); - const ValueType *lhstype = tok->astOperand1()->valueType(); - if (lhsvar->isPointer() || !lhstype || lhstype->type == ValueType::Type::ITERATOR) { - globalData = true; - return ChildrenToVisit::none; - } - if (lhsvar->isArgument() && lhsvar->isArray()) { - globalData = true; - return ChildrenToVisit::none; + const Token *lhs = tok->astOperand1(); + if (lhs->isCast()) { + lhs = lhs->astOperand2() ? lhs->astOperand2() : lhs->astOperand1(); } - if (lhsvar->isArgument() && lhstype->type <= ValueType::Type::VOID && !lhstype->container) { - globalData = true; - return ChildrenToVisit::none; + if (lhs && lhs->variable()) { + const Variable *lhsvar = lhs->variable(); + const ValueType *lhstype = lhs->valueType(); + if (lhsvar->isPointer() || !lhstype || lhstype->type == ValueType::Type::ITERATOR) { + globalData = true; + return ChildrenToVisit::none; + } + if (lhsvar->isArgument() && lhsvar->isArray()) { + globalData = true; + return ChildrenToVisit::none; + } + if (lhsvar->isArgument() && lhstype->type <= ValueType::Type::VOID && !lhstype->container) { + globalData = true; + return ChildrenToVisit::none; + } } } if (tok->varId() == 0 && tok->isName() && tok->strAt(-1) != ".") { diff --git a/lib/astutils.h b/lib/astutils.h index 4002e065ab5..617e01f0415 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -166,7 +166,7 @@ bool astIsContainerString(const Token* tok); Library::Container::Action astContainerAction(const Token* tok, const Library& library, const Token** ftok = nullptr); Library::Container::Yield astContainerYield(const Token* tok, const Library& library, const Token** ftok = nullptr); -Library::Container::Yield astFunctionYield(const Token* tok, const Settings& settings, const Token** ftok = nullptr); +Library::Container::Yield astFunctionYield(const Token* tok, const Library& library, const Token** ftok = nullptr); /** Is given token a range-declaration in a range-based for loop */ bool astIsRangeBasedForDecl(const Token* tok); diff --git a/lib/check.cpp b/lib/check.cpp index 58b8dbfe0e1..4033378e927 100644 --- a/lib/check.cpp +++ b/lib/check.cpp @@ -26,34 +26,15 @@ #include "tokenize.h" #include "vfvalue.h" -#include #include #include -#include #include //--------------------------------------------------------------------------- -Check::Check(const std::string &aname) - : mName(aname) -{ - { - const auto it = std::find_if(instances().begin(), instances().end(), [&](const Check *i) { - return i->name() == aname; - }); - if (it != instances().end()) - throw std::runtime_error("'" + aname + "' instance already exists"); - } - - // make sure the instances are sorted - const auto it = std::find_if(instances().begin(), instances().end(), [&](const Check* i) { - return i->name() > aname; - }); - if (it == instances().end()) - instances().push_back(this); - else - instances().insert(it, this); -} +Check::Check(std::string aname) + : mName(std::move(aname)) +{} void Check::writeToErrorList(const ErrorMessage &errmsg) { @@ -88,19 +69,6 @@ bool Check::wrongData(const Token *tok, const char *str) return true; } -std::list &Check::instances() -{ -#ifdef __SVR4 - // Under Solaris, destructors are called in wrong order which causes a segmentation fault. - // This fix ensures pointer remains valid and reachable until program terminates. - static std::list *_instances= new std::list; - return *_instances; -#else - static std::list _instances; - return _instances; -#endif -} - std::string Check::getMessageId(const ValueFlow::Value &value, const char id[]) { if (value.condition != nullptr) @@ -130,6 +98,7 @@ ErrorPath Check::getErrorPath(const Token* errtok, const ValueFlow::Value* value void Check::logChecker(const char id[]) { - reportError(nullptr, Severity::internal, "logChecker", id); + if (!mSettings->buildDir.empty() || mSettings->collectLogCheckers()) + reportError(nullptr, Severity::internal, "logChecker", id); } diff --git a/lib/check.h b/lib/check.h index 4e3c5b9a4e3..9a50e64baa1 100644 --- a/lib/check.h +++ b/lib/check.h @@ -59,25 +59,22 @@ class Tokenizer; class CPPCHECKLIB Check { public: /** This constructor is used when registering the CheckClass */ - explicit Check(const std::string &aname); + explicit Check(std::string aname); protected: /** This constructor is used when running checks. */ Check(std::string aname, const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger), mName(std::move(aname)) {} +private: + static std::list &instances_internal(); + public: - virtual ~Check() { - if (!mTokenizer) - instances().remove(this); - } + virtual ~Check() = default; Check(const Check &) = delete; Check& operator=(const Check &) = delete; - /** List of registered check classes. This is used by Cppcheck to run checks and generate documentation */ - static std::list &instances(); - /** run checks, the token list is not simplified */ virtual void runChecks(const Tokenizer &, ErrorLogger *) = 0; diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp index a106b0afe5f..b33ab5bdbcb 100644 --- a/lib/check64bit.cpp +++ b/lib/check64bit.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,11 +36,6 @@ // CWE ids used static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior -// Register this check class (by creating a static instance of it) -namespace { - Check64BitPortability instance; -} - static bool is32BitIntegerReturn(const Function* func, const Settings* settings) { if (settings->platform.sizeof_pointer != 8) diff --git a/lib/checkassert.cpp b/lib/checkassert.cpp index 3ab55967ede..ce2d7c62169 100644 --- a/lib/checkassert.cpp +++ b/lib/checkassert.cpp @@ -39,11 +39,6 @@ // CWE ids used static const CWE CWE398(398U); // Indicator of Poor Code Quality -// Register this check class (by creating a static instance of it) -namespace { - CheckAssert instance; -} - void CheckAssert::assertWithSideEffects() { if (!mSettings->severity.isEnabled(Severity::warning)) diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index bc18c3dc477..fdc5deceefa 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,12 +39,6 @@ //--------------------------------------------------------------------------- - -// Register this check class into cppcheck by creating a static instance of it.. -namespace { - CheckAutoVariables instance; -} - static const CWE CWE398(398U); // Indicator of Poor Code Quality static const CWE CWE562(562U); // Return of Stack Variable Address static const CWE CWE590(590U); // Free of Memory not on the Heap @@ -263,6 +257,29 @@ static bool hasOverloadedAssignment(const Token* tok, bool& inconclusive) return true; } +static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settings& settings) +{ + const Token *endBracket = nullptr; + if (!Token::Match(tok, "[;{}] %var% . %var%")) { + if (!Token::Match(tok, "[;{}] %var% [")) + return false; + endBracket = tok->linkAt(2); + if (!Token::Match(endBracket, "] . %var%")) + return false; + } + if (!isPtrArg(tok->next())) + return false; + const Token* assign = (endBracket ? endBracket->next() : tok->tokAt(2))->astParent(); + while (Token::simpleMatch(assign, "[")) + assign = assign->astParent(); + if (!Token::simpleMatch(assign, "=")) + return false; + if (!isAutoVariableRHS(assign->astOperand2(), settings)) + return false; + rhs = assign->astOperand2(); + return true; +} + void CheckAutoVariables::autoVariables() { logChecker("CheckAutoVariables::autoVariables"); @@ -277,6 +294,7 @@ void CheckAutoVariables::autoVariables() continue; } // Critical assignment + const Token* rhs{}; if (Token::Match(tok, "[;{}] %var% =") && isRefPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(2)->astOperand2(), *mSettings)) { checkAutoVariableAssignment(tok->next(), false); } else if (Token::Match(tok, "[;{}] * %var% =") && isPtrArg(tok->tokAt(2)) && isAutoVariableRHS(tok->tokAt(3)->astOperand2(), *mSettings)) { @@ -285,12 +303,12 @@ void CheckAutoVariables::autoVariables() if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive)) checkAutoVariableAssignment(tok->next(), inconclusive); tok = tok->tokAt(4); - } else if (Token::Match(tok, "[;{}] %var% . %var% =") && isPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(4)->astOperand2(), *mSettings)) { + } else if (isMemberAssignment(tok, rhs, *mSettings)) { const Token* lhs = tok->tokAt(3); bool inconclusive = false; if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive)) checkAutoVariableAssignment(tok->next(), inconclusive); - tok = tok->tokAt(5); + tok = rhs; } else if (Token::Match(tok, "[;{}] %var% [") && Token::simpleMatch(tok->linkAt(2), "] =") && (isPtrArg(tok->next()) || isArrayArg(tok->next(), *mSettings)) && isAutoVariableRHS(tok->linkAt(2)->next()->astOperand2(), *mSettings)) { @@ -330,8 +348,10 @@ bool CheckAutoVariables::checkAutoVariableAssignment(const Token *expr, bool inc if (!startToken) startToken = Token::findsimplematch(expr, "=")->next(); for (const Token *tok = startToken; tok; tok = tok->next()) { - if (tok->str() == "}" && tok->scope()->type == ScopeType::eFunction) + if (tok->str() == "}" && tok->scope()->type == ScopeType::eFunction) { errorAutoVariableAssignment(expr, inconclusive); + return true; + } if (Token::Match(tok, "return|throw|break|continue")) { errorAutoVariableAssignment(expr, inconclusive); @@ -368,6 +388,8 @@ bool CheckAutoVariables::checkAutoVariableAssignment(const Token *expr, bool inc void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inconclusive) { + diag(tok); + if (!inconclusive) { reportError(tok, Severity::error, "autoVariables", "Address of local auto-variable assigned to a function parameter.\n" @@ -617,7 +639,8 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token if ((tokvalue->variable() && !isEscapedReference(tokvalue->variable()) && isInScope(tokvalue->variable()->nameToken(), scope)) || isDeadTemporary(tokvalue, nullptr, mSettings->library)) { - errorReturnDanglingLifetime(tok, &val); + if (!diag(tokvalue)) + errorReturnDanglingLifetime(tok, &val); break; } } else if (tokvalue->variable() && isDeadScope(tokvalue->variable()->nameToken(), tok->scope())) { @@ -647,14 +670,16 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token const Token* nextTok = nextAfterAstRightmostLeaf(tok->astTop()); if (!nextTok) nextTok = tok->next(); - if (var && (!var->isLocal() || var->isStatic()) && !var->isArgument() && !(val.tokvalue && val.tokvalue->variable() && val.tokvalue->variable()->isStatic()) && + if (var && (!var->isLocal() || var->isStatic()) && (!var->isArgument() || (var->isReference() && isInScope(val.tokvalue, var->scope()))) && + !(val.tokvalue && val.tokvalue->variable() && val.tokvalue->variable()->isStatic()) && !isVariableChanged(nextTok, tok->scope()->bodyEnd, var->valueType() ? var->valueType()->pointer : 0, var->declarationId(), var->isGlobal(), *mSettings)) { - errorDanglngLifetime(tok2, &val, var->isLocal()); + if (!diag(tok2)) + errorDanglngLifetime(tok2, &val, var->isLocal()); break; } } @@ -796,8 +821,8 @@ void CheckAutoVariables::runChecks(const Tokenizer &tokenizer, ErrorLogger *erro { CheckAutoVariables checkAutoVariables(&tokenizer, &tokenizer.getSettings(), errorLogger); checkAutoVariables.assignFunctionArg(); - checkAutoVariables.checkVarLifetime(); checkAutoVariables.autoVariables(); + checkAutoVariables.checkVarLifetime(); } void CheckAutoVariables::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp index 93e501416aa..c9a66876317 100644 --- a/lib/checkbool.cpp +++ b/lib/checkbool.cpp @@ -32,11 +32,6 @@ #include //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckBool instance; -} - static const CWE CWE398(398U); // Indicator of Poor Code Quality static const CWE CWE571(571U); // Expression is Always True static const CWE CWE587(587U); // Assignment of a Fixed Address to a Pointer diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index b052fd52b51..3ba41882316 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,7 @@ #include "utils.h" #include "valueflow.h" #include "vfvalue.h" +#include "vf_common.h" #include #include @@ -49,13 +50,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckBufferOverrun instance; -} - -//--------------------------------------------------------------------------- - // CWE ids used: static const CWE CWE131(131U); // Incorrect Calculation of Buffer Size static const CWE CWE170(170U); // Improper Null Termination @@ -83,7 +77,7 @@ static const Token* getRealBufferTok(const Token* tok) { return (op->valueType() && op->valueType()->pointer) ? op : tok; } -static int getMinFormatStringOutputLength(const std::vector ¶meters, nonneg int formatStringArgNr) +static int getMinFormatStringOutputLength(const std::vector ¶meters, nonneg int formatStringArgNr, const Settings& settings) { if (formatStringArgNr <= 0 || formatStringArgNr > parameters.size()) return 0; @@ -138,8 +132,8 @@ static int getMinFormatStringOutputLength(const std::vector ¶m break; case 's': parameterLength = 0; - if (inputArgNr < parameters.size() && parameters[inputArgNr]->tokType() == Token::eString) - parameterLength = Token::getStrLength(parameters[inputArgNr]); + if (inputArgNr < parameters.size()) + parameterLength = ValueFlow::valueFlowGetStrLength(parameters[inputArgNr], settings); handleNextParameter = true; break; @@ -602,7 +596,7 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi switch (minsize.type) { case Library::ArgumentChecks::MinSize::Type::STRLEN: if (settings.library.isargformatstr(ftok, minsize.arg)) { - return getMinFormatStringOutputLength(args, minsize.arg) < bufferSize; + return getMinFormatStringOutputLength(args, minsize.arg, settings) < bufferSize; } else if (arg) { const Token *strtoken = arg->getValueTokenMaxStrLength(); if (strtoken) @@ -706,10 +700,10 @@ void CheckBufferOverrun::bufferOverflowError(const Token *tok, const ValueFlow:: void CheckBufferOverrun::arrayIndexThenCheck() { - if (!mSettings->severity.isEnabled(Severity::portability)) + if (!mSettings->severity.isEnabled(Severity::style)) return; - logChecker("CheckBufferOverrun::arrayIndexThenCheck"); + logChecker("CheckBufferOverrun::arrayIndexThenCheck"); // style const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * const scope : symbolDatabase->functionScopes) { diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 30cc582651c..3313fb636ed 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,11 +43,6 @@ //--------------------------------------------------------------------------- -// Register CheckClass.. -namespace { - CheckClass instance; -} - static const CWE CWE398(398U); // Indicator of Poor Code Quality static const CWE CWE404(404U); // Improper Resource Shutdown or Release static const CWE CWE665(665U); // Improper Initialization @@ -116,6 +111,90 @@ CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, Err mSymbolDatabase(tokenizer?tokenizer->getSymbolDatabase():nullptr) {} +bool CheckClass::isInitialized(const CheckClass::Usage& usage, FunctionType funcType) const +{ + const Variable& var = *usage.var; + + if (usage.assign || usage.init || var.isStatic()) + return true; + + if (!var.nameToken() || var.nameToken()->isAnonymous()) + return true; + + if (var.valueType() && var.valueType()->pointer == 0 && var.type() && var.type()->needInitialization == Type::NeedInitialization::False && var.type()->derivedFrom.empty()) + return true; + + if (var.isConst() && funcType == FunctionType::eOperatorEqual) // We can't set const members in assignment operator + return true; + + // Check if this is a class constructor + if (!var.isPointer() && !var.isPointerArray() && var.isClass() && funcType == FunctionType::eConstructor) { + // Unknown type so assume it is initialized + if (!var.type()) { + if (var.isStlType() && var.valueType() && var.valueType()->containerTypeToken) { + if (var.valueType()->type == ValueType::Type::ITERATOR) + { + // needs initialization + } + else if (var.getTypeName() == "std::array") { + const Token* ctt = var.valueType()->containerTypeToken; + if (!ctt->isStandardType() && + (!ctt->type() || ctt->type()->needInitialization != Type::NeedInitialization::True) && + !mSettings->library.podtype(ctt->str())) // TODO: handle complex type expression + return true; + } + else + return true; + } + else + return true; + } + + // Known type that doesn't need initialization or + // known type that has member variables of an unknown type + else if (var.type()->needInitialization != Type::NeedInitialization::True) + return true; + } + + // Check if type can't be copied + if (!var.isPointer() && !var.isPointerArray() && var.typeScope()) { + if (funcType == FunctionType::eMoveConstructor) { + if (canNotMove(var.typeScope())) + return true; + } + else { + if (canNotCopy(var.typeScope())) + return true; + } + } + return false; +} + +void CheckClass::handleUnionMembers(std::vector& usageList) +{ + // Assign 1 union member => assign all union members + for (const Usage& usage : usageList) { + const Variable& var = *usage.var; + if (!usage.assign && !usage.init) + continue; + const Scope* varScope1 = var.nameToken()->scope(); + while (varScope1->type == ScopeType::eStruct) + varScope1 = varScope1->nestedIn; + if (varScope1->type == ScopeType::eUnion) { + for (Usage& usage2 : usageList) { + const Variable& var2 = *usage2.var; + if (usage2.assign || usage2.init || var2.isStatic()) + continue; + const Scope* varScope2 = var2.nameToken()->scope(); + while (varScope2->type == ScopeType::eStruct) + varScope2 = varScope2->nestedIn; + if (varScope1 == varScope2) + usage2.assign = true; + } + } + } +} + //--------------------------------------------------------------------------- // ClassCheck: Check that all class constructors are ok. //--------------------------------------------------------------------------- @@ -145,6 +224,7 @@ void CheckClass::constructors() }); // There are no constructors. + std::set diagVars; if (scope->numConstructors == 0 && printStyle && !usedInUnion) { // If there is a private variable, there should be a constructor.. int needInit = 0, haveInit = 0; @@ -163,8 +243,10 @@ void CheckClass::constructors() if (haveInit == 0) noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct"); else - for (const Variable* uv : uninitVars) + for (const Variable* uv : uninitVars) { uninitVarError(uv->typeStartToken(), uv->scope()->className, uv->name()); + diagVars.emplace(uv); + } } } @@ -201,85 +283,15 @@ void CheckClass::constructors() std::list callstack; initializeVarList(func, callstack, scope, usageList); - // Assign 1 union member => assign all union members - for (const Usage &usage : usageList) { - const Variable& var = *usage.var; - if (!usage.assign && !usage.init) - continue; - const Scope* varScope1 = var.nameToken()->scope(); - while (varScope1->type == ScopeType::eStruct) - varScope1 = varScope1->nestedIn; - if (varScope1->type == ScopeType::eUnion) { - for (Usage &usage2 : usageList) { - const Variable& var2 = *usage2.var; - if (usage2.assign || usage2.init || var2.isStatic()) - continue; - const Scope* varScope2 = var2.nameToken()->scope(); - while (varScope2->type == ScopeType::eStruct) - varScope2 = varScope2->nestedIn; - if (varScope1 == varScope2) - usage2.assign = true; - } - } - } + handleUnionMembers(usageList); // Check if any variables are uninitialized for (const Usage &usage : usageList) { - const Variable& var = *usage.var; - - if (usage.assign || usage.init || var.isStatic()) - continue; - - if (!var.nameToken() || var.nameToken()->isAnonymous()) + if (isInitialized(usage, func.type)) continue; - if (var.valueType() && var.valueType()->pointer == 0 && var.type() && var.type()->needInitialization == Type::NeedInitialization::False && var.type()->derivedFrom.empty()) - continue; - - if (var.isConst() && func.isOperator()) // We can't set const members in assignment operator - continue; - - // Check if this is a class constructor - if (!var.isPointer() && !var.isPointerArray() && var.isClass() && func.type == FunctionType::eConstructor) { - // Unknown type so assume it is initialized - if (!var.type()) { - if (var.isStlType() && var.valueType() && var.valueType()->containerTypeToken) { - if (var.valueType()->type == ValueType::Type::ITERATOR) - { - // needs initialization - } - else if (var.getTypeName() == "std::array") { - const Token* ctt = var.valueType()->containerTypeToken; - if (!ctt->isStandardType() && - (!ctt->type() || ctt->type()->needInitialization != Type::NeedInitialization::True) && - !mSettings->library.podtype(ctt->str())) // TODO: handle complex type expression - continue; - } - else - continue; - } - else - continue; - } - - // Known type that doesn't need initialization or - // known type that has member variables of an unknown type - else if (var.type()->needInitialization != Type::NeedInitialization::True) - continue; - } - - // Check if type can't be copied - if (!var.isPointer() && !var.isPointerArray() && var.typeScope()) { - if (func.type == FunctionType::eMoveConstructor) { - if (canNotMove(var.typeScope())) - continue; - } else { - if (canNotCopy(var.typeScope())) - continue; - } - } - // Is there missing member copy in copy/move constructor or assignment operator? + const Variable& var = *usage.var; bool missingCopy = false; // Don't warn about unknown types in copy constructors since we @@ -326,6 +338,45 @@ void CheckClass::constructors() } } } + + if (scope->numConstructors == 0) { + + // Mark all variables not used + clearAllVar(usageList); + + // Variables with default initializers + bool hasAnyDefaultInit = false; + bool hasAnySelfInit = false; + const bool cpp14OrLater = mSettings->standards.cpp >= Standards::CPP14; + for (Usage& usage : usageList) { + const Variable& var = *usage.var; + + // check for C++11 initializer + if (var.hasDefault()) { + usage.init = true; + hasAnyDefaultInit = true; + } else if (cpp14OrLater && !hasAnySelfInit && isInitialized(usage, FunctionType::eConstructor)) { + hasAnySelfInit = true; + } + } + if (!hasAnyDefaultInit && !hasAnySelfInit) + continue; + + handleUnionMembers(usageList); + + // Check if any variables are uninitialized + for (const Usage& usage : usageList) { + if (isInitialized(usage, FunctionType::eConstructor)) + continue; + + const Variable& var = *usage.var; + if (var.typeScope() && var.typeScope()->numConstructors > 0) + continue; + + if (diagVars.count(&var) == 0) + uninitVarError(var.nameToken(), false, FunctionType::eConstructor, var.scope()->className, var.name(), false, false, true); + } + } } } @@ -1118,17 +1169,22 @@ void CheckClass::noExplicitConstructorError(const Token *tok, const std::string reportError(tok, Severity::style, "noExplicitConstructor", "$symbol:" + classname + '\n' + message + '\n' + verbose, CWE398, Certainty::normal); } -void CheckClass::uninitVarError(const Token *tok, bool isprivate, FunctionType functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive) +void CheckClass::uninitVarError(const Token *tok, bool isprivate, FunctionType functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive, bool noCtor) { - std::string ctor; - if (functionType == FunctionType::eCopyConstructor) - ctor = "copy "; - else if (functionType == FunctionType::eMoveConstructor) - ctor = "move "; - std::string message("Member variable '$symbol' is not initialized in the " + ctor + "constructor."); + std::string message("Member variable '$symbol' "); + if (noCtor) + message += "has no initializer."; + else { + message += "is not initialized in the "; + if (functionType == FunctionType::eCopyConstructor) + message += "copy "; + else if (functionType == FunctionType::eMoveConstructor) + message += "move "; + message += "constructor."; + } if (derived) message += " Maybe it should be initialized directly in the class " + classname + "?"; - std::string id = std::string("uninit") + (derived ? "Derived" : "") + "MemberVar" + (isprivate ? "Private" : ""); + std::string id = std::string("uninit") + (derived ? "Derived" : "") + "MemberVar" + (isprivate ? "Private" : "") + (noCtor ? "NoCtor" : ""); const std::string verbose {message + " Member variables of native types, pointers, or references are left uninitialized when the class is instantiated. That may cause bugs or undefined behavior."}; reportError(tok, Severity::warning, id, "$symbol:" + classname + "::" + varname + '\n' + message + '\n' + verbose, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); } @@ -1872,12 +1928,12 @@ CheckClass::Bool CheckClass::isInverted(const Token *tok, const Token *rhs) || (Token::simpleMatch(itr->astOperand2(), "this") && Token::simpleMatch(itr->astOperand1(), "&") && Token::simpleMatch(itr->astOperand1()->next(), rhs->str().c_str(), rhs->str().size())))) { //Do nothing } else { - return Bool::BAILOUT; + return Bool::Bailout; } } if (res) - return Bool::TRUE; - return Bool::FALSE; + return Bool::True; + return Bool::False; } const Token * CheckClass::getIfStmtBodyStart(const Token *tok, const Token *rhs) @@ -1885,11 +1941,11 @@ const Token * CheckClass::getIfStmtBodyStart(const Token *tok, const Token *rhs) const Token *top = tok->astTop(); if (Token::simpleMatch(top->link(), ") {")) { switch (isInverted(tok->astParent(), rhs)) { - case Bool::BAILOUT: + case Bool::Bailout: return nullptr; - case Bool::TRUE: + case Bool::True: return top->link()->next(); - case Bool::FALSE: + case Bool::False: return top->link()->linkAt(1); } } @@ -2513,7 +2569,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member return false; if (Token::Match(tok1->previous(), "( this . * %var% )")) // call using ptr to member function TODO: check constness return false; - if (Token::simpleMatch(tok1->astParent(), "*") && tok1->astParent()->astParent() && tok1->astParent()->astParent()->isIncDecOp()) + if (Token::simpleMatch(tok1->astParent(), "*")) return false; } @@ -2545,8 +2601,10 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member } } } else if (lhs->str() == ":" && lhs->astParent() && lhs->astParent()->str() == "(") { // range-based for-loop (C++11) - // TODO: We could additionally check what is done with the elements to avoid false negatives. Here we just rely on "const" keyword being used. - if (lhs->astParent()->strAt(1) != "const") + const Variable* loopVar = lhs->astOperand1()->variable(); + if (!loopVar || !loopVar->valueType()) + return false; + if (!loopVar->valueType()->isConst(loopVar->valueType()->pointer)) return false; } else { if (lhs->isAssignmentOp()) { @@ -2748,15 +2806,17 @@ namespace { // avoid one-definition-rule violation void CheckClass::initializerListOrder() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("initializerList")) - return; + if (!mSettings->isPremiumEnabled("initializerList")) { + if (!mSettings->severity.isEnabled(Severity::style)) + return; - // This check is not inconclusive. However it only determines if the initialization - // order is incorrect. It does not determine if being out of order causes - // a real error. Out of order is not necessarily an error but you can never - // have an error if the list is in order so this enforces defensive programming. - if (!mSettings->certainty.isEnabled(Certainty::inconclusive)) - return; + // This check is not inconclusive. However it only determines if the initialization + // order is incorrect. It does not determine if being out of order causes + // a real error. Out of order is not necessarily an error but you can never + // have an error if the list is in order so this enforces defensive programming. + if (!mSettings->certainty.isEnabled(Certainty::inconclusive)) + return; + } logChecker("CheckClass::initializerListOrder"); // style,inconclusive @@ -3123,6 +3183,8 @@ static std::vector getDuplInheritedMemberFunctionsRecursive( continue; if (classFuncIt.tokenDef->isExpandedMacro()) continue; + if (classFuncIt.templateDef) + continue; for (const Function& parentClassFuncIt : parentClassIt.type->classScope->functionList) { if (classFuncIt.name() == parentClassFuncIt.name() && (parentClassFuncIt.access != AccessControl::Private || !skipPrivate) && @@ -3265,6 +3327,8 @@ void CheckClass::checkOverride() continue; if (func.tokenDef->isExpandedMacro()) continue; + if (func.templateDef) + continue; const Function *baseFunc = func.getOverriddenFunction(); if (baseFunc) overrideError(baseFunc, &func); diff --git a/lib/checkclass.h b/lib/checkclass.h index 130f6ffd781..2fb1862dad1 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -125,7 +125,7 @@ class CPPCHECKLIB CheckClass : public Check { /** @brief Check that the override keyword is used when overriding virtual functions */ void checkOverride(); - /** @brief Check that the overriden function is not identical to the base function */ + /** @brief Check that the overridden function is not identical to the base function */ void checkUselessOverride(); /** @brief Check that large members are returned by reference from getter function */ @@ -138,7 +138,7 @@ class CPPCHECKLIB CheckClass : public Check { void checkUnsafeClassRefMember(); /** @brief Parse current TU and extract file info */ - Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& currentConfig) const override; + Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings& /*settings*/, const std::string& currentConfig) const override; Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; @@ -155,7 +155,7 @@ class CPPCHECKLIB CheckClass : public Check { void noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); void noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); void noDestructorError(const Scope *scope, bool isdefault, const Token *alloc); - void uninitVarError(const Token *tok, bool isprivate, FunctionType functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive); + void uninitVarError(const Token *tok, bool isprivate, FunctionType functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive, bool noCtor = false); void uninitVarError(const Token *tok, const std::string &classname, const std::string &varname); void missingMemberCopyError(const Token *tok, FunctionType functionType, const std::string& classname, const std::string& varname); void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive); @@ -228,7 +228,7 @@ class CPPCHECKLIB CheckClass : public Check { bool hasAllocation(const Function *func, const Scope* scope, const Token *start, const Token *end) const; bool hasAllocationInIfScope(const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const; static bool hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart); - enum class Bool : std::uint8_t { TRUE, FALSE, BAILOUT }; + enum class Bool : std::uint8_t { True, False, Bailout }; static Bool isInverted(const Token *tok, const Token *rhs); static const Token * getIfStmtBodyStart(const Token *tok, const Token *rhs); @@ -254,6 +254,10 @@ class CPPCHECKLIB CheckClass : public Check { bool init{}; }; + static void handleUnionMembers(std::vector& usageList); + + bool isInitialized(const Usage& usage, FunctionType funcType) const; + static bool isBaseClassMutableMemberFunc(const Token *tok, const Scope *scope); /** diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index dd797e19112..cec3293ad27 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,11 +52,6 @@ static const CWE CWE571(571U); // Expression is Always True //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckCondition instance; -} - bool CheckCondition::diag(const Token* tok, bool insert) { if (!tok) @@ -602,7 +597,7 @@ void CheckCondition::oppositeElseIfConditionError(const Token *ifCond, const Tok //--------------------------------------------------------------------------- // - Opposite inner conditions => always false -// - (TODO) Same/Overlapping inner condition => always true +// - Same/Overlapping inner condition => always true // - same condition after early exit => always false //--------------------------------------------------------------------------- @@ -619,6 +614,8 @@ static bool isNonConstFunctionCall(const Token *ftok, const Library &library) return false; if (ftok->function() && ftok->function()->isConst()) return false; + if (ftok->isControlFlowKeyword()) + return false; return true; } @@ -682,7 +679,7 @@ void CheckCondition::multiCondition2() if (!nonlocal && var) { if (!(var->isLocal() || var->isArgument())) nonlocal = true; - else if ((var->isPointer() || var->isReference()) && !Token::Match(cond->astParent(), "%oror%|&&|!")) + else if ((var->isPointer() || var->isReference() || var->isArray()) && !Token::Match(cond->astParent(), "%oror%|&&|!")) // TODO: if var is pointer check what it points at nonlocal = true; } @@ -739,7 +736,7 @@ void CheckCondition::multiCondition2() // Condition.. const Token *cond2 = tok->str() == "if" ? condStartToken->astOperand2() : condStartToken->astOperand1(); - const bool isReturnVar = (tok->str() == "return" && (!Token::Match(cond2, "%cop%") || (cond2 && cond2->isUnaryOp("!")))); + const bool isReturnVar = (tok->str() == "return" && (!Token::Match(cond2, "%cop%") || cond2->isUnaryOp("!") || cond2->isUnaryOp("*"))); ErrorPath errorPath; @@ -757,6 +754,8 @@ void CheckCondition::multiCondition2() oppositeInnerConditionError(firstCondition, cond2, errorPath); } else if (!isReturnVar && isSameExpression(true, firstCondition, cond2, *mSettings, true, true, &errorPath)) { identicalInnerConditionError(firstCondition, cond2, errorPath); + } else if (!isReturnVar && isOverlappingCond(cond2, firstCondition, true)) { + overlappingInnerConditionError(firstCondition, cond2, errorPath); } } return ChildrenToVisit::none; @@ -877,6 +876,21 @@ void CheckCondition::oppositeInnerConditionError(const Token *tok1, const Token* reportError(std::move(errorPath), Severity::warning, "oppositeInnerCondition", msg, CWE398, Certainty::normal); } +void CheckCondition::overlappingInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath) +{ + if (diag(tok1, tok2)) + return; + const std::string s1(tok1 ? tok1->expressionString() : "x"); + const std::string s2(tok2 ? tok2->expressionString() : "x"); + const std::string innerSmt = innerSmtString(tok2); + errorPath.emplace_back(tok1, "outer condition: " + s1); + errorPath.emplace_back(tok2, "overlapping inner condition: " + s2); + + const std::string msg("Overlapping inner '" + innerSmt + "' condition is always true.\n" + "Overlapping inner '" + innerSmt + "' condition is always true (outer condition is '" + s1 + "' and inner condition is '" + s2 + "')."); + reportError(std::move(errorPath), Severity::warning, "overlappingInnerCondition", msg, CWE398, Certainty::normal); +} + void CheckCondition::identicalInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath) { if (diag(tok1, tok2)) @@ -1502,10 +1516,11 @@ void CheckCondition::clarifyConditionError(const Token *tok, bool assign, bool b void CheckCondition::alwaysTrueFalse() { - if (!mSettings->severity.isEnabled(Severity::style) && - !mSettings->isPremiumEnabled("alwaysTrue") && - !mSettings->isPremiumEnabled("alwaysFalse") && - !mSettings->isPremiumEnabled("knownConditionTrueFalse")) + const bool pedantic = mSettings->isPremiumEnabled("alwaysTrue") || + mSettings->isPremiumEnabled("alwaysFalse") || + mSettings->isPremiumEnabled("knownConditionTrueFalse"); + + if (!pedantic && !mSettings->severity.isEnabled(Severity::style)) return; logChecker("CheckCondition::alwaysTrueFalse"); // style @@ -1521,11 +1536,6 @@ void CheckCondition::alwaysTrueFalse() } if (!tok->hasKnownIntValue()) continue; - if (Token::Match(tok->previous(), "%name% (") && tok->previous()->function()) { - const Function* f = tok->previous()->function(); - if (f->functionScope && Token::Match(f->functionScope->bodyStart, "{ return true|false ;")) - continue; - } const Token* condition = nullptr; { // is this a condition.. @@ -1545,6 +1555,8 @@ void CheckCondition::alwaysTrueFalse() condition = parent->astParent()->astParent()->previous(); else if (Token::Match(tok, "%comp%")) condition = tok; + else if (tok->str() == "(" && astIsBool(parent) && Token::Match(parent, "%assign%")) + condition = tok; else continue; } @@ -1586,7 +1598,8 @@ void CheckCondition::alwaysTrueFalse() true, true)) continue; - if (isConstVarExpression(tok, [](const Token* tok) { + + if (!pedantic && isConstVarExpression(tok, [](const Token* tok) { return Token::Match(tok, "[|(|&|+|-|*|/|%|^|>>|<<") && !Token::simpleMatch(tok, "( )"); })) continue; @@ -1647,11 +1660,20 @@ void CheckCondition::alwaysTrueFalse() } } +static std::string getConditionString(const Token* condition) +{ + if (Token::simpleMatch(condition, "return")) + return "Return value"; + if (Token::simpleMatch(condition, "(") && Token::Match(condition->astParent(), "%assign%")) + return "Assigned value"; + return "Condition"; +} + void CheckCondition::alwaysTrueFalseError(const Token* tok, const Token* condition, const ValueFlow::Value* value) { const bool alwaysTrue = value && (value->intvalue != 0 || value->isImpossible()); const std::string expr = tok ? tok->expressionString() : std::string("x"); - const std::string conditionStr = (Token::simpleMatch(condition, "return") ? "Return value" : "Condition"); + const std::string conditionStr = getConditionString(condition); const std::string errmsg = conditionStr + " '" + expr + "' is always " + bool_to_string(alwaysTrue); ErrorPath errorPath = getErrorPath(tok, value, errmsg); reportError(std::move(errorPath), @@ -1960,7 +1982,7 @@ void CheckCondition::checkCompareValueOutOfTypeRange() continue; if (valueTok->getKnownIntValue() < 0 && valueTok->valueType() && valueTok->valueType()->sign != ValueType::Sign::SIGNED) continue; - if (valueTok->valueType() && valueTok->valueType()->isTypeEqual(typeTok->valueType())) + if (typeTok->isLiteral()) continue; std::uint8_t bits = 0; switch (typeTok->valueType()->type) { @@ -2000,6 +2022,8 @@ void CheckCondition::checkCompareValueOutOfTypeRange() bool result{}; const auto kiv = valueTok->getKnownIntValue(); + if (kiv == 0) + continue; // prevent overlap with TestOther::unsignedPositive/unsignedLessThanZero if (tok->str() == "==") result = false; else if (tok->str() == "!=") @@ -2056,10 +2080,10 @@ void CheckCondition::checkCompareValueOutOfTypeRange() } } -void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparison, const std::string &type, MathLib::bigint value, bool result) +void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result) { reportError( - comparison, + comparisonTok, Severity::style, "compareValueOutOfTypeRangeError", "Comparing expression of type '" + type + "' against value " + MathLib::toString(value) + ". Condition is always " + bool_to_string(result) + ".", @@ -2096,6 +2120,7 @@ void CheckCondition::getErrorMessages(ErrorLogger *errorLogger, const Settings * c.comparisonError(nullptr, "&", 6, "==", 1, false); c.duplicateConditionError(nullptr, nullptr, ErrorPath{}); c.overlappingElseIfConditionError(nullptr, 1); + c.overlappingInnerConditionError(nullptr, nullptr, ErrorPath()); c.mismatchingBitAndError(nullptr, 0xf0, nullptr, 1); c.oppositeInnerConditionError(nullptr, nullptr, ErrorPath{}); c.identicalInnerConditionError(nullptr, nullptr, ErrorPath{}); diff --git a/lib/checkcondition.h b/lib/checkcondition.h index dac3ba8d0de..2ea20158b11 100644 --- a/lib/checkcondition.h +++ b/lib/checkcondition.h @@ -84,7 +84,7 @@ class CPPCHECKLIB CheckCondition : public Check { /** * multiconditions #2 * - Opposite inner conditions => always false - * - (TODO) Same/Overlapping inner condition => always true + * - Same/Overlapping inner condition => always true * - same condition after early exit => always false **/ void multiCondition2(); @@ -130,6 +130,7 @@ class CPPCHECKLIB CheckCondition : public Check { bool result); void duplicateConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath); void overlappingElseIfConditionError(const Token *tok, nonneg int line1); + void overlappingInnerConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath); void oppositeElseIfConditionError(const Token *ifCond, const Token *elseIfCond, ErrorPath errorPath); void oppositeInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath); @@ -155,7 +156,7 @@ class CPPCHECKLIB CheckCondition : public Check { void assignmentInCondition(const Token *eq); void checkCompareValueOutOfTypeRange(); - void compareValueOutOfTypeRangeError(const Token *comparison, const std::string &type, MathLib::bigint value, bool result); + void compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; diff --git a/lib/checkers.cpp b/lib/checkers.cpp index a84da1bc986..f7d7f913da6 100644 --- a/lib/checkers.cpp +++ b/lib/checkers.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ namespace checkers { {"CheckBufferOverrun::analyseWholeProgram",""}, {"CheckBufferOverrun::argumentSize","warning"}, {"CheckBufferOverrun::arrayIndex",""}, - {"CheckBufferOverrun::arrayIndexThenCheck",""}, + {"CheckBufferOverrun::arrayIndexThenCheck","style"}, {"CheckBufferOverrun::bufferOverflow",""}, {"CheckBufferOverrun::negativeArraySize",""}, {"CheckBufferOverrun::objectIndex",""}, @@ -211,797 +211,6 @@ namespace checkers { {"CheckVaarg::va_start_argument",""}, }; - const std::map premiumCheckers{ - {"Autosar: A0-1-3",""}, - {"Autosar: A0-1-4",""}, - {"Autosar: A0-1-5",""}, - {"Autosar: A0-1-6",""}, - {"Autosar: A0-4-2",""}, - {"Autosar: A0-4-4",""}, - {"Autosar: A10-1-1",""}, - {"Autosar: A11-0-2",""}, - {"Autosar: A11-3-1",""}, - {"Autosar: A13-2-1",""}, - {"Autosar: A13-2-3",""}, - {"Autosar: A13-5-2",""}, - {"Autosar: A13-5-5",""}, - {"Autosar: A15-1-2",""}, - {"Autosar: A15-3-5",""}, - {"Autosar: A16-6-1",""}, - {"Autosar: A16-7-1",""}, - {"Autosar: A18-0-3",""}, - {"Autosar: A18-1-1",""}, - {"Autosar: A18-1-2",""}, - {"Autosar: A18-1-3",""}, - {"Autosar: A18-5-1",""}, - {"Autosar: A18-9-1",""}, - {"Autosar: A2-11-1",""}, - {"Autosar: A2-13-1",""}, - {"Autosar: A2-13-3",""}, - {"Autosar: A2-13-5",""}, - {"Autosar: A2-5-2",""}, - {"Autosar: A2-7-1",""}, - {"Autosar: A20-8-2","warning"}, - {"Autosar: A20-8-3","warning"}, - {"Autosar: A20-8-4",""}, - {"Autosar: A20-8-5",""}, - {"Autosar: A20-8-6",""}, - {"Autosar: A21-8-1","warning"}, - {"Autosar: A23-0-1",""}, - {"Autosar: A25-1-1","warning"}, - {"Autosar: A25-4-1","warning"}, - {"Autosar: A26-5-1",""}, - {"Autosar: A26-5-2",""}, - {"Autosar: A27-0-1","warning"}, - {"Autosar: A27-0-2",""}, - {"Autosar: A27-0-4",""}, - {"Autosar: A3-1-3",""}, - {"Autosar: A3-1-4",""}, - {"Autosar: A3-3-1",""}, - {"Autosar: A3-9-1",""}, - {"Autosar: A4-10-1",""}, - {"Autosar: A4-7-1",""}, - {"Autosar: A5-0-2",""}, - {"Autosar: A5-0-3",""}, - {"Autosar: A5-0-4",""}, - {"Autosar: A5-1-1",""}, - {"Autosar: A5-1-2",""}, - {"Autosar: A5-1-3",""}, - {"Autosar: A5-1-6",""}, - {"Autosar: A5-1-7",""}, - {"Autosar: A5-16-1",""}, - {"Autosar: A5-2-1",""}, - {"Autosar: A5-2-3",""}, - {"Autosar: A5-2-4",""}, - {"Autosar: A5-3-3",""}, - {"Autosar: A6-5-3",""}, - {"Autosar: A7-1-4",""}, - {"Autosar: A7-1-6",""}, - {"Autosar: A7-1-7",""}, - {"Autosar: A7-2-1",""}, - {"Autosar: A7-2-2",""}, - {"Autosar: A7-6-1",""}, - {"Autosar: A8-4-1",""}, - {"Autosar: A8-5-3",""}, - {"Autosar: A9-3-1",""}, - {"Cert C++: CON50-CPP",""}, - {"Cert C++: CON51-CPP",""}, - {"Cert C++: CON52-CPP",""}, - {"Cert C++: CON53-CPP",""}, - {"Cert C++: CON54-CPP",""}, - {"Cert C++: CON55-CPP",""}, - {"Cert C++: CON56-CPP",""}, - {"Cert C++: CTR50-CPP",""}, - {"Cert C++: CTR52-CPP",""}, - {"Cert C++: CTR53-CPP",""}, - {"Cert C++: CTR56-CPP",""}, - {"Cert C++: CTR57-CPP","warning"}, - {"Cert C++: CTR58-CPP","warning"}, - {"Cert C++: DCL50-CPP",""}, - {"Cert C++: DCL51-CPP",""}, - {"Cert C++: DCL52-CPP",""}, - {"Cert C++: DCL53-CPP",""}, - {"Cert C++: DCL54-CPP",""}, - {"Cert C++: DCL56-CPP",""}, - {"Cert C++: DCL58-CPP",""}, - {"Cert C++: DCL59-CPP",""}, - {"Cert C++: ERR50-CPP",""}, - {"Cert C++: ERR51-CPP",""}, - {"Cert C++: ERR52-CPP",""}, - {"Cert C++: ERR53-CPP",""}, - {"Cert C++: ERR54-CPP",""}, - {"Cert C++: ERR55-CPP",""}, - {"Cert C++: ERR56-CPP",""}, - {"Cert C++: ERR58-CPP",""}, - {"Cert C++: ERR59-CPP","warning"}, - {"Cert C++: ERR60-CPP","warning"}, - {"Cert C++: ERR61-CPP",""}, - {"Cert C++: ERR62-CPP",""}, - {"Cert C++: EXP50-CPP",""}, - {"Cert C++: EXP51-CPP",""}, - {"Cert C++: EXP54-CPP",""}, - {"Cert C++: EXP55-CPP",""}, - {"Cert C++: EXP56-CPP",""}, - {"Cert C++: EXP57-CPP",""}, - {"Cert C++: EXP58-CPP",""}, - {"Cert C++: EXP59-CPP",""}, - {"Cert C++: EXP60-CPP",""}, - {"Cert C++: FIO51-CPP",""}, - {"Cert C++: INT50-CPP",""}, - {"Cert C++: MEM51-CPP",""}, - {"Cert C++: MEM52-CPP",""}, - {"Cert C++: MEM53-CPP",""}, - {"Cert C++: MEM54-CPP",""}, - {"Cert C++: MEM55-CPP",""}, - {"Cert C++: MEM57-CPP",""}, - {"Cert C++: MSC50-CPP",""}, - {"Cert C++: MSC51-CPP",""}, - {"Cert C++: MSC53-CPP",""}, - {"Cert C++: MSC54-CPP",""}, - {"Cert C++: OOP51-CPP",""}, - {"Cert C++: OOP55-CPP",""}, - {"Cert C++: OOP56-CPP",""}, - {"Cert C++: OOP57-CPP",""}, - {"Cert C++: OOP58-CPP",""}, - {"Cert C++: STR50-CPP",""}, - {"Cert C++: STR53-CPP",""}, - {"Cert C: ARR30-C",""}, - {"Cert C: ARR32-C",""}, - {"Cert C: ARR37-C",""}, - {"Cert C: ARR38-C",""}, - {"Cert C: ARR39-C",""}, - {"Cert C: CON30-C",""}, - {"Cert C: CON31-C",""}, - {"Cert C: CON32-C",""}, - {"Cert C: CON33-C",""}, - {"Cert C: CON34-C",""}, - {"Cert C: CON35-C",""}, - {"Cert C: CON36-C",""}, - {"Cert C: CON37-C",""}, - {"Cert C: CON38-C",""}, - {"Cert C: CON39-C",""}, - {"Cert C: CON40-C",""}, - {"Cert C: CON41-C",""}, - {"Cert C: DCL03-C",""}, - {"Cert C: DCL04-C",""}, - {"Cert C: DCL05-C",""}, - {"Cert C: DCL06-C",""}, - {"Cert C: DCL20-C",""}, - {"Cert C: DCL31-C",""}, - {"Cert C: DCL36-C",""}, - {"Cert C: DCL37-C",""}, - {"Cert C: DCL38-C",""}, - {"Cert C: DCL39-C",""}, - {"Cert C: DCL40-C",""}, - {"Cert C: DCL41-C",""}, - {"Cert C: ENV30-C",""}, - {"Cert C: ENV31-C",""}, - {"Cert C: ENV32-C",""}, - {"Cert C: ENV33-C",""}, - {"Cert C: ENV34-C",""}, - {"Cert C: ERR30-C",""}, - {"Cert C: ERR32-C",""}, - {"Cert C: ERR33-C",""}, - {"Cert C: ERR34-C",""}, - {"Cert C: EXP03-C",""}, - {"Cert C: EXP05-C",""}, - {"Cert C: EXP09-C",""}, - {"Cert C: EXP13-C",""}, - {"Cert C: EXP15-C",""}, - {"Cert C: EXP19-C",""}, - {"Cert C: EXP20-C",""}, - {"Cert C: EXP30-C",""}, - {"Cert C: EXP32-C",""}, - {"Cert C: EXP34-C",""}, - {"Cert C: EXP35-C",""}, - {"Cert C: EXP36-C",""}, - {"Cert C: EXP37-C",""}, - {"Cert C: EXP39-C",""}, - {"Cert C: EXP40-C",""}, - {"Cert C: EXP42-C",""}, - {"Cert C: EXP43-C",""}, - {"Cert C: EXP44-C",""}, - {"Cert C: EXP45-C",""}, - {"Cert C: FIO30-C",""}, - {"Cert C: FIO32-C",""}, - {"Cert C: FIO34-C",""}, - {"Cert C: FIO37-C",""}, - {"Cert C: FIO38-C",""}, - {"Cert C: FIO40-C",""}, - {"Cert C: FIO41-C",""}, - {"Cert C: FIO44-C",""}, - {"Cert C: FIO45-C",""}, - {"Cert C: FLP30-C",""}, - {"Cert C: FLP36-C","portability"}, - {"Cert C: FLP37-C",""}, - {"Cert C: INT17-C",""}, - {"Cert C: INT30-C",""}, - {"Cert C: INT31-C",""}, - {"Cert C: INT32-C",""}, - {"Cert C: INT33-C",""}, - {"Cert C: INT34-C",""}, - {"Cert C: INT35-C",""}, - {"Cert C: INT36-C",""}, - {"Cert C: MEM33-C",""}, - {"Cert C: MEM35-C",""}, - {"Cert C: MEM36-C",""}, - {"Cert C: MSC30-C",""}, - {"Cert C: MSC32-C",""}, - {"Cert C: MSC33-C",""}, - {"Cert C: MSC38-C",""}, - {"Cert C: MSC39-C",""}, - {"Cert C: MSC40-C",""}, - {"Cert C: MSC41-C",""}, - {"Cert C: PRE00-C",""}, - {"Cert C: PRE01-C",""}, - {"Cert C: PRE02-C",""}, - {"Cert C: PRE04-C",""}, - {"Cert C: PRE05-C",""}, - {"Cert C: PRE06-C",""}, - {"Cert C: PRE07-C",""}, - {"Cert C: PRE08-C",""}, - {"Cert C: PRE09-C",""}, - {"Cert C: PRE10-C",""}, - {"Cert C: PRE11-C",""}, - {"Cert C: PRE12-C",""}, - {"Cert C: PRE31-C",""}, - {"Cert C: SIG30-C",""}, - {"Cert C: SIG31-C",""}, - {"Cert C: SIG34-C",""}, - {"Cert C: SIG35-C",""}, - {"Cert C: STR30-C",""}, - {"Cert C: STR31-C",""}, - {"Cert C: STR32-C",""}, - {"Cert C: STR34-C",""}, - {"Cert C: STR38-C",""}, - {"Misra C++ 2008: 3-2-3",""}, - {"Misra C++ 2008: 3-2-4",""}, - {"Misra C++ 2008: 7-5-4",""}, - {"Misra C++ 2008: M0-1-11",""}, - {"Misra C++ 2008: M0-1-12",""}, - {"Misra C++ 2008: M0-1-4",""}, - {"Misra C++ 2008: M0-1-5",""}, - {"Misra C++ 2008: M0-1-7",""}, - {"Misra C++ 2008: M0-1-8",""}, - {"Misra C++ 2008: M0-3-2",""}, - {"Misra C++ 2008: M1-0-1","portability"}, - {"Misra C++ 2008: M10-1-1",""}, - {"Misra C++ 2008: M10-1-2",""}, - {"Misra C++ 2008: M10-1-3",""}, - {"Misra C++ 2008: M10-2-1",""}, - {"Misra C++ 2008: M10-3-1",""}, - {"Misra C++ 2008: M10-3-2",""}, - {"Misra C++ 2008: M10-3-3",""}, - {"Misra C++ 2008: M11-0-1",""}, - {"Misra C++ 2008: M12-1-2",""}, - {"Misra C++ 2008: M12-8-1",""}, - {"Misra C++ 2008: M12-8-2",""}, - {"Misra C++ 2008: M14-5-1","warning"}, - {"Misra C++ 2008: M14-5-2","warning"}, - {"Misra C++ 2008: M14-5-3","warning"}, - {"Misra C++ 2008: M14-6-1","warning"}, - {"Misra C++ 2008: M14-6-2","warning"}, - {"Misra C++ 2008: M14-7-1",""}, - {"Misra C++ 2008: M14-7-2",""}, - {"Misra C++ 2008: M14-7-3",""}, - {"Misra C++ 2008: M14-8-1",""}, - {"Misra C++ 2008: M14-8-2",""}, - {"Misra C++ 2008: M15-0-3",""}, - {"Misra C++ 2008: M15-1-1",""}, - {"Misra C++ 2008: M15-1-2",""}, - {"Misra C++ 2008: M15-1-3",""}, - {"Misra C++ 2008: M15-3-2","warning"}, - {"Misra C++ 2008: M15-3-3",""}, - {"Misra C++ 2008: M15-3-4",""}, - {"Misra C++ 2008: M15-3-6",""}, - {"Misra C++ 2008: M15-3-7",""}, - {"Misra C++ 2008: M15-4-1",""}, - {"Misra C++ 2008: M15-5-2",""}, - {"Misra C++ 2008: M16-0-1",""}, - {"Misra C++ 2008: M16-0-2",""}, - {"Misra C++ 2008: M16-0-3",""}, - {"Misra C++ 2008: M16-0-4",""}, - {"Misra C++ 2008: M16-0-6",""}, - {"Misra C++ 2008: M16-0-7",""}, - {"Misra C++ 2008: M16-0-8",""}, - {"Misra C++ 2008: M16-1-1",""}, - {"Misra C++ 2008: M16-1-2",""}, - {"Misra C++ 2008: M16-2-1",""}, - {"Misra C++ 2008: M16-2-2",""}, - {"Misra C++ 2008: M16-2-3",""}, - {"Misra C++ 2008: M16-2-4",""}, - {"Misra C++ 2008: M16-2-5",""}, - {"Misra C++ 2008: M16-2-6",""}, - {"Misra C++ 2008: M16-3-1",""}, - {"Misra C++ 2008: M16-3-2",""}, - {"Misra C++ 2008: M17-0-1",""}, - {"Misra C++ 2008: M17-0-2",""}, - {"Misra C++ 2008: M17-0-3",""}, - {"Misra C++ 2008: M17-0-5",""}, - {"Misra C++ 2008: M18-0-1",""}, - {"Misra C++ 2008: M18-0-2",""}, - {"Misra C++ 2008: M18-0-3",""}, - {"Misra C++ 2008: M18-0-4",""}, - {"Misra C++ 2008: M18-0-5",""}, - {"Misra C++ 2008: M18-2-1",""}, - {"Misra C++ 2008: M18-4-1",""}, - {"Misra C++ 2008: M18-7-1",""}, - {"Misra C++ 2008: M19-3-1",""}, - {"Misra C++ 2008: M2-10-1",""}, - {"Misra C++ 2008: M2-10-3",""}, - {"Misra C++ 2008: M2-10-4",""}, - {"Misra C++ 2008: M2-10-5",""}, - {"Misra C++ 2008: M2-10-6",""}, - {"Misra C++ 2008: M2-13-2",""}, - {"Misra C++ 2008: M2-13-3",""}, - {"Misra C++ 2008: M2-13-4",""}, - {"Misra C++ 2008: M2-13-5",""}, - {"Misra C++ 2008: M2-3-1",""}, - {"Misra C++ 2008: M2-7-1",""}, - {"Misra C++ 2008: M2-7-2",""}, - {"Misra C++ 2008: M2-7-3",""}, - {"Misra C++ 2008: M27-0-1",""}, - {"Misra C++ 2008: M3-1-1",""}, - {"Misra C++ 2008: M3-1-2",""}, - {"Misra C++ 2008: M3-1-3",""}, - {"Misra C++ 2008: M3-2-1",""}, - {"Misra C++ 2008: M3-3-1",""}, - {"Misra C++ 2008: M3-3-2",""}, - {"Misra C++ 2008: M3-9-1",""}, - {"Misra C++ 2008: M3-9-2",""}, - {"Misra C++ 2008: M3-9-3",""}, - {"Misra C++ 2008: M4-10-1",""}, - {"Misra C++ 2008: M4-10-2",""}, - {"Misra C++ 2008: M4-5-1",""}, - {"Misra C++ 2008: M4-5-2",""}, - {"Misra C++ 2008: M4-5-3",""}, - {"Misra C++ 2008: M5-0-10",""}, - {"Misra C++ 2008: M5-0-11",""}, - {"Misra C++ 2008: M5-0-12",""}, - {"Misra C++ 2008: M5-0-14",""}, - {"Misra C++ 2008: M5-0-15",""}, - {"Misra C++ 2008: M5-0-2",""}, - {"Misra C++ 2008: M5-0-20",""}, - {"Misra C++ 2008: M5-0-21",""}, - {"Misra C++ 2008: M5-0-3",""}, - {"Misra C++ 2008: M5-0-4",""}, - {"Misra C++ 2008: M5-0-5",""}, - {"Misra C++ 2008: M5-0-6",""}, - {"Misra C++ 2008: M5-0-7",""}, - {"Misra C++ 2008: M5-0-8",""}, - {"Misra C++ 2008: M5-0-9",""}, - {"Misra C++ 2008: M5-14-1",""}, - {"Misra C++ 2008: M5-17-1",""}, - {"Misra C++ 2008: M5-18-1",""}, - {"Misra C++ 2008: M5-19-1",""}, - {"Misra C++ 2008: M5-2-1",""}, - {"Misra C++ 2008: M5-2-10",""}, - {"Misra C++ 2008: M5-2-11",""}, - {"Misra C++ 2008: M5-2-12",""}, - {"Misra C++ 2008: M5-2-2",""}, - {"Misra C++ 2008: M5-2-3",""}, - {"Misra C++ 2008: M5-2-5",""}, - {"Misra C++ 2008: M5-2-6",""}, - {"Misra C++ 2008: M5-2-7",""}, - {"Misra C++ 2008: M5-2-8",""}, - {"Misra C++ 2008: M5-2-9",""}, - {"Misra C++ 2008: M5-3-1",""}, - {"Misra C++ 2008: M5-3-2",""}, - {"Misra C++ 2008: M5-3-3",""}, - {"Misra C++ 2008: M6-2-1",""}, - {"Misra C++ 2008: M6-2-2",""}, - {"Misra C++ 2008: M6-2-3",""}, - {"Misra C++ 2008: M6-3-1",""}, - {"Misra C++ 2008: M6-4-1",""}, - {"Misra C++ 2008: M6-4-2",""}, - {"Misra C++ 2008: M6-4-3",""}, - {"Misra C++ 2008: M6-4-4",""}, - {"Misra C++ 2008: M6-4-5",""}, - {"Misra C++ 2008: M6-4-6",""}, - {"Misra C++ 2008: M6-4-7",""}, - {"Misra C++ 2008: M6-4-8",""}, - {"Misra C++ 2008: M6-5-1",""}, - {"Misra C++ 2008: M6-5-2",""}, - {"Misra C++ 2008: M6-5-3",""}, - {"Misra C++ 2008: M6-5-4",""}, - {"Misra C++ 2008: M6-5-5",""}, - {"Misra C++ 2008: M6-5-6",""}, - {"Misra C++ 2008: M6-6-1",""}, - {"Misra C++ 2008: M6-6-2",""}, - {"Misra C++ 2008: M6-6-3",""}, - {"Misra C++ 2008: M6-6-4",""}, - {"Misra C++ 2008: M6-6-5",""}, - {"Misra C++ 2008: M7-2-1",""}, - {"Misra C++ 2008: M7-3-1",""}, - {"Misra C++ 2008: M7-3-2",""}, - {"Misra C++ 2008: M7-3-3",""}, - {"Misra C++ 2008: M7-3-4",""}, - {"Misra C++ 2008: M7-3-5",""}, - {"Misra C++ 2008: M7-3-6",""}, - {"Misra C++ 2008: M7-4-2",""}, - {"Misra C++ 2008: M7-4-3",""}, - {"Misra C++ 2008: M7-5-3",""}, - {"Misra C++ 2008: M8-0-1",""}, - {"Misra C++ 2008: M8-3-1",""}, - {"Misra C++ 2008: M8-4-4",""}, - {"Misra C++ 2008: M8-5-2",""}, - {"Misra C++ 2008: M8-5-3",""}, - {"Misra C++ 2008: M9-3-1",""}, - {"Misra C++ 2008: M9-5-1",""}, - {"Misra C++ 2008: M9-6-2",""}, - {"Misra C++ 2008: M9-6-3",""}, - {"Misra C++ 2008: M9-6-4",""}, - {"Misra C++ 2023: 0.1.2",""}, - {"Misra C++ 2023: 0.2.1",""}, - {"Misra C++ 2023: 0.2.2",""}, - {"Misra C++ 2023: 0.2.3",""}, - {"Misra C++ 2023: 0.2.4",""}, - {"Misra C++ 2023: 10.0.1",""}, - {"Misra C++ 2023: 10.1.2",""}, - {"Misra C++ 2023: 10.2.1",""}, - {"Misra C++ 2023: 10.2.2",""}, - {"Misra C++ 2023: 10.2.3",""}, - {"Misra C++ 2023: 10.3.1",""}, - {"Misra C++ 2023: 10.4.1",""}, - {"Misra C++ 2023: 11.3.1",""}, - {"Misra C++ 2023: 11.3.2",""}, - {"Misra C++ 2023: 11.6.1",""}, - {"Misra C++ 2023: 11.6.3",""}, - {"Misra C++ 2023: 12.2.1",""}, - {"Misra C++ 2023: 12.2.2",""}, - {"Misra C++ 2023: 12.2.3",""}, - {"Misra C++ 2023: 12.3.1",""}, - {"Misra C++ 2023: 13.1.1",""}, - {"Misra C++ 2023: 13.1.2",""}, - {"Misra C++ 2023: 13.3.1",""}, - {"Misra C++ 2023: 13.3.2",""}, - {"Misra C++ 2023: 13.3.3",""}, - {"Misra C++ 2023: 13.3.4",""}, - {"Misra C++ 2023: 14.1.1",""}, - {"Misra C++ 2023: 15.0.1",""}, - {"Misra C++ 2023: 15.0.2",""}, - {"Misra C++ 2023: 15.1.2",""}, - {"Misra C++ 2023: 15.1.3",""}, - {"Misra C++ 2023: 15.1.5",""}, - {"Misra C++ 2023: 16.5.1",""}, - {"Misra C++ 2023: 16.5.2",""}, - {"Misra C++ 2023: 16.6.1",""}, - {"Misra C++ 2023: 17.8.1",""}, - {"Misra C++ 2023: 18.1.1",""}, - {"Misra C++ 2023: 18.1.2",""}, - {"Misra C++ 2023: 18.3.1",""}, - {"Misra C++ 2023: 18.3.2",""}, - {"Misra C++ 2023: 18.3.3",""}, - {"Misra C++ 2023: 18.4.1",""}, - {"Misra C++ 2023: 18.5.1",""}, - {"Misra C++ 2023: 18.5.2",""}, - {"Misra C++ 2023: 19.0.1",""}, - {"Misra C++ 2023: 19.0.2",""}, - {"Misra C++ 2023: 19.0.3",""}, - {"Misra C++ 2023: 19.0.4",""}, - {"Misra C++ 2023: 19.1.1",""}, - {"Misra C++ 2023: 19.1.2",""}, - {"Misra C++ 2023: 19.1.3",""}, - {"Misra C++ 2023: 19.2.1",""}, - {"Misra C++ 2023: 19.2.2",""}, - {"Misra C++ 2023: 19.2.3",""}, - {"Misra C++ 2023: 19.3.1",""}, - {"Misra C++ 2023: 19.3.2",""}, - {"Misra C++ 2023: 19.3.3",""}, - {"Misra C++ 2023: 19.3.4",""}, - {"Misra C++ 2023: 19.6.1",""}, - {"Misra C++ 2023: 21.10.1",""}, - {"Misra C++ 2023: 21.10.2",""}, - {"Misra C++ 2023: 21.10.3",""}, - {"Misra C++ 2023: 21.2.1",""}, - {"Misra C++ 2023: 21.2.2",""}, - {"Misra C++ 2023: 21.2.3",""}, - {"Misra C++ 2023: 21.2.4",""}, - {"Misra C++ 2023: 21.6.1",""}, - {"Misra C++ 2023: 21.6.2",""}, - {"Misra C++ 2023: 21.6.3",""}, - {"Misra C++ 2023: 21.6.4",""}, - {"Misra C++ 2023: 21.6.5",""}, - {"Misra C++ 2023: 22.3.1",""}, - {"Misra C++ 2023: 22.4.1",""}, - {"Misra C++ 2023: 23.11.1",""}, - {"Misra C++ 2023: 24.5.1",""}, - {"Misra C++ 2023: 24.5.2",""}, - {"Misra C++ 2023: 25.5.1",""}, - {"Misra C++ 2023: 25.5.2",""}, - {"Misra C++ 2023: 25.5.3",""}, - {"Misra C++ 2023: 26.3.1",""}, - {"Misra C++ 2023: 28.3.1",""}, - {"Misra C++ 2023: 28.6.1",""}, - {"Misra C++ 2023: 28.6.2",""}, - {"Misra C++ 2023: 30.0.1",""}, - {"Misra C++ 2023: 30.0.2",""}, - {"Misra C++ 2023: 4.1.1",""}, - {"Misra C++ 2023: 4.1.2",""}, - {"Misra C++ 2023: 5.0.1",""}, - {"Misra C++ 2023: 5.10.1",""}, - {"Misra C++ 2023: 5.13.1",""}, - {"Misra C++ 2023: 5.13.2",""}, - {"Misra C++ 2023: 5.13.3",""}, - {"Misra C++ 2023: 5.13.4",""}, - {"Misra C++ 2023: 5.13.5",""}, - {"Misra C++ 2023: 5.13.6",""}, - {"Misra C++ 2023: 5.13.7",""}, - {"Misra C++ 2023: 5.7.1",""}, - {"Misra C++ 2023: 5.7.2",""}, - {"Misra C++ 2023: 5.7.3",""}, - {"Misra C++ 2023: 6.0.1",""}, - {"Misra C++ 2023: 6.0.2",""}, - {"Misra C++ 2023: 6.0.3",""}, - {"Misra C++ 2023: 6.0.4",""}, - {"Misra C++ 2023: 6.2.2",""}, - {"Misra C++ 2023: 6.2.3",""}, - {"Misra C++ 2023: 6.2.4",""}, - {"Misra C++ 2023: 6.4.2",""}, - {"Misra C++ 2023: 6.4.3",""}, - {"Misra C++ 2023: 6.5.1",""}, - {"Misra C++ 2023: 6.5.2",""}, - {"Misra C++ 2023: 6.7.1",""}, - {"Misra C++ 2023: 6.7.2",""}, - {"Misra C++ 2023: 6.8.3",""}, - {"Misra C++ 2023: 6.8.4",""}, - {"Misra C++ 2023: 6.9.1",""}, - {"Misra C++ 2023: 6.9.2",""}, - {"Misra C++ 2023: 7.0.1",""}, - {"Misra C++ 2023: 7.0.2",""}, - {"Misra C++ 2023: 7.0.3",""}, - {"Misra C++ 2023: 7.0.4",""}, - {"Misra C++ 2023: 7.0.5",""}, - {"Misra C++ 2023: 7.0.6",""}, - {"Misra C++ 2023: 7.11.1",""}, - {"Misra C++ 2023: 7.11.2",""}, - {"Misra C++ 2023: 7.11.3",""}, - {"Misra C++ 2023: 8.0.1",""}, - {"Misra C++ 2023: 8.1.1",""}, - {"Misra C++ 2023: 8.1.2",""}, - {"Misra C++ 2023: 8.14.1",""}, - {"Misra C++ 2023: 8.18.2",""}, - {"Misra C++ 2023: 8.19.1",""}, - {"Misra C++ 2023: 8.2.1",""}, - {"Misra C++ 2023: 8.2.10",""}, - {"Misra C++ 2023: 8.2.11",""}, - {"Misra C++ 2023: 8.2.2",""}, - {"Misra C++ 2023: 8.2.3",""}, - {"Misra C++ 2023: 8.2.4",""}, - {"Misra C++ 2023: 8.2.5",""}, - {"Misra C++ 2023: 8.2.6",""}, - {"Misra C++ 2023: 8.2.7",""}, - {"Misra C++ 2023: 8.2.8",""}, - {"Misra C++ 2023: 8.2.9",""}, - {"Misra C++ 2023: 8.20.1",""}, - {"Misra C++ 2023: 8.3.1",""}, - {"Misra C++ 2023: 8.3.2",""}, - {"Misra C++ 2023: 9.2.1",""}, - {"Misra C++ 2023: 9.3.1",""}, - {"Misra C++ 2023: 9.4.1",""}, - {"Misra C++ 2023: 9.4.2",""}, - {"Misra C++ 2023: 9.5.1",""}, - {"Misra C++ 2023: 9.5.2",""}, - {"Misra C++ 2023: 9.6.1",""}, - {"Misra C++ 2023: 9.6.2",""}, - {"Misra C++ 2023: 9.6.3",""}, - {"Misra C++ 2023: 9.6.4",""}, - {"Misra C: 1.2",""}, - {"Misra C: 1.4",""}, - {"Misra C: 1.5",""}, - {"Misra C: 10.1",""}, - {"Misra C: 10.2",""}, - {"Misra C: 10.3",""}, - {"Misra C: 10.4",""}, - {"Misra C: 10.5",""}, - {"Misra C: 10.6",""}, - {"Misra C: 10.7",""}, - {"Misra C: 10.8",""}, - {"Misra C: 11.1",""}, - {"Misra C: 11.10",""}, - {"Misra C: 11.11",""}, - {"Misra C: 11.2",""}, - {"Misra C: 11.3",""}, - {"Misra C: 11.4",""}, - {"Misra C: 11.5",""}, - {"Misra C: 11.6",""}, - {"Misra C: 11.7",""}, - {"Misra C: 11.8",""}, - {"Misra C: 11.9",""}, - {"Misra C: 12.1",""}, - {"Misra C: 12.2",""}, - {"Misra C: 12.3",""}, - {"Misra C: 12.4",""}, - {"Misra C: 12.6",""}, - {"Misra C: 13.1",""}, - {"Misra C: 13.2",""}, - {"Misra C: 13.3",""}, - {"Misra C: 13.4",""}, - {"Misra C: 13.5",""}, - {"Misra C: 13.6",""}, - {"Misra C: 14.1",""}, - {"Misra C: 14.2",""}, - {"Misra C: 14.4",""}, - {"Misra C: 15.1",""}, - {"Misra C: 15.2",""}, - {"Misra C: 15.3",""}, - {"Misra C: 15.4",""}, - {"Misra C: 15.5",""}, - {"Misra C: 15.6",""}, - {"Misra C: 15.7",""}, - {"Misra C: 16.1",""}, - {"Misra C: 16.2",""}, - {"Misra C: 16.3",""}, - {"Misra C: 16.4",""}, - {"Misra C: 16.5",""}, - {"Misra C: 16.6",""}, - {"Misra C: 16.7",""}, - {"Misra C: 17.1",""}, - {"Misra C: 17.10",""}, - {"Misra C: 17.11",""}, - {"Misra C: 17.12",""}, - {"Misra C: 17.13",""}, - {"Misra C: 17.2",""}, - {"Misra C: 17.3",""}, - {"Misra C: 17.4",""}, - {"Misra C: 17.6",""}, - {"Misra C: 17.7",""}, - {"Misra C: 17.8",""}, - {"Misra C: 17.9",""}, - {"Misra C: 18.10",""}, - {"Misra C: 18.4",""}, - {"Misra C: 18.5",""}, - {"Misra C: 18.7",""}, - {"Misra C: 18.8",""}, - {"Misra C: 18.9",""}, - {"Misra C: 19.2",""}, - {"Misra C: 19.3",""}, - {"Misra C: 2.2",""}, - {"Misra C: 2.7",""}, - {"Misra C: 20.1",""}, - {"Misra C: 20.10",""}, - {"Misra C: 20.11",""}, - {"Misra C: 20.12",""}, - {"Misra C: 20.13",""}, - {"Misra C: 20.14",""}, - {"Misra C: 20.15",""}, - {"Misra C: 20.2",""}, - {"Misra C: 20.3",""}, - {"Misra C: 20.4",""}, - {"Misra C: 20.5",""}, - {"Misra C: 20.7",""}, - {"Misra C: 20.8",""}, - {"Misra C: 20.9",""}, - {"Misra C: 21.1",""}, - {"Misra C: 21.10",""}, - {"Misra C: 21.11",""}, - {"Misra C: 21.12",""}, - {"Misra C: 21.14",""}, - {"Misra C: 21.15",""}, - {"Misra C: 21.16",""}, - {"Misra C: 21.18",""}, - {"Misra C: 21.19",""}, - {"Misra C: 21.2",""}, - {"Misra C: 21.20",""}, - {"Misra C: 21.21",""}, - {"Misra C: 21.22",""}, - {"Misra C: 21.23",""}, - {"Misra C: 21.24",""}, - {"Misra C: 21.25","warning"}, - {"Misra C: 21.26","warning"}, - {"Misra C: 21.3",""}, - {"Misra C: 21.4",""}, - {"Misra C: 21.5",""}, - {"Misra C: 21.6",""}, - {"Misra C: 21.7",""}, - {"Misra C: 21.8",""}, - {"Misra C: 21.9",""}, - {"Misra C: 22.10",""}, - {"Misra C: 22.11",""}, - {"Misra C: 22.12",""}, - {"Misra C: 22.13",""}, - {"Misra C: 22.14",""}, - {"Misra C: 22.15",""}, - {"Misra C: 22.16","warning"}, - {"Misra C: 22.17","warning"}, - {"Misra C: 22.18","warning"}, - {"Misra C: 22.19","warning"}, - {"Misra C: 22.20",""}, - {"Misra C: 22.5",""}, - {"Misra C: 22.7",""}, - {"Misra C: 22.8",""}, - {"Misra C: 22.9",""}, - {"Misra C: 23.1",""}, - {"Misra C: 23.2",""}, - {"Misra C: 23.3",""}, - {"Misra C: 23.4",""}, - {"Misra C: 23.5",""}, - {"Misra C: 23.6",""}, - {"Misra C: 23.7",""}, - {"Misra C: 23.8",""}, - {"Misra C: 3.1",""}, - {"Misra C: 3.2",""}, - {"Misra C: 4.1",""}, - {"Misra C: 4.2",""}, - {"Misra C: 5.1",""}, - {"Misra C: 5.10",""}, - {"Misra C: 5.2",""}, - {"Misra C: 5.3",""}, - {"Misra C: 5.4",""}, - {"Misra C: 5.5",""}, - {"Misra C: 5.6",""}, - {"Misra C: 5.7",""}, - {"Misra C: 6.1",""}, - {"Misra C: 6.2",""}, - {"Misra C: 6.3",""}, - {"Misra C: 7.1",""}, - {"Misra C: 7.2",""}, - {"Misra C: 7.3",""}, - {"Misra C: 7.4","style"}, - {"Misra C: 7.5",""}, - {"Misra C: 7.6",""}, - {"Misra C: 8.1",""}, - {"Misra C: 8.10",""}, - {"Misra C: 8.11",""}, - {"Misra C: 8.12",""}, - {"Misra C: 8.14",""}, - {"Misra C: 8.15",""}, - {"Misra C: 8.16",""}, - {"Misra C: 8.17",""}, - {"Misra C: 8.18",""}, - {"Misra C: 8.19",""}, - {"Misra C: 8.2",""}, - {"Misra C: 8.3",""}, - {"Misra C: 8.4",""}, - {"Misra C: 8.5",""}, - {"Misra C: 8.6",""}, - {"Misra C: 8.7",""}, - {"Misra C: 8.8",""}, - {"Misra C: 8.9",""}, - {"Misra C: 9.2",""}, - {"Misra C: 9.3",""}, - {"Misra C: 9.4",""}, - {"Misra C: 9.5",""}, - {"Misra C: 9.6",""}, - {"Misra C: 9.7",""}, - {"Misra C: Dir 1.2",""}, - {"Misra C: Dir 4.12",""}, - {"Misra C: Dir 4.3",""}, - {"Misra C: Dir 4.4",""}, - {"Misra C: Dir 4.5",""}, - {"Misra C: Dir 4.6",""}, - {"Misra C: Dir 4.7",""}, - {"Misra C: Dir 4.9",""}, - {"PremiumCheckBufferOverrun::addressOfPointerArithmetic","warning"}, - {"PremiumCheckBufferOverrun::negativeBufferSizeCheckedNonZero","warning"}, - {"PremiumCheckHang::infiniteLoop",""}, - {"PremiumCheckHang::infiniteLoopContinue",""}, - {"PremiumCheckOther::arrayPointerComparison","style"}, - {"PremiumCheckOther::invalidPointerLiteral",""}, - {"PremiumCheckOther::knownResult","style"}, - {"PremiumCheckOther::lossOfPrecision","style"}, - {"PremiumCheckOther::pointerCast","style"}, - {"PremiumCheckOther::reassignInLoop","style"}, - {"PremiumCheckOther::unreachableCode","style"}, - {"PremiumCheckOther::useAfterFree",""}, - {"PremiumCheckStrictAlias::strictAliasCondition","warning"}, - {"PremiumCheckUninitVar::uninitmember",""}, - {"PremiumCheckUninitVar::uninitvar",""}, - {"PremiumCheckUnusedVar::unreadVariable","style"}, - {"PremiumCheckUnusedVar::unusedPrivateMember","style"}, - {"PremiumMetrics::HIS::Call",""}, - {"PremiumMetrics::HIS::Calling",""}, - {"PremiumMetrics::HIS::Comment",""}, - {"PremiumMetrics::HIS::Goto",""}, - {"PremiumMetrics::HIS::Level",""}, - {"PremiumMetrics::HIS::Param",""}, - {"PremiumMetrics::HIS::Path",""}, - {"PremiumMetrics::HIS::Stmt",""}, - {"PremiumMetrics::HIS::StmtFile",""}, - {"PremiumMetrics::HIS::VOCF",""}, - {"PremiumMetrics::HIS::return",""}, - {"PremiumMetrics::cyclomaticComplexity",""}, - }; const char Req[] = "Required"; const char Adv[] = "Advisory"; diff --git a/lib/checkers.h b/lib/checkers.h index a9329d6c08f..bda4a0320f5 100644 --- a/lib/checkers.h +++ b/lib/checkers.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +40,6 @@ enum class ReportType : std::uint8_t { namespace checkers { extern CPPCHECKLIB const std::map allCheckers; - extern CPPCHECKLIB const std::map premiumCheckers; struct CPPCHECKLIB MisraInfo { int a; diff --git a/lib/checkersidmapping.cpp b/lib/checkersidmapping.cpp index 5b0e6705c4c..e9636843853 100644 --- a/lib/checkersidmapping.cpp +++ b/lib/checkersidmapping.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ std::vector checkers::idMappingAutosar{ {"m0-1-1", "unreachableCode,duplicateBreak"}, {"m0-1-2", "unsignedLessThanZero"}, {"m0-1-3", "unusedVariable,unusedStructMember"}, - {"a0-1-1", "unreadVariable,unusedValue,redundantAssignment"}, + {"a0-1-1", "unreadVariable,redundantAssignment"}, {"m0-1-9", "redundantAssignment,redundantInitialization"}, {"m0-1-10", "unusedFunction"}, {"m0-2-1", "overlappingWriteUnion,overlappingWriteFunction"}, @@ -41,7 +41,6 @@ std::vector checkers::idMappingAutosar{ {"m5-0-17", "comparePointers"}, {"m5-0-18", "comparePointers"}, {"a5-1-4", "returnDanglingLifetime"}, - {"a5-2-2", "cstyleCast"}, {"a5-2-5", "arrayIndexOutOfBounds,arrayIndexOutOfBoundsCond,pointerOutOfBounds,pointerOutOfBoundsCond,negativeIndex,arrayIndexThenCheck,bufferAccessOutOfBounds,objectIndex,argumentSize"}, {"m5-3-4", "sizeofFunctionCall"}, {"a5-3-2", "nullPointer,nullPointerRedundantCheck,nullPointerArithmetic,nullPointerArithmeticRedundantCheck,nullPointerDefaultArg"}, @@ -99,13 +98,13 @@ std::vector checkers::idMappingCertCpp{ {"CTR51", "eraseDereference"}, {"CTR54", "comparePointers"}, {"CTR55", "containerOutOfBounds"}, - {"DCL57", "deallocThrow,exceptThrowInDestructor"}, + {"DCL57", "exceptDeallocThrow,exceptThrowInDestructor"}, {"DCL60", "ctuOneDefinitionRuleViolation"}, {"ERR57", "memleak"}, {"EXP52", "sizeofCalculation"}, {"EXP53", "uninitvar,uninitdata,uninitStructMember"}, {"EXP54", "uninitvar,danglingLifetime,danglingReference,danglingTemporaryLifetime,danglingTempReference,returnDanglingLifetime"}, - {"EXP61", "danglingLifetime,danglingReference,danglingTemporaryLifetime,danglingTempReference,returnDanglingLifetime"}, + {"EXP61", "danglingLifetime,danglingReference,danglingTemporaryLifetime,danglingTempReference,returnDanglingLifetime,deallocuse,deallocret"}, {"EXP63", "accessMoved"}, {"FIO50", "IOWithoutPositioning"}, {"MEM50", "deallocuse"}, @@ -124,7 +123,7 @@ std::vector checkers::idMappingMisraC{ {"1.1", "syntaxError"}, {"1.3", "error"}, {"2.1", "duplicateBreak,unreachableCode"}, - {"2.2", "constStatement,redundantCondition,redundantAssignment,redundantAssignInSwitch,unreadVariable"}, + {"2.2", "constStatement,redundantCondition,redundantAssignment,redundantAssignInSwitch,unreadVariable,unusedFunction"}, {"2.6", "unusedLabel"}, {"2.8", "unusedVariable"}, {"5.3", "shadowVariable"}, @@ -168,7 +167,7 @@ std::vector checkers::idMappingMisraCpp2008{ {"5-0-16", "pointerOutOfBounds"}, {"5-0-17", "comparePointers"}, {"5-0-18", "comparePointers"}, - {"5-2-4", "cstyleCast"}, + {"5-2-4", "cstyleCast,dangerousTypeCast"}, {"5-3-4", "sizeofFunctionCall"}, {"5-8-1", "shiftTooManyBits"}, {"6-6-5", "missingReturn"}, diff --git a/lib/checkersreport.cpp b/lib/checkersreport.cpp index a5135bed3f8..f2c4a84653f 100644 --- a/lib/checkersreport.cpp +++ b/lib/checkersreport.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +20,8 @@ #include "addoninfo.h" #include "checkers.h" -#include "errortypes.h" #include "settings.h" +#include "utils.h" #include #include @@ -133,12 +133,15 @@ void CheckersReport::countCheckers() ++mActiveCheckersCount; ++mAllCheckersCount; } - for (const auto& checkReq: checkers::premiumCheckers) { - if (mActiveCheckers.count(checkReq.first) > 0) - ++mActiveCheckersCount; - ++mAllCheckersCount; + for (const auto& addonInfo: mSettings.addonInfos) { + for (const auto& checkReq: addonInfo.checkers) { + if (mActiveCheckers.count(checkReq.first) > 0) + ++mActiveCheckersCount; + ++mAllCheckersCount; + } } - if (mSettings.premiumArgs.find("misra-c-") != std::string::npos || mSettings.addons.count("misra")) { + + if (mSettings.addons.count("misra")) { const bool doUnusedFunctionOnly = Settings::unusedFunctionOnly(); for (const checkers::MisraInfo& info: checkers::misraC2012Rules) { const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b); @@ -167,7 +170,7 @@ std::string CheckersReport::getReport(const std::string& criticalErrors) const // TODO: mention "information" and "debug" as source for indications of bailouts // TODO: still rephrase this - this message does not provides confidence in the results // TODO: document what a bailout is and why it is done - mention it in the upcoming security/tuning guide - // TODO: make bailouts a seperate group - need to differentiate between user bailouts (missing data like configuration/includes) and internal bailouts (e.g. limitations of ValueFlow) + // TODO: make bailouts a separate group - need to differentiate between user bailouts (missing data like configuration/includes) and internal bailouts (e.g. limitations of ValueFlow) fout << "Note: There might still have been non-critical bailouts which might lead to false negatives." << std::endl; } @@ -190,106 +193,39 @@ std::string CheckersReport::getReport(const std::string& criticalErrors) const fout << std::endl; } - const bool cppcheckPremium = mSettings.premium; - - auto reportSection = [&fout, cppcheckPremium] - (const std::string& title, - const Settings& settings, - const std::set& activeCheckers, - const std::map& premiumCheckers, - const std::string& substring) { + for (const auto& addonInfo: mSettings.addonInfos) { + if (addonInfo.checkers.empty()) + continue; fout << std::endl << std::endl; + std::string title; + if (mSettings.premium && addonInfo.name == "premiumaddon.json") + title = "Cppcheck Premium"; + else { + title = addonInfo.name; + if (endsWith(title, ".json")) + title.erase(title.rfind('.')); + } + title += " checkers"; fout << title << std::endl; fout << std::string(title.size(), '-') << std::endl; - if (!cppcheckPremium) { - fout << "Not available, Cppcheck Premium is not used" << std::endl; - return; - } - int maxCheckerSize = 0; - for (const auto& checkReq: premiumCheckers) { + + maxCheckerSize = 0; + for (const auto& checkReq: addonInfo.checkers) { const std::string& checker = checkReq.first; - if (checker.find(substring) != std::string::npos && checker.size() > maxCheckerSize) - maxCheckerSize = checker.size(); + maxCheckerSize = std::max(checker.size(), maxCheckerSize); } - for (const auto& checkReq: premiumCheckers) { + + for (const auto& checkReq: addonInfo.checkers) { const std::string& checker = checkReq.first; - if (checker.find(substring) == std::string::npos) - continue; - std::string req = checkReq.second; - bool active = cppcheckPremium && activeCheckers.count(checker) > 0; - if (substring == "::") { - if (req == "warning") - active &= settings.severity.isEnabled(Severity::warning); - else if (req == "style") - active &= settings.severity.isEnabled(Severity::style); - else if (req == "portability") - active &= settings.severity.isEnabled(Severity::portability); - else if (!req.empty()) - active = false; // FIXME: handle req - } + const bool active = mActiveCheckers.count(checkReq.first) > 0; + const std::string& req = checkReq.second; fout << (active ? "Yes " : "No ") << checker; - if (!cppcheckPremium) { - if (!req.empty()) - req = "premium," + req; - else - req = "premium"; - } - if (!req.empty()) - req = "require:" + req; - if (!active) - fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << req; + if (!active && !req.empty()) + fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << "require:" << req; fout << std::endl; } - }; - - reportSection("Premium checkers", mSettings, mActiveCheckers, checkers::premiumCheckers, "::"); - reportSection("Autosar", mSettings, mActiveCheckers, checkers::premiumCheckers, "Autosar: "); - reportSection("Cert C", mSettings, mActiveCheckers, checkers::premiumCheckers, "Cert C: "); - reportSection("Cert C++", mSettings, mActiveCheckers, checkers::premiumCheckers, "Cert C++: "); - - const int misraCVersion = getMisraCVersion(mSettings); - - if (misraCVersion == 0) { - fout << std::endl << std::endl; - fout << "Misra C" << std::endl; - fout << "-------" << std::endl; - fout << "Misra is not enabled" << std::endl; - } else { - fout << std::endl << std::endl; - fout << "Misra C " << misraCVersion << std::endl; - fout << "------------" << std::endl; - for (const checkers::MisraInfo& info: checkers::misraC2012Directives) { - const std::string directive = "Dir " + std::to_string(info.a) + "." + std::to_string(info.b); - const bool active = isMisraRuleActive(mActiveCheckers, directive); - fout << (active ? "Yes " : "No ") << "Misra C " << misraCVersion << ": " << directive; - std::string extra; - if (misraCVersion == 2012 && info.amendment >= 1) - extra = " amendment:" + std::to_string(info.amendment); - if (!extra.empty()) - fout << std::string(10 - directive.size(), ' ') << extra; - fout << '\n'; - } - for (const checkers::MisraInfo& info: checkers::misraC2012Rules) { - const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b); - const bool active = isMisraRuleActive(mActiveCheckers, rule); - fout << (active ? "Yes " : "No ") << "Misra C " << misraCVersion << ": " << rule; - std::string extra; - if (misraCVersion == 2012 && info.amendment >= 1) - extra = " amendment:" + std::to_string(info.amendment); - std::string reqs; - if (info.amendment >= 3) - reqs += ",premium"; - if (!active && !reqs.empty()) - extra += " require:" + reqs.substr(1); - if (!extra.empty()) - fout << std::string(10 - rule.size(), ' ') << extra; - fout << '\n'; - } } - reportSection("Misra C++ 2008", mSettings, mActiveCheckers, checkers::premiumCheckers, "Misra C++ 2008: "); - reportSection("Misra C++ 2023", mSettings, mActiveCheckers, checkers::premiumCheckers, "Misra C++ 2023: "); - return fout.str(); } diff --git a/lib/checkexceptionsafety.cpp b/lib/checkexceptionsafety.cpp index 36cec717d90..6da5281e80a 100644 --- a/lib/checkexceptionsafety.cpp +++ b/lib/checkexceptionsafety.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,11 +34,6 @@ //--------------------------------------------------------------------------- -// Register CheckExceptionSafety.. -namespace { - CheckExceptionSafety instance; -} - static const CWE CWE398(398U); // Indicator of Poor Code Quality static const CWE CWE703(703U); // Improper Check or Handling of Exceptional Conditions static const CWE CWE480(480U); // Use of Incorrect Operator @@ -95,7 +90,7 @@ void CheckExceptionSafety::destructorsError(const Token * const tok, const std:: void CheckExceptionSafety::deallocThrow() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("exceptDeallocThrow")) return; logChecker("CheckExceptionSafety::deallocThrow"); // warning @@ -257,7 +252,8 @@ static const Token * functionThrowsRecursive(const Function * function, std::set tok = tok->linkAt(1); // skip till start of catch clauses if (tok->str() == "throw") return tok; - if (tok->function() && Token::simpleMatch(tok->astParent(), "(")) { + if (tok->function() && (Token::simpleMatch(tok->astParent(), "(") || + (Token::simpleMatch(tok->astParent(), ".") && Token::simpleMatch(tok->astParent()->astParent(), "(")))) { const Function * called = tok->function(); // check if called function has an exception specification if (called->isThrow() && called->throwArg) diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 1ab21eacfd2..733b868814e 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,12 +44,6 @@ //--------------------------------------------------------------------------- - -// Register this check class (by creating a static instance of it) -namespace { - CheckFunctions instance; -} - static const CWE CWE252(252U); // Unchecked Return Value static const CWE CWE477(477U); // Use of Obsolete Functions static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior @@ -153,7 +147,7 @@ void CheckFunctions::invalidFunctionUsage() // Is non-null terminated local variable of type char (e.g. char buf[] = {'x'};) ? if (variable && variable->isLocal() && valueType && (valueType->type == ValueType::Type::CHAR || valueType->type == ValueType::Type::WCHAR_T) - && !isVariablesChanged(variable->declEndToken(), functionToken, 0 /*indirect*/, { variable }, *mSettings)) { + && !isVariablesChanged(variable->declEndToken(), functionToken, valueType->pointer, { variable }, *mSettings)) { const Token* varTok = variable->declEndToken(); MathLib::bigint count = -1; // Find out explicitly set count, e.g.: char buf[3] = {...}. Variable 'count' is set to 3 then. if (varTok && Token::simpleMatch(varTok->astOperand1(), "[")) @@ -635,6 +629,12 @@ void CheckFunctions::checkLibraryMatchFunctions() if (!tok->scope() || !tok->scope()->isExecutable()) continue; + // skip uninstantiated templates + if (tok == tok->scope()->bodyStart && tok->scope()->function && tok->scope()->function->templateDef) { + tok = tok->link(); + continue; + } + if (tok->str() == "new") insideNew = true; else if (tok->str() == ";") diff --git a/lib/checkinternal.cpp b/lib/checkinternal.cpp index f289044b102..ed39b4db96a 100644 --- a/lib/checkinternal.cpp +++ b/lib/checkinternal.cpp @@ -31,12 +31,6 @@ #include #include -// Register this check class (by creating a static instance of it). -// Disabled in release builds -namespace { - CheckInternal instance; -} - void CheckInternal::checkTokenMatchPatterns() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); diff --git a/lib/checkinternal.h b/lib/checkinternal.h index 1fc97bcb247..d62d9698b8d 100644 --- a/lib/checkinternal.h +++ b/lib/checkinternal.h @@ -22,6 +22,8 @@ #define checkinternalH //--------------------------------------------------------------------------- +#ifdef CHECK_INTERNAL + #include "check.h" #include "config.h" @@ -93,4 +95,7 @@ class CPPCHECKLIB CheckInternal : public Check { }; /// @} //--------------------------------------------------------------------------- + +#endif // CHECK_INTERNAL + #endif // checkinternalH diff --git a/lib/checkio.cpp b/lib/checkio.cpp index a250e044c9f..4161b9b224d 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,11 +45,6 @@ //--------------------------------------------------------------------------- -// Register CheckIO.. -namespace { - CheckIO instance; -} - // CVE ID used: static const CWE CWE119(119U); // Improper Restriction of Operations within the Bounds of a Memory Buffer static const CWE CWE398(398U); // Indicator of Poor Code Quality @@ -245,6 +240,28 @@ void CheckIO::checkFileUsage() } else if (tok->str() == "fclose") { fileTok = tok->tokAt(2); operation = Filepointer::Operation::CLOSE; + + // #1473 Check if fclose is in a while loop condition + if (fileTok && fileTok->isVariable()) { + const Token* loopTok = tok->astTop()->previous(); + + if (loopTok && loopTok->str() == "while") { + const Token* bodyEnd = nullptr; + const Token* bodyStart = nullptr; + + if (Token::simpleMatch(loopTok->previous(), "}") && loopTok->previous()->scope()->type == ScopeType::eDo) { // Handle do-while loops + bodyEnd = loopTok->previous(); + bodyStart = bodyEnd->link(); + } else { + bodyStart = loopTok->linkAt(1)->next(); + bodyEnd = bodyStart->link(); + } + + // Do not trigger a warning if the loop always exits or if the file is opened again in the loop. + if (!isReturnScope(bodyEnd, mSettings->library) && Token::findmatch(bodyStart, "%var% =", bodyEnd, fileTok->varId()) == nullptr) + fcloseInLoopConditionError(tok, fileTok->str()); + } + } } else if (whitelist.find(tok->str()) != whitelist.end()) { fileTok = tok->tokAt(2); if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok) @@ -392,6 +409,15 @@ void CheckIO::useClosedFileError(const Token *tok) "useClosedFile", "Used file that is not opened.", CWE910, Certainty::normal); } +void CheckIO::fcloseInLoopConditionError(const Token *tok, const std::string &varname) +{ + reportError(tok, Severity::warning, + "fcloseInLoopCondition", + "fclose() used as loop condition may skip loop body or double-close file handle.\n" + "fclose() closes '" + varname + "' each time it is evaluated. On success the loop body might never execute, on failure fclose() might be called again on the already-closed file handle.", + CWE910, Certainty::normal); +} + void CheckIO::seekOnAppendedFileError(const Token *tok) { reportError(tok, Severity::warning, @@ -674,7 +700,6 @@ void CheckIO::checkFormatString(const Token * const tok, ++i; } if (scanf_s && !skip) { - numSecure++; if (argListTok) { argListTok = argListTok->nextArgument(); } @@ -722,7 +747,7 @@ void CheckIO::checkFormatString(const Token * const tok, if (!(argInfo.isArrayOrPointer() && argInfo.element && !argInfo.typeToken->isStandardType())) invalidScanfArgTypeError_s(tok, numFormat, specifier, &argInfo); } - if (scanf_s && argInfo.typeToken) { + if (scanf_s) { numSecure++; if (argListTok) { argListTok = argListTok->nextArgument(); @@ -1540,9 +1565,10 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * arg, const Settings &settings, if (element && isStdVectorOrString()) { // isStdVectorOrString sets type token if true element = false; // not really an array element } else if (variableInfo->isEnumType()) { - if (variableInfo->type() && variableInfo->type()->classScope && variableInfo->type()->classScope->enumType) + const bool hasEnumType = variableInfo->type() && variableInfo->type()->classScope && variableInfo->type()->classScope->enumType; + if (hasEnumType && variableInfo->type()->classScope->enumType->isStandardType()) typeToken = variableInfo->type()->classScope->enumType; - else { + else if (!hasEnumType) { tempToken = new Token(tok1); tempToken->str("int"); typeToken = tempToken; @@ -2043,6 +2069,7 @@ void CheckIO::getErrorMessages(ErrorLogger *errorLogger, const Settings *setting c.readWriteOnlyFileError(nullptr); c.writeReadOnlyFileError(nullptr); c.useClosedFileError(nullptr); + c.fcloseInLoopConditionError(nullptr, "fp"); c.seekOnAppendedFileError(nullptr); c.incompatibleFileOpenError(nullptr, "tmp"); c.invalidScanfError(nullptr); diff --git a/lib/checkio.h b/lib/checkio.h index e37a942770b..b3c86da3577 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -105,6 +105,7 @@ class CPPCHECKLIB CheckIO : public Check { void readWriteOnlyFileError(const Token *tok); void writeReadOnlyFileError(const Token *tok); void useClosedFileError(const Token *tok); + void fcloseInLoopConditionError(const Token *tok, const std::string &varname); void seekOnAppendedFileError(const Token *tok); void incompatibleFileOpenError(const Token *tok, const std::string &filename); void invalidScanfError(const Token *tok); diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 83f7227091c..1c9a7283161 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,20 +34,17 @@ #include "tokenize.h" #include "tokenlist.h" #include "utils.h" +#include "vfvalue.h" #include #include #include +#include #include #include //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckLeakAutoVar instance; -} - static const CWE CWE672(672U); static const CWE CWE415(415U); @@ -191,11 +188,20 @@ static bool isVarUsedInTree(const Token *tok, nonneg int varid) { if (!tok) return false; - if (tok->varId() == varid) - return true; - if (tok->str() == "(" && Token::simpleMatch(tok->astOperand1(), "sizeof")) - return false; - return isVarUsedInTree(tok->astOperand1(), varid) || isVarUsedInTree(tok->astOperand2(), varid); + std::deque nodes{ tok }; + while (!nodes.empty()) { + const Token* node = nodes.front(); + if (node->varId() == varid) + return true; + if (node->str() != "(" || !Token::simpleMatch(node->astOperand1(), "sizeof")) { + if (node->astOperand1()) + nodes.emplace_back(node->astOperand1()); + if (node->astOperand2()) + nodes.emplace_back(node->astOperand2()); + } + nodes.pop_front(); + } + return false; } static bool isPointerReleased(const Token *startToken, const Token *endToken, nonneg int varid) @@ -285,6 +291,18 @@ static const Token* getReturnValueFromOutparamAlloc(const Token* alloc, const Se return nullptr; } +static std::vector getComparisonTokens(const Token* tok) +{ + std::vector result{ tok }; + if (tok->hasKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)) + result.push_back(tok->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)->tokvalue); + for (const Token* op : { tok->astOperand1(), tok->astOperand2() }) { + if (op && op->hasKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)) + result.push_back(op->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)->tokvalue); + } + return result; +} + bool CheckLeakAutoVar::checkScope(const Token * const startToken, VarInfo &varInfo, std::set notzero, @@ -434,7 +452,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, if (tok2->str() == ";") { break; } - if (tok2->varId()) { + if (tok2->varId() && !Token::Match(tok2->astParent(), "%comp%|!")) { varInfo.erase(tok2->varId()); } } @@ -568,53 +586,56 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, astOperand2AfterCommas = astOperand2AfterCommas->astOperand2(); // Recursively scan variable comparisons in condition - visitAstNodes(astOperand2AfterCommas, [&](const Token *tok3) { - if (!tok3) - return ChildrenToVisit::none; - if (tok3->str() == "&&" || tok3->str() == "||") { - // FIXME: handle && ! || better - return ChildrenToVisit::op1_and_op2; - } - if (tok3->str() == "(" && Token::Match(tok3->astOperand1(), "UNLIKELY|LIKELY")) { - return ChildrenToVisit::op2; - } - if (tok3->str() == "(" && tok3->previous()->isName()) { - const std::vector params = getArguments(tok3->previous()); - for (const Token *par : params) { - if (!par->isComparisonOp()) - continue; - const Token *vartok = nullptr; - if (isVarTokComparison(par, &vartok, alloc_success_conds) || - (isVarTokComparison(par, &vartok, alloc_failed_conds))) { - varInfo1.erase(vartok->varId()); - varInfo2.erase(vartok->varId()); + for (const Token* compTok : getComparisonTokens(astOperand2AfterCommas)) { + visitAstNodes(compTok, [&](const Token* tok3) { + if (!tok3) + return ChildrenToVisit::none; + if (tok3->str() == "&&" || tok3->str() == "||") { + // FIXME: handle && ! || better + return ChildrenToVisit::op1_and_op2; + } + if (tok3->str() == "(" && Token::Match(tok3->astOperand1(), "UNLIKELY|LIKELY")) { + return ChildrenToVisit::op2; + } + if (tok3->str() == "(" && tok3->previous()->isName()) { + const std::vector params = getArguments(tok3->previous()); + for (const Token* par : params) { + if (!par->isComparisonOp()) + continue; + const Token* vartok = nullptr; + if (isVarTokComparison(par, &vartok, alloc_success_conds) || + (isVarTokComparison(par, &vartok, alloc_failed_conds))) { + varInfo1.erase(vartok->varId()); + varInfo2.erase(vartok->varId()); + } } + return ChildrenToVisit::none; } - return ChildrenToVisit::none; - } - const Token *vartok = nullptr; - if (isVarTokComparison(tok3, &vartok, alloc_success_conds)) { - varInfo2.reallocToAlloc(vartok->varId()); - varInfo2.erase(vartok->varId()); - if (astIsVariableComparison(tok3, "!=", "0", &vartok) && - (notzero.find(vartok->varId()) != notzero.end())) - varInfo2.clear(); - - if (std::any_of(varInfo1.alloctype.begin(), varInfo1.alloctype.end(), [&](const std::pair& info) { - if (info.second.status != VarInfo::ALLOC) - return false; - const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, *mSettings); - return ret && vartok && ret->varId() && ret->varId() == vartok->varId(); - })) { - varInfo1.clear(); + const Token* vartok = nullptr; + if (isVarTokComparison(tok3, &vartok, alloc_success_conds)) { + varInfo2.reallocToAlloc(vartok->varId()); + varInfo2.erase(vartok->varId()); + if (astIsVariableComparison(tok3, "!=", "0", &vartok) && + (notzero.find(vartok->varId()) != notzero.end())) + varInfo2.clear(); + + if (std::any_of(varInfo1.alloctype.begin(), varInfo1.alloctype.end(), [&](const std::pair& info) { + if (info.second.status != VarInfo::ALLOC) + return false; + const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, *mSettings); + return ret && vartok && ret->varId() && ret->varId() == vartok->varId(); + })) { + varInfo1.clear(); + } } - } else if (isVarTokComparison(tok3, &vartok, alloc_failed_conds)) { - varInfo1.reallocToAlloc(vartok->varId()); - varInfo1.erase(vartok->varId()); - } - return ChildrenToVisit::none; - }); + else if (isVarTokComparison(tok3, &vartok, alloc_failed_conds)) { + varInfo1.reallocToAlloc(vartok->varId()); + varInfo1.erase(vartok->varId()); + } + return ChildrenToVisit::none; + }); + } if (!skipIfBlock && !checkScope(closingParenthesis->next(), varInfo1, notzero, recursiveCount)) { varInfo.clear(); @@ -1138,7 +1159,7 @@ void CheckLeakAutoVar::leakIfAllocated(const Token *vartok, const std::map &alloctype = varInfo.alloctype; const auto& possibleUsage = varInfo.possibleUsage; - const auto var = utils::as_const(alloctype).find(vartok->varId()); + const auto var = alloctype.find(vartok->varId()); if (var != alloctype.cend() && var->second.status == VarInfo::ALLOC) { const auto use = possibleUsage.find(vartok->varId()); if (use == possibleUsage.end()) { diff --git a/lib/checkleakautovar.h b/lib/checkleakautovar.h index b7f57d0bd5e..d7d8d390b3d 100644 --- a/lib/checkleakautovar.h +++ b/lib/checkleakautovar.h @@ -75,7 +75,7 @@ class CPPCHECKLIB VarInfo { referenced.erase(varid); } - void swap(VarInfo &other) NOEXCEPT { + void swap(VarInfo &other) noexcept { alloctype.swap(other.alloctype); possibleUsage.swap(other.possibleUsage); conditionalAlloc.swap(other.conditionalAlloc); diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index ac6329bcf86..b2f97693cd6 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +28,7 @@ #include "symboldatabase.h" #include "token.h" #include "tokenize.h" +#include "utils.h" #include #include @@ -36,14 +37,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckMemoryLeakInFunction instance1; - CheckMemoryLeakInClass instance2; - CheckMemoryLeakStructMember instance3; - CheckMemoryLeakNoVar instance4; -} - // CWE ID used: static const CWE CWE398(398U); // Indicator of Poor Code Quality static const CWE CWE401(401U); // Improper Release of Memory Before Removing Last Reference ('Memory Leak') @@ -56,6 +49,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, { // What we may have... // * var = (char *)malloc(10); + // * var = static_cast(malloc(10)); // * var = new char[10]; // * var = strdup("hello"); // * var = strndup("hello", 3); @@ -63,6 +57,8 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, tok2 = tok2->link(); tok2 = tok2 ? tok2->next() : nullptr; } + if (tok2 && tok2->isCpp() && tok2->isKeyword() && endsWith(tok2->str(), "_cast")) + tok2 = tok2->astParent()->next(); if (!tok2) return No; if (tok2->str() == "::") @@ -473,8 +469,11 @@ void CheckMemoryLeakInFunction::checkReallocUsage() // Check that another copy of the pointer wasn't saved earlier in the function if (Token::findmatch(scope->bodyStart, "%name% = %varid% ;", tok, tok->varId()) || - Token::findmatch(scope->bodyStart, "[{};] %varid% = *| %var% .| %var%| [;=]", tok, tok->varId())) + Token::findmatch(scope->bodyStart, "[{};] %varid% = *| %var%", tok, tok->varId())) continue; + if (const Token* storeTok = Token::findmatch(scope->bodyStart, "[{};] %varid% = %name% (", tok, tok->varId())) + if (storeTok->tokAt(3) != reallocTok && !mSettings->library.getAllocFuncInfo(storeTok->tokAt(3))) + continue; // Check if the argument is known to be null, which means it is not a memory leak if (arg->hasKnownIntValue() && arg->getKnownIntValue() == 0) { @@ -783,7 +782,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const vari bool deallocated = false; const Token* const end = tok->linkAt(1); for (const Token* tok2 = tok; tok2 != end; tok2 = tok2->next()) { - if (Token::Match(tok2, "[(,] &| %varid% [,)]", structid)) { + if (Token::Match(tok2, "%varid%", structid)) { /** @todo check if the function deallocates the memory */ deallocated = true; break; @@ -943,7 +942,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const vari } // Returning from function.. - else if ((tok3->scope()->type != ScopeType::eLambda || tok3->scope() == variable->scope()) && tok3->str() == "return") { + else if (((!isWithinScope(tok3, variable, ScopeType::eLambda) && !isWithinScope(tok3, variable, ScopeType::eSwitch)) || tok3->scope() == variable->scope()) && tok3->str() == "return") { // Returning from function without deallocating struct member? if (!Token::Match(tok3, "return %varid% ;", structid) && !Token::Match(tok3, "return & %varid%", structid) && @@ -1098,7 +1097,10 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope) if (allocType == No) continue; - if (tok != tok->next()->astOperand1() && !isNew) + const Token* ftok = tok->next()->astOperand1(); + while (Token::simpleMatch(ftok, "::")) + ftok = ftok->astOperand2() ? ftok->astOperand2() : ftok->astOperand1(); + if (tok != ftok && !isNew) continue; if (isReopenStandardStream(tok)) diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index cf8cc4c11a2..c9fb2274252 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -266,7 +266,7 @@ class CPPCHECKLIB CheckMemoryLeakStructMember : public Check, private CheckMemor void checkStructVariable(const Variable* variable) const; - void getErrorMessages(ErrorLogger * errorLogger, const Settings * settings) const override; + void getErrorMessages(ErrorLogger* /*errorLogger*/, const Settings* /*settings*/) const override; static std::string myName() { return "Memory leaks (struct members)"; diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 4b6a21f82f9..5bd602488b4 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,11 +47,6 @@ static const CWE CWE_NULL_POINTER_DEREFERENCE(476U); static const CWE CWE_INCORRECT_CALCULATION(682U); -// Register this check class (by creating a static instance of it) -namespace { - CheckNullPointer instance; -} - //--------------------------------------------------------------------------- static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsigned int arg) @@ -59,20 +54,13 @@ static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsig return !func || (func->argCount() >= arg && func->getArgumentVar(arg - 1) && func->getArgumentVar(arg - 1)->isPointer()); } -/** - * @brief parse a function call and extract information about variable usage - * @param tok first token - * @param var variables that the function read / write. - * @param library --library files data - * @param checkNullArg perform isnullargbad check for each argument? - */ -void CheckNullPointer::parseFunctionCall(const Token &tok, std::list &var, const Library &library, bool checkNullArg) +std::list CheckNullPointer::parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg) { if (Token::Match(&tok, "%name% ( )") || !tok.tokAt(2)) - return; + return {}; const std::vector args = getArguments(&tok); - + std::list var; for (int argnr = 1; argnr <= args.size(); ++argnr) { const Token *param = args[argnr - 1]; if ((!checkNullArg || library.isnullargbad(&tok, argnr)) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr)) @@ -87,14 +75,14 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list= args.size()) - return; + return var; // 1st parameter.. if (Token::Match(&tok, "snprintf|vsnprintf|fnprintf|vfnprintf") && args.size() > 1 && !(args[1] && args[1]->hasKnownIntValue() && args[1]->getKnownIntValue() == 0)) // Only if length (second parameter) is not zero var.push_back(args[0]); if (args[formatStringArgNr]->tokType() != Token::eString) - return; + return var; const std::string &formatString = args[formatStringArgNr]->strValue(); int argnr = formatStringArgNr + 1; const bool scan = library.formatstr_scan(&tok); @@ -116,7 +104,7 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::listprevious(); } if (ftok && ftok->previous()) { - std::list varlist; - parseFunctionCall(*ftok->previous(), varlist, settings.library, checkNullArg); + const std::list varlist = parseFunctionCall(*ftok->previous(), settings.library, checkNullArg); if (std::find(varlist.cbegin(), varlist.cend(), tok) != varlist.cend()) { return true; } @@ -194,6 +182,8 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set // declaration of function pointer if (tok->variable() && tok->variable()->nameToken() == tok) return false; + if ((tok->valueType() && tok->valueType()->pointer == 0) && !astIsIterator(tok) && !astIsSmartPointer(tok)) + return false; if (!addressOf) return true; } @@ -376,8 +366,7 @@ void CheckNullPointer::nullConstantDereference() if (var && !var->isPointer() && !var->isArray() && var->isStlStringType()) nullPointerError(tok); } else { // function call - std::list var; - parseFunctionCall(*tok, var, mSettings->library); + const std::list var = parseFunctionCall(*tok, mSettings->library); // is one of the var items a NULL pointer? for (const Token *vartok : var) { @@ -456,6 +445,8 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var reportError(tok, Severity::warning, "nullPointerOutOfResources", "Null pointer dereference", CWE_NULL_POINTER_DEREFERENCE, Certainty::normal); return; } + if (diag(tok)) + return; if (!value) { reportError(tok, Severity::error, "nullPointer", "Null pointer dereference", CWE_NULL_POINTER_DEREFERENCE, inconclusive ? Certainty::inconclusive : Certainty::normal); diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h index d28927d19e9..c02feae303e 100644 --- a/lib/checknullpointer.h +++ b/lib/checknullpointer.h @@ -26,6 +26,7 @@ #include "config.h" #include +#include #include class ErrorLogger; @@ -69,12 +70,11 @@ class CPPCHECKLIB CheckNullPointer : public Check { /** * @brief parse a function call and extract information about variable usage * @param tok first token - * @param var variables that the function read / write. * @param library --library files data + * @param checkNullArg perform isnullargbad check for each argument? + * @return list of variables that the function reads / writes. */ - static void parseFunctionCall(const Token &tok, - std::list &var, - const Library &library, bool checkNullArg = true); + static std::list parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg = true); /** @brief This constructor is used when running checks. */ CheckNullPointer(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) @@ -125,6 +125,12 @@ class CPPCHECKLIB CheckNullPointer : public Check { void arithmetic(); void pointerArithmeticError(const Token* tok, const ValueFlow::Value *value, bool inconclusive); void redundantConditionWarning(const Token* tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive); + + bool diag(const Token* tok) { + return !mDiag.emplace(tok).second; + } + + std::set mDiag; }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 979ea4ffdad..b454c4410cf 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,11 +49,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckOther instance; -} - static const CWE CWE128(128U); // Wrap-around Error static const CWE CWE131(131U); // Incorrect Calculation of Buffer Size static const CWE CWE197(197U); // Numeric Truncation Error @@ -415,7 +410,7 @@ void CheckOther::warningDangerousTypeCast() // Only valid on C++ code if (!mTokenizer->isCPP()) return; - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("cstyleCast")) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("dangerousTypeCast")) return; logChecker("CheckOther::warningDangerousTypeCast"); // warning,c++ @@ -631,7 +626,7 @@ void CheckOther::checkRedundantAssignment() [&](const Token *rhs) { if (Token::simpleMatch(rhs, "{ 0 }")) return ChildrenToVisit::none; - if (Token::Match(rhs, "%str%|%num%|%name%") && !rhs->varId()) + if (Token::Match(rhs, "%num%|%name%") && !rhs->varId()) return ChildrenToVisit::none; if (Token::Match(rhs, ":: %name%") && rhs->hasKnownIntValue()) return ChildrenToVisit::none; @@ -1163,6 +1158,8 @@ static bool isSimpleExpr(const Token* tok, const Variable* var, const Settings& return false; if (tok->isNumber() || tok->tokType() == Token::eString || tok->tokType() == Token::eChar || tok->isBoolean()) return true; + if (isNullOperand(tok)) + return true; bool needsCheck = tok->varId() > 0; if (!needsCheck) { if (tok->isArithmeticalOp()) @@ -1290,7 +1287,7 @@ void CheckOther::checkVariableScope() tok = tok->link(); // parse else if blocks.. - } else if (Token::simpleMatch(tok, "else { if (") && Token::simpleMatch(tok->linkAt(3), ") {")) { + } else if (Token::simpleMatch(tok, "else { if (") && tok->next()->isSimplifiedScope() && Token::simpleMatch(tok->linkAt(3), ") {")) { tok = tok->next(); } else if (tok->varId() == var->declarationId() || tok->str() == "goto") { reduce = false; @@ -1329,6 +1326,15 @@ static bool mayDependOn(const ValueType *other, const ValueType *original) return otherPtr > originalPtr; } +static bool isOnlyUsedInCurrentScope(const Variable* var, const Token *tok, const Scope* scope) +{ + if (tok->scope() == scope) + return true; + if (tok->scope()->type == ScopeType::eSwitch) + return false; + return !Token::findmatch(tok->scope()->bodyEnd, "%varid%", var->scope()->bodyEnd, var->declarationId()); +} + bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& used) const { const Scope* scope = tok->next()->scope(); @@ -1368,7 +1374,8 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us if (tok == forHeadEnd) forHeadEnd = nullptr; - if (loopVariable && noContinue && tok->scope() == scope && !forHeadEnd && scope->type != ScopeType::eSwitch && Token::Match(tok, "%varid% =", var->declarationId())) { // Assigned in outer scope. + if (loopVariable && noContinue && !forHeadEnd && scope->type != ScopeType::eSwitch && Token::Match(tok, "%varid% =", var->declarationId()) && + isOnlyUsedInCurrentScope(var, tok, scope)) { // Assigned in outer scope. loopVariable = false; std::pair range = tok->next()->findExpressionStartEndTokens(); if (range.first) @@ -1506,7 +1513,7 @@ void CheckOther::commaSeparatedReturnError(const Token *tok) " if (x)\n" " return a + 1,\n" " b++;\n" - "However it can be useful to use comma in macros. Cppcheck does not warn when such a " + "However it can be useful to use comma in macros. No warning is reported when such a " "macro is then used in a return statement, it is less likely such code is misunderstood.", CWE398, Certainty::normal); } @@ -1579,6 +1586,21 @@ void CheckOther::checkPassByReference() if (var->isArray() && (!var->isStlType() || Token::simpleMatch(var->nameToken()->next(), "["))) continue; + if (var->isArgument()) { + const Token *tok = var->typeStartToken(); + for (; tok; tok = tok->next()) { + if (Token::simpleMatch(tok, "(")) { + tok = tok->link(); + continue; + } + if (Token::simpleMatch(tok, ")")) + break; + } + + if (Token::simpleMatch(tok, ") ;")) + continue; + } + const bool isConst = var->isConst(); if (isConst) { passedByValueError(var, inconclusive, isRangeBasedFor); @@ -1742,9 +1764,13 @@ void CheckOther::checkConstVariable() //Is it the right side of an initialization of a non-const reference bool usedInAssignment = false; for (const Token* tok = var->nameToken(); tok != scope->bodyEnd && tok != nullptr; tok = tok->next()) { - if (Token::Match(tok, "& %var% = %varid%", var->declarationId())) { - const Variable* refvar = tok->next()->variable(); - if (refvar && !refvar->isConst() && refvar->nameToken() == tok->next()) { + if (Token::Match(tok, "%name% = %varid%", var->declarationId())) { + const Variable* refvar = tok->variable(); + if (tok->strAt(-1) == "&" && refvar && !refvar->isConst() && refvar->nameToken() == tok) { + usedInAssignment = true; + break; + } + if (!tok->valueType() || tok->valueType()->type == ValueType::Type::RECORD) { usedInAssignment = true; break; } @@ -1838,6 +1864,17 @@ static bool isCastToInteger(const Token* tok) return tok && tok->isCast() && tok->valueType() && tok->valueType()->isIntegral() && tok->valueType()->pointer == 0; } +static const Function* getEnclosingFunction(const Variable* var) +{ + if (var->isArgument()) + return var->scope()->function; + const Scope* scope = var->scope(); + while (scope && scope->type != ScopeType::eFunction) { + scope = scope->nestedIn; + } + return scope ? scope->function : nullptr; +} + void CheckOther::checkConstPointer() { if (!mSettings->severity.isEnabled(Severity::style) && @@ -1856,6 +1893,8 @@ void CheckOther::checkConstPointer() continue; if (!var->isLocal() && !var->isArgument()) continue; + if (var->isArgument() && var->scope() && var->scope()->type == ScopeType::eLambda && !Token::simpleMatch(var->scope()->bodyEnd, "} (")) + continue; const Token* const nameTok = var->nameToken(); if (tok == nameTok && var->isLocal() && !astIsRangeBasedForDecl(nameTok)) { if (var->isReference() && var->isPointer()) { @@ -1897,7 +1936,9 @@ void CheckOther::checkConstPointer() continue; if (deref != NONE) { const Token* gparent = parent->astParent(); - while (Token::simpleMatch(gparent, "[") && parent != gparent->astOperand2() && parent->str() == gparent->str()) + while (Token::simpleMatch(gparent, "[") && parent != gparent->astOperand2()) + gparent = gparent->astParent(); + while (Token::Match(gparent, "[?:]")) gparent = gparent->astParent(); if (deref == MEMBER) { if (!gparent) @@ -1907,6 +1948,10 @@ void CheckOther::checkConstPointer() continue; if (mSettings->library.isFunctionConst(parent->astOperand2())) continue; + if (parent->astOperand2()->varId()) { + if (gparent->str() == "?" && astIsLHS(parent)) + continue; + } } } if (hasIncDecPlus) { @@ -1917,7 +1962,7 @@ void CheckOther::checkConstPointer() continue; int argn = -1; if (Token::simpleMatch(gparent, "return")) { - const Function* function = gparent->scope()->function; + const Function* function = getEnclosingFunction(var); if (function && (!Function::returnsReference(function) || Function::returnsConst(function))) continue; } @@ -2652,7 +2697,7 @@ void CheckOther::checkDuplicateBranch() const std::string branch2 = tokElse->stringifyList(scope.bodyEnd->linkAt(2)); // check for duplicates - if (branch1 == branch2) { + if (branch1 == branch2 && branch1 != ";") { duplicateBranchError(scope.classDef, scope.bodyEnd->next(), ErrorPath{}); continue; } @@ -3277,10 +3322,67 @@ static bool constructorTakesReference(const Scope * const classScope) }); } +static bool isLargeObject(const Variable* var, const Settings& settings) +{ + if (!var || var->isGlobal() || !var->valueType()) + return false; + ValueType vt = *var->valueType(); + vt.reference = Reference::None; + return vt.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) > 2 * settings.platform.sizeof_pointer; +} + //--------------------------------------------------------------------------- // This check rule works for checking the "const A a = getA()" usage when getA() returns "const A &" or "A &". // In most scenarios, "const A & a = getA()" will be more efficient. //--------------------------------------------------------------------------- +static bool checkFunctionReturnsRef(const Token* tok, const Settings& settings) +{ + if (!Token::Match(tok->previous(), "%name% (")) + return false; + if (!Token::Match(tok->link(), ") )|}| ;")) // bailout for usage like "const A a = getA()+3" + return false; + const Token* dot = tok->astOperand1(); + if (Token::simpleMatch(dot, ".")) { + const Token* varTok = dot->astOperand1(); + const int indirect = varTok->valueType() ? varTok->valueType()->pointer : 0; + if (isVariableChanged(tok, tok->scope()->bodyEnd, indirect, varTok->varId(), /*globalvar*/ true, settings)) + return false; + if (isTemporary(dot, &settings.library, /*unknown*/ true)) + return false; + } + if (exprDependsOnThis(tok->previous())) + return false; + const Function* func = tok->previous()->function(); + if (func && func->tokenDef->strAt(-1) == "&") { + const Scope* fScope = func->functionScope; + if (fScope && fScope->bodyEnd && Token::Match(fScope->bodyEnd->tokAt(-3), "return %var% ;")) { + const Token* varTok = fScope->bodyEnd->tokAt(-2); + if (isLargeObject(varTok->variable(), settings)) + return true; + } + } + return false; +} + +static bool checkVariableAssignment(const Token* tok, const ValueType* vtLhs, const Settings& settings) +{ + if (!Token::Match(tok, "%var% ;")) + return false; + const Variable* var = tok->variable(); + if (!var || !isLargeObject(var, settings)) + return false; + if (!vtLhs || !vtLhs->isTypeEqual(var->valueType())) + return false; + if (findVariableChanged(tok->tokAt(2), tok->scope()->bodyEnd, /*indirect*/ 0, var->declarationId(), /*globalvar*/ false, settings)) + return false; + if (var->isLocal() || (var->isArgument() && !var->isReference())) + return true; + const Scope* scope = tok->scope(); + while (scope && scope->type != ScopeType::eFunction) + scope = scope->nestedIn; + return scope && scope->function && (!scope->functionOf || scope->function->isConst() || scope->function->isStatic()); +} + void CheckOther::checkRedundantCopy() { if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC() || !mSettings->certainty.isEnabled(Certainty::inconclusive)) @@ -3313,35 +3415,9 @@ void CheckOther::checkRedundantCopy() const Token* tok = startTok->next()->astOperand2(); if (!tok) continue; - if (!Token::Match(tok->previous(), "%name% (")) - continue; - if (!Token::Match(tok->link(), ") )|}| ;")) // bailout for usage like "const A a = getA()+3" + if (!checkFunctionReturnsRef(tok, *mSettings) && !checkVariableAssignment(tok, var->valueType(), *mSettings)) continue; - - const Token* dot = tok->astOperand1(); - if (Token::simpleMatch(dot, ".")) { - const Token* varTok = dot->astOperand1(); - const int indirect = varTok->valueType() ? varTok->valueType()->pointer : 0; - if (isVariableChanged(tok, tok->scope()->bodyEnd, indirect, varTok->varId(), /*globalvar*/ true, *mSettings)) - continue; - if (isTemporary(dot, &mSettings->library, /*unknown*/ true)) - continue; - } - if (exprDependsOnThis(tok->previous())) - continue; - - const Function* func = tok->previous()->function(); - if (func && func->tokenDef->strAt(-1) == "&") { - const Scope* fScope = func->functionScope; - if (fScope && fScope->bodyEnd && Token::Match(fScope->bodyEnd->tokAt(-3), "return %var% ;")) { - const Token* varTok = fScope->bodyEnd->tokAt(-2); - if (varTok->variable() && !varTok->variable()->isGlobal() && - (!varTok->variable()->type() || !varTok->variable()->type()->classScope || - (varTok->variable()->valueType() && - varTok->variable()->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) > 2 * mSettings->platform.sizeof_pointer))) - redundantCopyError(startTok, startTok->str()); - } - } + redundantCopyError(startTok, startTok->str()); } } @@ -3501,7 +3577,7 @@ void CheckOther::checkVarFuncNullUB() for (const Scope * scope : symbolDatabase->functionScopes) { for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { // Is NULL passed to a function? - if (Token::Match(tok,"[(,] NULL [,)]")) { + if (Token::Match(tok,"[(,] NULL )")) { // Locate function name in this function call. const Token *ftok = tok; int argnr = 1; @@ -3692,7 +3768,7 @@ void CheckOther::checkUnusedLabel() void CheckOther::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef) { - if (tok && !mSettings->severity.isEnabled(inSwitch ? Severity::warning : Severity::style)) + if (tok && !mSettings->severity.isEnabled(inSwitch ? Severity::warning : Severity::style) && !mSettings->isPremiumEnabled("unusedLabel")) return; std::string id = "unusedLabel"; @@ -3794,6 +3870,8 @@ void CheckOther::checkEvaluationOrder() continue; if (!tok->astOperand1()) continue; + if (isDesignatedInitializer(tok->astOperand1())) + continue; for (const Token *tok2 = tok;; tok2 = tok2->astParent()) { // If ast parent is a sequence point then break const Token * const parent = tok2->astParent(); @@ -3957,8 +4035,6 @@ void CheckOther::checkFuncArgNamesDifferent() std::vector definitions(function->argCount()); const Token * decl = function->argDef->next(); for (int j = 0; j < function->argCount(); ++j) { - declarations[j] = nullptr; - definitions[j] = nullptr; // get the definition const Variable * variable = function->getArgumentVar(j); if (variable) { @@ -3973,8 +4049,8 @@ void CheckOther::checkFuncArgNamesDifferent() decl = decl->nextArgument(); break; } - // skip over template - if (decl->link()) + // skip over templates and arrays + if (decl->link() && decl->str() != "(") decl = decl->link(); else if (decl->varId()) declarations[j] = decl; @@ -4005,7 +4081,9 @@ void CheckOther::checkFuncArgNamesDifferent() // check for different argument names if (style && inconclusive) { for (int j = 0; j < function->argCount(); ++j) { - if (declarations[j] && definitions[j] && declarations[j]->str() != definitions[j]->str()) + const bool warn = (declarations[j] != nullptr) != (definitions[j] != nullptr) || + (declarations[j] && definitions[j] && declarations[j]->str() != definitions[j]->str()); + if (warn) funcArgNamesDifferent(function->name(), j, declarations[j], definitions[j]); } } @@ -4016,11 +4094,12 @@ void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg const Token* declaration, const Token* definition) { std::list tokens = { declaration,definition }; - reportError(tokens, Severity::style, "funcArgNamesDifferent", + const std::string id = (declaration != nullptr) == (definition != nullptr) ? "funcArgNamesDifferent" : "funcArgNamesDifferentUnnamed"; + reportError(tokens, Severity::style, id, "$symbol:" + functionName + "\n" "Function '$symbol' argument " + std::to_string(index + 1) + " names different: declaration '" + - (declaration ? declaration->str() : std::string("A")) + "' definition '" + - (definition ? definition->str() : std::string("B")) + "'.", CWE628, Certainty::inconclusive); + (declaration ? declaration->str() : "") + "' definition '" + + (definition ? definition->str() : "") + "'.", CWE628, Certainty::inconclusive); } void CheckOther::funcArgOrderDifferent(const std::string & functionName, @@ -4086,18 +4165,21 @@ void CheckOther::checkShadowVariables() const Scope *functionScope = &scope; while (functionScope && functionScope->type != ScopeType::eFunction && functionScope->type != ScopeType::eLambda) functionScope = functionScope->nestedIn; - for (const Variable &var : scope.varlist) { - if (var.nameToken() && var.nameToken()->isExpandedMacro()) // #8903 - continue; + const auto checkVar = [&](const Variable &var) { + if (!var.nameToken()) + return; + + if (var.nameToken()->isExpandedMacro()) // #8903 + return; - if (functionScope && functionScope->type == ScopeType::eFunction && functionScope->function) { + if (!var.isArgument() && functionScope && functionScope->type == ScopeType::eFunction && functionScope->function) { const auto & argList = functionScope->function->argumentList; auto it = std::find_if(argList.cbegin(), argList.cend(), [&](const Variable& arg) { return arg.nameToken() && var.name() == arg.name(); }); if (it != argList.end()) { - shadowError(var.nameToken(), it->nameToken(), "argument"); - continue; + shadowError(var.nameToken(), "local variable", it->nameToken(), "argument"); + return; } } @@ -4105,27 +4187,43 @@ void CheckOther::checkShadowVariables() if (!shadowed) shadowed = findShadowed(scope.functionOf, var, var.nameToken()->linenr()); if (!shadowed) - continue; + return; if (scope.type == ScopeType::eFunction && scope.className == var.name()) - continue; + return; if (functionScope->functionOf && functionScope->functionOf->isClassOrStructOrUnion() && functionScope->function && (functionScope->function->isStatic() || functionScope->function->isFriend()) && shadowed->variable() && !shadowed->variable()->isLocal()) - continue; - shadowError(var.nameToken(), shadowed, (shadowed->varId() != 0) ? "variable" : "function"); - } + return; + if (var.scope() && var.scope()->function && var.scope()->function->isConstructor()) { + if (shadowed->variable() && shadowed->variable()->isMember()) + return; + if (shadowed->function() && shadowed->function()->nestedIn && + shadowed->function()->nestedIn->isClassOrStruct()) + return; + } + shadowError(var.nameToken(), var.isArgument() ? "argument" : "local variable", + shadowed, (shadowed->varId() != 0) ? + (shadowed->variable()->isMember() ? "member" : "variable") : "function"); + }; + for (const Variable &var : scope.varlist) + checkVar(var); + if (functionScope && functionScope->type == ScopeType::eFunction && functionScope->function) + for (const Variable &arg: functionScope->function->argumentList) + checkVar(arg); } } -void CheckOther::shadowError(const Token *var, const Token *shadowed, const std::string& type) +void CheckOther::shadowError(const Token *shadows, const std::string &shadowsType, + const Token *shadowed, const std::string &shadowedType) { ErrorPath errorPath; - errorPath.emplace_back(shadowed, "Shadowed declaration"); - errorPath.emplace_back(var, "Shadow variable"); - const std::string &varname = var ? var->str() : type; - const std::string Type = char(std::toupper(type[0])) + type.substr(1); - const std::string id = "shadow" + Type; - const std::string message = "$symbol:" + varname + "\nLocal variable \'$symbol\' shadows outer " + type; + errorPath.emplace_back(shadowed, "Shadowed " + shadowedType); + errorPath.emplace_back(shadows, "Shadow " + shadowsType); + const std::string &varname = shadows ? shadows->str() : shadowsType; + const std::string ShadowsType = char(std::toupper(shadowsType[0])) + shadowsType.substr(1); + const std::string ShadowedType = char(std::toupper(shadowedType[0])) + shadowedType.substr(1); + const std::string id = "shadow" + ShadowedType; + const std::string message = "$symbol:" + varname + "\n" + ShadowsType + " \'$symbol\' shadows outer " + shadowedType; reportError(std::move(errorPath), Severity::style, id.c_str(), message, CWE398, Certainty::normal); } @@ -4371,7 +4469,7 @@ void CheckOther::checkModuloOfOne() for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { if (!tok->astOperand2() || !tok->astOperand1()) continue; - if (tok->str() != "%") + if (tok->str() != "%" && tok->str() != "%=") continue; if (!tok->valueType() || !tok->valueType()->isIntegral()) continue; @@ -4807,9 +4905,10 @@ void CheckOther::getErrorMessages(ErrorLogger *errorLogger, const Settings *sett c.accessMovedError(nullptr, "v", nullptr, false); c.funcArgNamesDifferent("function", 1, nullptr, nullptr); c.redundantBitwiseOperationInSwitchError(nullptr, "varname"); - c.shadowError(nullptr, nullptr, "variable"); - c.shadowError(nullptr, nullptr, "function"); - c.shadowError(nullptr, nullptr, "argument"); + c.shadowError(nullptr, "local variable", nullptr, "variable"); + c.shadowError(nullptr, "local variable", nullptr, "argument"); + c.shadowError(nullptr, "local variable", nullptr, "function"); + c.shadowError(nullptr, "local variable", nullptr, "member"); c.knownArgumentError(nullptr, nullptr, nullptr, "x", false); c.knownPointerToBoolError(nullptr, nullptr); c.comparePointersError(nullptr, nullptr, nullptr); diff --git a/lib/checkother.h b/lib/checkother.h index 28ee25cfa76..f779141f499 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -258,7 +258,7 @@ class CPPCHECKLIB CheckOther : public Check { void accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive); void funcArgNamesDifferent(const std::string & functionName, nonneg int index, const Token* declaration, const Token* definition); void funcArgOrderDifferent(const std::string & functionName, const Token * declaration, const Token * definition, const std::vector & declarations, const std::vector & definitions); - void shadowError(const Token *var, const Token *shadowed, const std::string& type); + void shadowError(const Token *shadows, const std::string &shadowsType, const Token *shadowed, const std::string &shadowedType); void knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden); void knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value); void comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2); diff --git a/lib/checkpostfixoperator.cpp b/lib/checkpostfixoperator.cpp index c6c9ccba77b..d771177b2d2 100644 --- a/lib/checkpostfixoperator.cpp +++ b/lib/checkpostfixoperator.cpp @@ -34,12 +34,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckPostfixOperator instance; -} - - // CWE ids used static const CWE CWE398(398U); // Indicator of Poor Code Quality diff --git a/lib/checks.cpp b/lib/checks.cpp new file mode 100644 index 00000000000..169832c2745 --- /dev/null +++ b/lib/checks.cpp @@ -0,0 +1,123 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2026 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "checks.h" + +#include "check64bit.h" +#include "checkassert.h" +#include "checkautovariables.h" +#include "checkbool.h" +#include "checkbufferoverrun.h" +#include "checkclass.h" +#include "checkcondition.h" +#include "checkexceptionsafety.h" +#include "checkfunctions.h" +#include "checkinternal.h" +#include "checkio.h" +#include "checkleakautovar.h" +#include "checkmemoryleak.h" +#include "checknullpointer.h" +#include "checkother.h" +#include "checkpostfixoperator.h" +#include "checksizeof.h" +#include "checkstl.h" +#include "checkstring.h" +#include "checktype.h" +#include "checkuninitvar.h" +#include "checkunusedvar.h" +#include "checkvaarg.h" + +class CheckInstancesImpl +{ +private: +/* *INDENT-OFF* */ +#define UPI(c) std::unique_ptr m##c{new c} +/* *INDENT-ON* */ + UPI(Check64BitPortability); + UPI(CheckAssert); + UPI(CheckAutoVariables); + UPI(CheckBool); + UPI(CheckBufferOverrun); + UPI(CheckClass); + UPI(CheckCondition); + UPI(CheckExceptionSafety); + UPI(CheckFunctions); +#ifdef CHECK_INTERNAL + UPI(CheckInternal); +#endif + UPI(CheckIO); + UPI(CheckLeakAutoVar); + UPI(CheckMemoryLeakInFunction); + UPI(CheckMemoryLeakInClass); + UPI(CheckMemoryLeakStructMember); + UPI(CheckMemoryLeakNoVar); + UPI(CheckNullPointer); + UPI(CheckOther); + UPI(CheckPostfixOperator); + UPI(CheckSizeof); + UPI(CheckStl); + UPI(CheckString); + UPI(CheckType); + UPI(CheckUninitVar); + UPI(CheckUnusedVar); + UPI(CheckVaarg); +#undef UPI + +public: + const std::list& get() const + { + static std::list s_checks{ + mCheck64BitPortability.get(), + mCheckAssert.get(), + mCheckAutoVariables.get(), + mCheckBool.get(), + mCheckBufferOverrun.get(), + mCheckClass.get(), + mCheckCondition.get(), + mCheckExceptionSafety.get(), + mCheckFunctions.get(), + #ifdef CHECK_INTERNAL + mCheckInternal.get(), + #endif + mCheckIO.get(), + mCheckLeakAutoVar.get(), + mCheckMemoryLeakInFunction.get(), + mCheckMemoryLeakInClass.get(), + mCheckMemoryLeakStructMember.get(), + mCheckMemoryLeakNoVar.get(), + mCheckNullPointer.get(), + mCheckOther.get(), + mCheckPostfixOperator.get(), + mCheckSizeof.get(), + mCheckStl.get(), + mCheckString.get(), + mCheckType.get(), + mCheckUninitVar.get(), + mCheckUnusedVar.get(), + mCheckVaarg.get() + }; + + return s_checks; + } +}; + +const std::list& CheckInstances::get() +{ + static const CheckInstancesImpl s_impl; + return s_impl.get(); +} diff --git a/lib/checks.h b/lib/checks.h new file mode 100644 index 00000000000..ec4a78c2008 --- /dev/null +++ b/lib/checks.h @@ -0,0 +1,34 @@ +/* -*- C++ -*- + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2026 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef checksH +#define checksH + +#include "config.h" + +#include + +class Check; + +namespace CheckInstances +{ + /** List of registered check classes. This is used by Cppcheck to run checks and generate documentation */ + CPPCHECKLIB const std::list& get(); +}; + +#endif // checksH diff --git a/lib/checksizeof.cpp b/lib/checksizeof.cpp index 15a1caf1a8e..134cca92b7f 100644 --- a/lib/checksizeof.cpp +++ b/lib/checksizeof.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,11 +34,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckSizeof instance; -} - // CWE IDs used: static const CWE CWE467(467U); // Use of sizeof() on a Pointer Type static const CWE CWE682(682U); // Incorrect Calculation @@ -139,7 +134,7 @@ void CheckSizeof::checkSizeofForPointerSize() variable = tok; else if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-2), "%var% =")) variable = tok->linkAt(1)->tokAt(-2); - else if (tok->link() && Token::Match(tok, "> ( %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2)) && Token::Match(tok->link()->tokAt(-3), "%var% =")) + else if (tok->link() && Token::Match(tok, "> ( %name% (") && Token::Match(tok->link()->tokAt(-3), "%var% =")) variable = tok->link()->tokAt(-3); tokSize = tok->tokAt(4); tokFunc = tok->tokAt(2); diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index c4827157988..c665d72757e 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -46,11 +46,6 @@ #include #include -// Register this check class (by creating a static instance of it) -namespace { - CheckStl instance; -} - // CWE IDs used: static const CWE CWE398(398U); // Indicator of Poor Code Quality static const CWE CWE597(597U); // Use of Wrong Operator in String Comparison @@ -1193,8 +1188,7 @@ void CheckStl::invalidContainer() if (info.tok->variable()->isReference() && !isVariableDecl(info.tok) && reaches(info.tok->variable()->nameToken(), tok, nullptr)) { - if ((assignExpr && Token::Match(assignExpr->astOperand1(), "& %varid%", info.tok->varId())) || // TODO: fix AST - Token::Match(assignExpr, "& %varid% {|(", info.tok->varId())) { + if ((assignExpr && Token::Match(assignExpr->astOperand1()->previous(), "& %varid%", info.tok->varId()))) { return false; } @@ -1227,7 +1221,7 @@ void CheckStl::invalidContainer() errorPath.insert(errorPath.end(), info.errorPath.cbegin(), info.errorPath.cend()); errorPath.insert(errorPath.end(), r.errorPath.cbegin(), r.errorPath.cend()); if (v) { - invalidContainerError(info.tok, r.tok, v, std::move(errorPath)); + invalidContainerError(info.tok, v, std::move(errorPath)); } else { invalidContainerReferenceError(info.tok, r.tok, std::move(errorPath)); } @@ -1252,7 +1246,7 @@ void CheckStl::invalidContainerLoopError(const Token* tok, const Token* loopTok, reportError(std::move(errorPath), Severity::error, "invalidContainerLoop", msg, CWE664, Certainty::normal); } -void CheckStl::invalidContainerError(const Token *tok, const Token * /*contTok*/, const ValueFlow::Value *val, ErrorPath errorPath) +void CheckStl::invalidContainerError(const Token *tok, const ValueFlow::Value *val, ErrorPath errorPath) { const bool inconclusive = val ? val->isInconclusive() : false; if (val) @@ -1959,6 +1953,70 @@ static bool isLocal(const Token *tok) return var && !var->isStatic() && var->isLocal(); } +static bool isc_strCall(const Token* tok, const Library::Container* container) +{ + if (!Token::simpleMatch(tok, "(")) + return false; + const Token* dot = tok->astOperand1(); + if (!Token::simpleMatch(dot, ".")) + return false; + const Token* obj = dot->astOperand1(); + if (!obj || !obj->valueType()) + return false; + const Library::Container* objContainer = obj->valueType()->container; + if (!objContainer || !container || !objContainer->stdStringLike || (objContainer != container && !container->view)) + return false; + return Token::Match(dot->astOperand2(), "c_str|data ( )"); +} + +static bool isc_strConcat(const Token* tok) +{ + if (!tok->isBinaryOp() || !Token::simpleMatch(tok, "+")) + return false; + for (const Token* op : { tok->astOperand1(), tok->astOperand2() }) { // NOLINT(readability-use-anyofallof) + const Token* sibling = op->astSibling(); + if (!sibling->valueType()) + continue; + if (isc_strCall(op, sibling->valueType()->container)) + return true; + } + return false; +} + +static bool isc_strInPlusChain(const Token* tok, const Library::Container* container) +{ + if (!tok || !tok->valueType() || !tok->valueType()->pointer) + return false; + bool result = false; + visitAstNodes(tok, [&](const Token* tok2) { + if (Token::simpleMatch(tok2, "+")) + return ChildrenToVisit::op1_and_op2; + if (isc_strCall(tok2, container)) { + result = true; + return ChildrenToVisit::done; + } + return ChildrenToVisit::none; + }); + return result; +} + +static bool isc_strAssignment(const Token* tok) +{ + if (!Token::simpleMatch(tok, "=")) + return false; + const Token* strTok = tok->astOperand1(); + if (!strTok || !strTok->valueType()) + return false; + return isc_strCall(tok->astOperand2(), strTok->valueType()->container); +} + +static bool isc_strConstructor(const Token* tok) +{ + if (!tok->valueType() || !Token::Match(tok, "%var% (|{")) + return false; + return isc_strInPlusChain(tok->tokAt(1)->astOperand2(), tok->valueType()->container); +} + namespace { const std::set stl_string_stream = { "istringstream", "ostringstream", "stringstream", "wstringstream" @@ -2027,16 +2085,14 @@ void CheckStl::string_c_str() const Variable* var2 = tok->tokAt(2)->variable(); if (var->isPointer() && var2 && var2->isStlType(stl_string_stream)) string_c_strError(tok); + } else if (printPerformance && isc_strAssignment(tok->tokAt(1))) { + string_c_strAssignment(tok, tok->variable()->getTypeName()); } else if (Token::Match(tok->tokAt(2), "%name% (") && Token::Match(tok->linkAt(3), ") . c_str|data ( ) ;") && tok->tokAt(2)->function() && Token::Match(tok->tokAt(2)->function()->retDef, "std :: string|wstring %name%")) { const Variable* var = tok->variable(); if (var->isPointer()) string_c_strError(tok); - } else if (printPerformance && tok->tokAt(1)->astOperand2() && Token::Match(tok->tokAt(1)->astOperand2()->tokAt(-3), "%var% . c_str|data ( ) ;")) { - const Token* vartok = tok->tokAt(1)->astOperand2()->tokAt(-3); - if ((tok->variable()->isStlStringType() || tok->variable()->isStlStringViewType()) && vartok->variable() && vartok->variable()->isStlStringType()) - string_c_strAssignment(tok, tok->variable()->getTypeName()); } } else if (printPerformance && tok->function() && Token::Match(tok, "%name% ( !!)") && tok->str() != scope.className) { const auto range = c_strFuncParam.equal_range(tok->function()); @@ -2068,13 +2124,9 @@ void CheckStl::string_c_str() } } } - } else if (printPerformance && Token::Match(tok, "%var% (|{ %var% . c_str|data ( ) !!,") && - tok->variable() && (tok->variable()->isStlStringType() || tok->variable()->isStlStringViewType()) && - tok->tokAt(2)->variable() && tok->tokAt(2)->variable()->isStlStringType()) { + } else if (printPerformance && isc_strConstructor(tok)) { string_c_strConstructor(tok, tok->variable()->getTypeName()); - } else if (printPerformance && tok->next() && tok->next()->variable() && tok->next()->variable()->isStlStringType() && tok->valueType() && tok->valueType()->type == ValueType::CONTAINER && - ((Token::Match(tok->previous(), "%var% + %var% . c_str|data ( )") && tok->previous()->variable() && tok->previous()->variable()->isStlStringType()) || - (Token::Match(tok->tokAt(-5), "%var% . c_str|data ( ) + %var%") && tok->tokAt(-5)->variable() && tok->tokAt(-5)->variable()->isStlStringType()))) { + } else if (printPerformance && isc_strConcat(tok)) { string_c_strConcat(tok); } else if (printPerformance && Token::simpleMatch(tok, "<<") && tok->astOperand2() && Token::Match(tok->astOperand2()->astOperand1(), ". c_str|data ( )")) { const Token* str = tok->astOperand2()->astOperand1()->astOperand1(); @@ -2275,7 +2327,7 @@ void CheckStl::uselessCalls() !tok->tokAt(4)->astParent() && tok->next()->variable() && tok->next()->variable()->isStlType(stl_containers_with_empty_and_clear)) uselessCallsEmptyError(tok->next()); - else if (Token::Match(tok, "[{};] std :: remove|remove_if|unique (") && tok->tokAt(5)->nextArgument()) + else if (Token::Match(tok, "[{};] std :: remove|remove_if|unique (") && tok->tokAt(5)->nextArgument() && !tok->tokAt(4)->astParent()) uselessCallsRemoveError(tok->next(), tok->strAt(3)); else if (printPerformance && tok->valueType() && tok->valueType()->type == ValueType::CONTAINER) { if (Token::Match(tok, "%var% = { %var% . begin ( ) ,") && tok->varId() == tok->tokAt(3)->varId()) @@ -3446,7 +3498,7 @@ void CheckStl::getErrorMessages(ErrorLogger* errorLogger, const Settings* settin c.iteratorsError(nullptr, "container1", "container2"); c.iteratorsError(nullptr, nullptr, "container"); c.invalidContainerLoopError(nullptr, nullptr, ErrorPath{}); - c.invalidContainerError(nullptr, nullptr, nullptr, ErrorPath{}); + c.invalidContainerError(nullptr, nullptr, ErrorPath{}); c.invalidContainerReferenceError(nullptr, nullptr, ErrorPath{}); c.mismatchingContainerIteratorError(nullptr, nullptr, nullptr); c.mismatchingContainersError(nullptr, nullptr); diff --git a/lib/checkstl.h b/lib/checkstl.h index 60b9d4c7000..03a634f1ed1 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -187,7 +187,7 @@ class CPPCHECKLIB CheckStl : public Check { void sizeError(const Token* tok); void redundantIfRemoveError(const Token* tok); void invalidContainerLoopError(const Token* tok, const Token* loopTok, ErrorPath errorPath); - void invalidContainerError(const Token *tok, const Token * contTok, const ValueFlow::Value *val, ErrorPath errorPath); + void invalidContainerError(const Token *tok, const ValueFlow::Value *val, ErrorPath errorPath); void invalidContainerReferenceError(const Token* tok, const Token* contTok, ErrorPath errorPath); void uselessCallsReturnValueError(const Token* tok, const std::string& varname, const std::string& function); diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp index 64b575df72d..580597bb10d 100644 --- a/lib/checkstring.cpp +++ b/lib/checkstring.cpp @@ -36,11 +36,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckString instance; -} - // CWE ids used: static const CWE CWE570(570U); // Expression is Always False static const CWE CWE571(571U); // Expression is Always True diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 68b6580d270..eb222fbe6f5 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,11 +44,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckType instance; -} - //--------------------------------------------------------------------------- // Checking for shift by too many bits //--------------------------------------------------------------------------- @@ -383,8 +378,12 @@ void CheckType::checkLongCast() const ValueType *type = tok->astOperand1()->valueType(); if (type && checkTypeCombination(*type, *retVt, *mSettings) && type->pointer == 0U && - type->originalTypeName.empty()) - ret = tok; + type->originalTypeName.empty()) { + if (!tok->astOperand1()->hasKnownIntValue()) { + ret = tok; + } else if (!mSettings->platform.isIntValue(tok->astOperand1()->getKnownIntValue())) + ret = tok; + } } // All return statements must have problem otherwise no warning if (ret != tok) { diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 8463f6a1c8e..b88debda6f8 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,11 +50,6 @@ // CWE ids used: static const CWE CWE_USE_OF_UNINITIALIZED_VARIABLE(457U); -// Register this check class (by creating a static instance of it) -namespace { - CheckUninitVar instance; -} - //--------------------------------------------------------------------------- // get ast parent, skip possible address-of and casts @@ -304,7 +299,7 @@ static void conditionAlwaysTrueOrFalse(const Token *tok, const std::mapisName() || tok->str() == ".") { while (tok && tok->str() == ".") tok = tok->astOperand2(); - const auto it = utils::as_const(variableValue).find(tok ? tok->varId() : ~0U); + const auto it = tok ? variableValue.find(tok->varId()) : variableValue.end(); if (it != variableValue.end()) { *alwaysTrue = (it->second != 0LL); *alwaysFalse = (it->second == 0LL); @@ -330,7 +325,7 @@ static void conditionAlwaysTrueOrFalse(const Token *tok, const std::mapstr() == ".") vartok = vartok->astOperand2(); - const auto it = utils::as_const(variableValue).find(vartok ? vartok->varId() : ~0U); + const auto it = vartok ? variableValue.find(vartok->varId()) : variableValue.end(); if (it == variableValue.end()) return; @@ -383,7 +378,7 @@ static bool isVariableUsed(const Token *tok, const Variable& var) return isVariableUsed(tok->astOperand1(),var) || isVariableUsed(tok->astOperand2(),var); if (tok->varId() != var.declarationId()) return false; - if (!var.isArray()) + if (!var.isArray() && !var.isPointer()) return true; const Token *parent = tok->astParent(); @@ -784,12 +779,16 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var // standard or enum type: check if new initializes the allocated memory if (var.typeStartToken()->isStandardType() || var.typeStartToken()->isEnumType()) { // scalar new with initialization - if (Token::Match(tok->next(), "= new %type% (")) - return true; - // array new - if (Token::Match(tok->next(), "= new %type% [") && Token::simpleMatch(tok->linkAt(4), "] (")) - return true; + if (Token::Match(tok->next(), "= new ::|%type%")) { + const Token* initTok = tok->tokAt(4); + while (Token::Match(initTok, "::|%type%")) + initTok = initTok->next(); + if (Token::simpleMatch(initTok, "[")) + initTok = initTok->link()->next(); + if (Token::Match(initTok, "[({]")) + return true; + } } continue; @@ -844,7 +843,8 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var } // assume that variable is assigned - return true; + if (!Token::simpleMatch(tok->astParent(), "<<")) + return true; } } } @@ -906,7 +906,7 @@ bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Va continue; uninitvarError(errorToken, errorToken->expressionString(), alloc); } - return true; + return !Token::Match(tok->astParent(), "!|%comp%"); } // skip sizeof / offsetof if (isUnevaluated(tok)) @@ -1242,7 +1242,7 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& return nullptr; } if (alloc != NO_ALLOC) { - if (Token::Match(valueExpr->astParent(), "%comp%|%oror%|&&|?|!")) + if (Token::Match(valueExpr->astParent(), "%comp%|%oror%|&&|?|!|%")) return nullptr; if (Token::Match(valueExpr->astParent(), "%or%|&") && valueExpr->astParent()->isBinaryOp()) return nullptr; @@ -1257,8 +1257,6 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& const Token *parent = valueExpr->astParent(); while (Token::simpleMatch(parent, ",")) parent = parent->astParent(); - if (Token::simpleMatch(parent, "{")) - return valueExpr; const int use = isFunctionParUsage(valueExpr, library, pointer, alloc, indirect); return (use>0) ? valueExpr : nullptr; } @@ -1421,6 +1419,8 @@ int CheckUninitVar::isFunctionParUsage(const Token *vartok, const Library& libra const bool isnullbad = library.isnullargbad(start->previous(), argumentNumber + 1); if (indirect == 0 && pointer && !address && isnullbad && alloc == NO_ALLOC) return 1; + if (vartok->varId() == 0 && vartok->valueType()) + indirect = vartok->valueType()->pointer; bool hasIndirect = false; const bool isuninitbad = library.isuninitargbad(start->previous(), argumentNumber + 1, indirect, &hasIndirect); if (alloc != NO_ALLOC) diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index 7edaff6c241..5965de1aada 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -261,11 +261,14 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting while (Token::Match(funcname, "%name% :: %name%")) funcname = funcname->tokAt(2); + if (funcname && funcname->isName() && !funcname->function() && !tok->astParent() && Token::Match(tok, "[(,]")) // unknown type in parameter list + continue; + if (!Token::Match(funcname, "%name% [(),;]:}<>]")) continue; } - if (!funcname || funcname->isKeyword() || funcname->isStandardType() || funcname->varId() || funcname->enumerator() || funcname->type()) + if (!funcname || funcname->isKeyword() || funcname->isStandardType() || funcname->varId() || funcname->enumerator() || funcname->type() || funcname->isLiteral()) continue; // funcname ( => Assert that the end parentheses isn't followed by { @@ -385,7 +388,7 @@ bool CheckUnusedFunctions::check(const Settings& settings, ErrorLogger& errorLog if (func.filename != "+") filename = func.filename; errors.emplace_back(filename, func.fileIndex, func.lineNumber, func.column, it->first); - } else if (func.isC && !func.isStatic && !func.usedOtherFile) { + } else if (func.isC && !func.isStatic) { std::string filename; if (func.filename != "+") filename = func.filename; @@ -482,7 +485,12 @@ void CheckUnusedFunctions::analyseWholeProgram(const Settings &settings, ErrorLo } }; - AnalyzerInformation::processFilesTxt(buildDir, handler); + const std::string err = AnalyzerInformation::processFilesTxt(buildDir, handler, settings.debugainfo); + if (!err.empty()) { + const ErrorMessage errmsg({}, "", Severity::error, err, "internalError", Certainty::normal); + errorLogger.reportErr(errmsg); + return; + } for (auto decl = decls.cbegin(); decl != decls.cend(); ++decl) { const std::string &functionName = stripTemplateParameters(decl->first); @@ -497,9 +505,9 @@ void CheckUnusedFunctions::analyseWholeProgram(const Settings &settings, ErrorLo } } -void CheckUnusedFunctions::updateFunctionData(const CheckUnusedFunctions& check) +void CheckUnusedFunctions::updateFunctionData(const CheckUnusedFunctions& checkUnusedFunctions) { - for (const auto& entry : check.mFunctions) + for (const auto& entry : checkUnusedFunctions.mFunctions) { FunctionUsage &usage = mFunctions[entry.first]; if (!usage.lineNumber) { @@ -513,6 +521,6 @@ void CheckUnusedFunctions::updateFunctionData(const CheckUnusedFunctions& check) usage.usedOtherFile |= entry.second.usedOtherFile; usage.usedSameFile |= entry.second.usedSameFile; } - mFunctionDecl.insert(mFunctionDecl.cend(), check.mFunctionDecl.cbegin(), check.mFunctionDecl.cend()); - mFunctionCalls.insert(check.mFunctionCalls.cbegin(), check.mFunctionCalls.cend()); + mFunctionDecl.insert(mFunctionDecl.cend(), checkUnusedFunctions.mFunctionDecl.cbegin(), checkUnusedFunctions.mFunctionDecl.cend()); + mFunctionCalls.insert(checkUnusedFunctions.mFunctionCalls.cbegin(), checkUnusedFunctions.mFunctionCalls.cend()); } diff --git a/lib/checkunusedfunctions.h b/lib/checkunusedfunctions.h index 6f10e3446eb..20e1788cf64 100644 --- a/lib/checkunusedfunctions.h +++ b/lib/checkunusedfunctions.h @@ -58,7 +58,7 @@ class CPPCHECKLIB CheckUnusedFunctions { // Return true if an error is reported. bool check(const Settings& settings, ErrorLogger& errorLogger) const; - void updateFunctionData(const CheckUnusedFunctions& check); + void updateFunctionData(const CheckUnusedFunctions& checkUnusedFunctions); private: static void unusedFunctionError(ErrorLogger& errorLogger, diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index ddaffa0f817..9531237a208 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,11 +40,6 @@ #include //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckUnusedVar instance; -} - static const CWE CWE563(563U); // Assignment to Variable without Use ('Unused Variable') static const CWE CWE665(665U); // Improper Initialization @@ -424,6 +419,9 @@ static const Token* doAssignment(Variables &variables, const Token *tok, bool de Variables::VariableUsage *var1 = variables.find(varid1); if (var1) { + if (var1->mType == Variables::pointerArray) + variables.use(varid1, tok); + // jump behind '=' tok = tok->next(); while (!tok->isAssignmentOp()) { @@ -562,13 +560,15 @@ static const Token* doAssignment(Variables &variables, const Token *tok, bool de variables.readAll(varid2, tok); } } - } else if (var1->mType == Variables::reference) { + } else if (var1->mType == Variables::reference || var1->mType == Variables::referenceArray) { variables.alias(varid1, varid2, true); } else if (var1->mType == Variables::standard && addressOf) { variables.alias(varid1, varid2, true); } else { - if ((var2->mType == Variables::pointer || var2->mType == Variables::pointerArray) && tok->strAt(1) == "[") + if (var2->mType == Variables::pointer || var2->mType == Variables::pointerArray) { + variables.alias(varid1, varid2, true); variables.readAliases(varid2, tok); + } variables.read(varid2, tok); } @@ -733,7 +733,11 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken())) continue; const Token* defValTok = i->nameToken()->next(); - if (Token::Match(i->nameToken()->previous(), "* %var% ) (")) // function pointer. Jump behind parameter list. + if (Token::Match(i->nameToken()->previous(), "& %var% )")) + defValTok = defValTok->next(); + while (defValTok && defValTok->str() == "[") + defValTok = defValTok->link()->next(); + if (Token::simpleMatch(defValTok, ") (")) defValTok = defValTok->linkAt(1)->next(); for (; defValTok; defValTok = defValTok->next()) { if (defValTok->str() == "[") @@ -1198,6 +1202,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() const Token *nextStructuredBindingTok = nullptr; std::vector> unusedStructuredBindingTokens; size_t structuredBindingTokCount = 0; + std::set diagUnreadVariable; // prevent duplicate warnings for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { if (nextStructuredBindingTok) { @@ -1351,6 +1356,20 @@ void CheckUnusedVar::checkFunctionVariableUsage() if (tok->previous() && tok->previous()->variable() && tok->previous()->variable()->nameToken()->scope()->type == ScopeType::eUnion) continue; + if (const ValueType *vt = expr->valueType()) { + if (vt->type == ValueType::RECORD && + !vt->pointer && + vt->typeScope && + vt->typeScope->definedType && + !symbolDatabase->isRecordTypeWithoutSideEffects(vt->typeScope->definedType)) + continue; + + if (vt->type == ValueType::SMART_POINTER && + vt->smartPointerType && + !symbolDatabase->isRecordTypeWithoutSideEffects(vt->smartPointerType)) + continue; + } + FwdAnalysis fwdAnalysis(*mSettings); const Token* scopeEnd = ValueFlow::getEndOfExprScope(expr, scope, /*smallest*/ false); if (fwdAnalysis.unusedValue(expr, start, scopeEnd)) { @@ -1366,8 +1385,10 @@ void CheckUnusedVar::checkFunctionVariableUsage() if (!expr->variable() || !expr->variable()->isMaybeUnused()) { if (structuredBindingTokCount > 0) unusedStructuredBindingTokens.emplace_back(tok, expr); - else + else { unreadVariableError(tok, expr->expressionString(), false); + diagUnreadVariable.emplace(expr->variable()); + } } } } @@ -1390,7 +1411,6 @@ void CheckUnusedVar::checkFunctionVariableUsage() // skip things that are only partially implemented to prevent false positives if (usage.mType == Variables::pointerPointer || - usage.mType == Variables::pointerArray || usage.mType == Variables::referenceArray) continue; @@ -1420,7 +1440,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() !(var->valueType() && var->valueType()->container) && !(var->isStatic() && isReturnedByRef(var, scope->function))) unassignedVariableError(usage._var->nameToken(), varname); - else if (!usage._var->isMaybeUnused() && !usage._modified && !usage._read && var) { + else if (!usage._var->isMaybeUnused() && !usage._modified && !usage._read && var && diagUnreadVariable.count(usage._var) == 0) { const Token* vnt = var->nameToken(); bool error = false; if (vnt->next()->isSplittedVarDeclEq() || (!var->isReference() && vnt->strAt(1) == "=")) { diff --git a/lib/checkvaarg.cpp b/lib/checkvaarg.cpp index 96c65ea41a2..e6efc8f5ed9 100644 --- a/lib/checkvaarg.cpp +++ b/lib/checkvaarg.cpp @@ -30,14 +30,6 @@ #include #include -//--------------------------------------------------------------------------- - -// Register this check class (by creating a static instance of it) -namespace { - CheckVaarg instance; -} - - //--------------------------------------------------------------------------- // Ensure that correct parameter is passed to va_start() //--------------------------------------------------------------------------- @@ -73,7 +65,7 @@ void CheckVaarg::va_start_argument() if (var && var->index() + 2 < function->argCount() && printWarnings) { auto it = function->argumentList.end(); std::advance(it, -2); - wrongParameterTo_va_start_error(tok, var->name(), it->name()); // cppcheck-suppress derefInvalidIterator // FP due to isVariableChangedByFunctionCall() + wrongParameterTo_va_start_error(tok, var->name(), it->name()); } tok = tok->linkAt(1); } diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 44d10f17c60..c96a678347a 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,6 @@ #include "errortypes.h" #include "mathlib.h" -#include "settings.h" #include "standards.h" #include "symboldatabase.h" #include "token.h" @@ -45,6 +44,8 @@ #include #include +class Settings; + static const std::string AccessSpecDecl = "AccessSpecDecl"; static const std::string ArraySubscriptExpr = "ArraySubscriptExpr"; static const std::string BinaryOperator = "BinaryOperator"; diff --git a/lib/config.h b/lib/config.h index 1b217e4546d..c88c431288c 100644 --- a/lib/config.h +++ b/lib/config.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,16 +52,6 @@ #define __has_feature(x) 0 #endif -// C++11 noexcept -#if defined(__cpp_noexcept_function_type) || \ - (defined(__GNUC__) && (__GNUC__ >= 5)) \ - || defined(__clang__) \ - || defined(__CPPCHECK__) -# define NOEXCEPT noexcept -#else -# define NOEXCEPT -#endif - // C++11 noreturn #if __has_cpp_attribute (noreturn) \ || (defined(__GNUC__) && (__GNUC__ >= 5)) \ @@ -96,6 +86,7 @@ # define UNUSED #endif +// TODO: AppleClang versions do not align with Clang versions - add check for proper version // warn_unused #if __has_cpp_attribute (gnu::warn_unused) || \ (defined(__clang__) && (__clang_major__ >= 15)) @@ -115,6 +106,7 @@ # define DEPRECATED #endif +// TODO: AppleClang versions do not align with Clang versions - add check for proper version // returns_nonnull #if __has_cpp_attribute (gnu::returns_nonnull) # define RET_NONNULL [[gnu::returns_nonnull]] @@ -206,9 +198,15 @@ #define USE_WINDOWS_SEH #endif -#if !defined(NO_UNIX_BACKTRACE_SUPPORT) && defined(__GNUC__) && !defined(__APPLE__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__SVR4) && !defined(__QNX__) && !defined(_AIX) +#if !defined(NO_UNIX_BACKTRACE_SUPPORT) +#if defined(HAVE_EXECINFO_H) +#if HAVE_EXECINFO_H +#define USE_UNIX_BACKTRACE_SUPPORT +#endif +#elif __has_include() #define USE_UNIX_BACKTRACE_SUPPORT #endif +#endif #if !defined(NO_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && !defined(__MINGW32__) && !defined(__OS2__) #define USE_UNIX_SIGNAL_HANDLING diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 399eb6d3d6e..f39e64a938f 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include "addoninfo.h" #include "analyzerinfo.h" #include "check.h" +#include "checks.h" #include "checkunusedfunctions.h" #include "clangimport.h" #include "color.h" @@ -177,6 +178,8 @@ class CppCheck::CppCheckLogger : public ErrorLogger // TODO: only convert if necessary const auto errorMessage = SuppressionList::ErrorMessage::fromErrorMessage(msg, macroNames); + bool suppressed = false; + if (mSuppressions.nomsg.isSuppressed(errorMessage, mUseGlobalSuppressions)) { // Safety: Report critical errors to ErrorLogger if (mSettings.safety && ErrorLogger::isCriticalErrorId(msg.id)) { @@ -193,7 +196,7 @@ class CppCheck::CppCheckLogger : public ErrorLogger mErrorLogger.reportErr(msg); } } - return; + suppressed = true; } // TODO: there should be no need for the verbose and default messages here @@ -210,6 +213,9 @@ class CppCheck::CppCheckLogger : public ErrorLogger if (mAnalyzerInformation) mAnalyzerInformation->reportErr(msg); + if (suppressed) + return; + if (!mSuppressions.nofail.isSuppressed(errorMessage) && !mSuppressions.nomsg.isSuppressed(errorMessage)) { mExitCode = 1; } @@ -330,17 +336,17 @@ static std::vector split(const std::string &str, const std::string return ret; } -static std::string getDumpFileName(const Settings& settings, const std::string& filename, int fileIndex) +static std::string getDumpFileName(const Settings& settings, const FileWithDetails& file) { std::string extension = ".dump"; - if (fileIndex > 0) - extension = "." + std::to_string(fileIndex) + extension; + if (file.fsFileId() > 0) + extension = "." + std::to_string(file.fsFileId()) + extension; if (!settings.dump && settings.buildDir.empty()) extension = "." + std::to_string(settings.pid) + extension; if (!settings.dump && !settings.buildDir.empty()) - return AnalyzerInformation::getAnalyzerInfoFile(settings.buildDir, filename, "", fileIndex) + extension; - return filename + extension; + return AnalyzerInformation::getAnalyzerInfoFile(settings.buildDir, file.spath(), "", file.fsFileId()) + extension; + return file.spath() + extension; } static std::string getCtuInfoFileName(const std::string &dumpFile) @@ -350,13 +356,12 @@ static std::string getCtuInfoFileName(const std::string &dumpFile) static void createDumpFile(const Settings& settings, const FileWithDetails& file, - int fileIndex, std::ofstream& fdump, std::string& dumpFile) { if (!settings.dump && settings.addons.empty()) return; - dumpFile = getDumpFileName(settings, file.spath(), fileIndex); + dumpFile = getDumpFileName(settings, file); fdump.open(dumpFile); if (!fdump.is_open()) @@ -660,7 +665,7 @@ static std::string getClangFlags(const Settings& setting, Standards::Language la } // TODO: clear error list before returning -unsigned int CppCheck::checkClang(const FileWithDetails &file, int fileIndex) +unsigned int CppCheck::checkClang(const FileWithDetails &file) { // TODO: clear exitcode @@ -673,7 +678,7 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file, int fileIndex) // TODO: get language from FileWithDetails object std::string clangStderr; if (!mSettings.buildDir.empty()) - clangStderr = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, file.spath(), "", fileIndex) + ".clang-stderr"; + clangStderr = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, file.spath(), "", file.fsFileId()) + ".clang-stderr"; std::string exe = mSettings.clangExecutable; #ifdef _WIN32 @@ -747,7 +752,7 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file, int fileIndex) // create dumpfile std::ofstream fdump; std::string dumpFile; - createDumpFile(mSettings, file, fileIndex, fdump, dumpFile); + createDumpFile(mSettings, file, fdump, dumpFile); if (fdump.is_open()) { fdump << getLibraryDumpData(); // TODO: use tinyxml2 to create XML @@ -791,9 +796,9 @@ unsigned int CppCheck::check(const FileWithDetails &file) unsigned int returnValue; if (mSettings.clang) - returnValue = checkClang(file, 0); + returnValue = checkClang(file); else - returnValue = checkFile(file, "", 0); + returnValue = checkFile(file, ""); // TODO: call analyseClangTidy() @@ -802,7 +807,7 @@ unsigned int CppCheck::check(const FileWithDetails &file) unsigned int CppCheck::checkBuffer(const FileWithDetails &file, const char* data, std::size_t size) { - return checkBuffer(file, "", 0, data, size); + return checkBuffer(file, "", data, size); } unsigned int CppCheck::check(const FileSettings &fs) @@ -838,7 +843,7 @@ unsigned int CppCheck::check(const FileSettings &fs) } // need to pass the externally provided ErrorLogger instead of our internal wrapper CppCheck temp(tempSettings, mSuppressions, mErrorLoggerDirect, mTimerResults, mUseGlobalSuppressions, mExecuteCommand); - const unsigned int returnValue = temp.checkFile(fs.file, fs.cfg, fs.fileIndex); + const unsigned int returnValue = temp.checkFile(fs.file, fs.cfg); if (mUnusedFunctionsCheck) mUnusedFunctionsCheck->updateFunctionData(*temp.mUnusedFunctionsCheck); while (!temp.mFileInfo.empty()) { @@ -875,20 +880,20 @@ std::size_t CppCheck::calculateHash(const Preprocessor& preprocessor, const std: return preprocessor.calculateHash(toolinfo.str()); } -unsigned int CppCheck::checkBuffer(const FileWithDetails &file, const std::string &cfgname, int fileIndex, const char* data, std::size_t size) +unsigned int CppCheck::checkBuffer(const FileWithDetails &file, const std::string &cfgname, const char* data, std::size_t size) { const auto f = [&file, data, size](std::vector& files, simplecpp::OutputList* outputList) { return simplecpp::TokenList{{data, size}, files, file.spath(), outputList}; }; - return checkInternal(file, cfgname, fileIndex, f); + return checkInternal(file, cfgname, f); } -unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname, int fileIndex) +unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname) { const auto f = [&file](std::vector& files, simplecpp::OutputList* outputList) { return simplecpp::TokenList{file.spath(), files, outputList}; }; - return checkInternal(file, cfgname, fileIndex, f); + return checkInternal(file, cfgname, f); } void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector& files) @@ -906,7 +911,7 @@ void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vectorexitcode(); - const Timer fileTotalTimer{file.spath(), mSettings.showtime, nullptr, Timer::Type::FILE}; + std::unique_ptr checkTimeTimer; + if (mSettings.showtime == Settings::ShowTime::FILE || mSettings.showtime == Settings::ShowTime::FILE_TOTAL || mSettings.showtime == Settings::ShowTime::TOP5_FILE) + checkTimeTimer.reset(new OneShotTimer("Check time: " + file.spath())); if (!mSettings.quiet) { std::string fixedpath = Path::toNativeSeparators(file.spath()); @@ -974,7 +981,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str mLogger->setAnalyzerInfo(nullptr); std::list errors; - analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, fileIndex, hash, errors); + analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, file.fsFileId(), hash, errors, mSettings.debugainfo); analyzerInformation->setFileInfo("CheckUnusedFunctions", mUnusedFunctionsCheck->analyzerInfo(tokenizer)); analyzerInformation->close(); } @@ -1020,7 +1027,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str // Calculate hash so it can be compared with old hash / future hashes const std::size_t hash = calculateHash(preprocessor, file.spath()); std::list errors; - if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, fileIndex, hash, errors)) { + if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, file.fsFileId(), hash, errors, mSettings.debugainfo)) { while (!errors.empty()) { mErrorLogger.reportErr(errors.front()); errors.pop_front(); @@ -1039,7 +1046,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str // Get configurations.. std::set configurations; if (maxConfigs > 1) { - Timer::run("Preprocessor::getConfigs", mSettings.showtime, mTimerResults, [&]() { + Timer::run("Preprocessor::getConfigs", mTimerResults, [&]() { configurations = preprocessor.getConfigs(); }); } else { @@ -1077,7 +1084,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str // write dump file xml prolog std::ofstream fdump; std::string dumpFile; - createDumpFile(mSettings, file, fileIndex, fdump, dumpFile); + createDumpFile(mSettings, file, fdump, dumpFile); if (fdump.is_open()) { fdump << getLibraryDumpData(); fdump << dumpProlog; @@ -1124,7 +1131,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (mSettings.preprocessOnly) { std::string codeWithoutCfg; - Timer::run("Preprocessor::getcode", mSettings.showtime, mTimerResults, [&]() { + Timer::run("Preprocessor::getcode", mTimerResults, [&]() { codeWithoutCfg = preprocessor.getcode(currentConfig, files, true); }); @@ -1148,7 +1155,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str { bool skipCfg = false; // Create tokens, skip rest of iteration if failed - Timer::run("Tokenizer::createTokens", mSettings.showtime, mTimerResults, [&]() { + Timer::run("Tokenizer::createTokens", mTimerResults, [&]() { simplecpp::OutputList outputList_cfg; simplecpp::TokenList tokensP = preprocessor.preprocess(currentConfig, files, outputList_cfg); const simplecpp::Output* o = preprocessor.handleErrors(outputList_cfg); @@ -1162,7 +1169,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (!hasValidConfig && currCfg == *configurations.rbegin()) { // If there is no valid configuration then report error.. - preprocessor.error(tokensP.file(o->location), o->location.line, o->location.col, o->msg, o->type); + preprocessor.error(o->location, o->msg, o->type); } skipCfg = true; } @@ -1174,8 +1181,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str Tokenizer tokenizer(std::move(tokenlist), mErrorLogger); try { - if (mSettings.showtime != ShowTime::NONE) - tokenizer.setTimerResults(mTimerResults); + tokenizer.setTimerResults(mTimerResults); tokenizer.setDirectives(directives); // TODO: how to avoid repeated copies? // locations macros @@ -1200,7 +1206,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str #endif // Simplify tokens into normal form, skip rest of iteration if failed - if (!tokenizer.simplifyTokens1(currentConfig, fileIndex)) + if (!tokenizer.simplifyTokens1(currentConfig, file.fsFileId())) continue; // dump xml if --dump @@ -1218,7 +1224,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (mSettings.inlineSuppressions) { // Need to call this even if the hash will skip this configuration - mSuppressions.nomsg.markUnmatchedInlineSuppressionsAsChecked(tokenizer); + mSuppressions.nomsg.markUnmatchedInlineSuppressionsAsChecked(tokenizer.list); } // Skip if we already met the same simplified token list @@ -1242,8 +1248,8 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (!hasValidConfig && configurations.size() > 1 && mSettings.severity.isEnabled(Severity::information)) { std::string msg; - msg = "This file is not analyzed. Cppcheck failed to extract a valid configuration. Use -v for more details."; - msg += "\nThis file is not analyzed. Cppcheck failed to extract a valid configuration. The tested configurations have these preprocessor errors:"; + msg = "This file is not analyzed. No working configuration could be extracted. Use -v for more details."; + msg += "\nThis file is not analyzed. No working configuration could be extracted. The tested configurations have these preprocessor errors:"; for (const std::string &s : configurationError) msg += '\n' + s; @@ -1288,8 +1294,12 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str // TODO: clear earlier? mLogger->clear(); - if (mTimerResults && (mSettings.showtime == ShowTime::FILE || mSettings.showtime == ShowTime::TOP5_FILE)) - mTimerResults->showResults(mSettings.showtime); + if (mTimerResults) { + if (mSettings.showtime == Settings::ShowTime::FILE) + mTimerResults->showResults(); + else if (mSettings.showtime == Settings::ShowTime::TOP5_FILE) + mTimerResults->showResults(5); + } return mLogger->exitcode(); } @@ -1317,6 +1327,8 @@ void CppCheck::internalError(const std::string &filename, const std::string &msg void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation* analyzerInformation, const std::string& currentConfig) { + const ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, tokenizer.list.getSourceFilePath(), "Run checkers"); + CheckUnusedFunctions unusedFunctionsChecker; // TODO: this should actually be the behavior if only "--enable=unusedFunction" is specified - see #10648 @@ -1327,8 +1339,7 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation const std::time_t maxTime = mSettings.checksMaxTime > 0 ? std::time(nullptr) + mSettings.checksMaxTime : 0; // call all "runChecks" in all registered Check classes - // cppcheck-suppress shadowFunction - TODO: fix this - for (Check *check : Check::instances()) { + for (Check * const c : CheckInstances::get()) { if (Settings::terminated()) return; @@ -1346,8 +1357,8 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation return; } - Timer::run(check->name() + "::runChecks", mSettings.showtime, mTimerResults, [&]() { - check->runChecks(tokenizer, &mErrorLogger); + Timer::run(c->name() + "::runChecks", mTimerResults, [&]() { + c->runChecks(tokenizer, &mErrorLogger); }); } } @@ -1377,11 +1388,10 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation } if (!doUnusedFunctionOnly) { - // cppcheck-suppress shadowFunction - TODO: fix this - for (const Check *check : Check::instances()) { - if (Check::FileInfo * const fi = check->getFileInfo(tokenizer, mSettings, currentConfig)) { + for (const Check * const c : CheckInstances::get()) { + if (Check::FileInfo * const fi = c->getFileInfo(tokenizer, mSettings, currentConfig)) { if (analyzerInformation) - analyzerInformation->setFileInfo(check->name(), fi->toString()); + analyzerInformation->setFileInfo(c->name(), fi->toString()); if (mSettings.useSingleJob()) mFileInfo.push_back(fi); else @@ -1481,7 +1491,7 @@ void CppCheck::executeAddons(const std::string& dumpFile, const FileWithDetails& { if (!dumpFile.empty()) { std::vector f{dumpFile}; - Timer::run("CppCheck::executeAddons", mSettings.showtime, mTimerResults, [&]() { + Timer::run("CppCheck::executeAddons", mTimerResults, [&]() { executeAddons(f, file.spath()); }); } @@ -1515,6 +1525,8 @@ void CppCheck::executeAddons(const std::vector& files, const std::s if (isCtuInfo && addonInfo.name != "misra" && !addonInfo.ctu) continue; + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, files.front(), "addon:" + addonInfo.name + (isCtuInfo ? " (ctu)" : "")); + std::vector results; try { @@ -1631,12 +1643,12 @@ void CppCheck::executeAddonsWholeProgram(const std::list &files std::vector ctuInfoFiles; for (const auto &f: files) { - const std::string &dumpFileName = getDumpFileName(mSettings, f.path(), 0); + const std::string &dumpFileName = getDumpFileName(mSettings, f); ctuInfoFiles.push_back(getCtuInfoFileName(dumpFileName)); } - for (const auto &f: fileSettings) { - const std::string &dumpFileName = getDumpFileName(mSettings, f.filename(), f.fileIndex); + for (const auto &fs: fileSettings) { + const std::string &dumpFileName = getDumpFileName(mSettings, fs.file); ctuInfoFiles.push_back(getCtuInfoFileName(dumpFileName)); } @@ -1701,8 +1713,8 @@ void CppCheck::getErrorMessages(ErrorLogger &errorlogger) s.addEnabled("all"); // call all "getErrorMessages" in all registered Check classes - for (auto it = Check::instances().cbegin(); it != Check::instances().cend(); ++it) - (*it)->getErrorMessages(&errorlogger, &s); + for (const Check * const c : CheckInstances::get()) + c->getErrorMessages(&errorlogger, &s); CheckUnusedFunctions::getErrorMessages(errorlogger); Preprocessor::getErrorMessages(errorlogger, s); @@ -1748,7 +1760,7 @@ void CppCheck::analyseClangTidy(const FileSettings &fileSettings) std::string line; if (!mSettings.buildDir.empty()) { - const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, fileSettings.filename(), "", fileSettings.fileIndex); + const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, fileSettings.sfilename(), "", fileSettings.file.fsFileId()); std::ofstream fcmd(analyzerInfoFile + ".clang-tidy-cmd"); fcmd << istr.str(); } @@ -1819,9 +1831,8 @@ bool CppCheck::analyseWholeProgram() } } - // cppcheck-suppress shadowFunction - TODO: fix this - for (Check *check : Check::instances()) - errors |= check->analyseWholeProgram(ctu, mFileInfo, mSettings, mErrorLogger); // TODO: ctu + for (Check * const c : CheckInstances::get()) + errors |= c->analyseWholeProgram(ctu, mFileInfo, mSettings, mErrorLogger); // TODO: ctu } if (mUnusedFunctionsCheck) @@ -1851,7 +1862,7 @@ unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const st ctuFileInfo.loadFromXml(e); return; } - for (const Check *check : Check::instances()) { + for (const Check *check : CheckInstances::get()) { if (checkattr == check->name()) { if (Check::FileInfo* fi = check->loadFileInfoFromXml(e)) { fi->file0 = filesTxtInfo.sourceFile; @@ -1861,12 +1872,16 @@ unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const st } }; - AnalyzerInformation::processFilesTxt(buildDir, handler); - - // Analyse the tokens - // cppcheck-suppress shadowFunction - TODO: fix this - for (Check *check : Check::instances()) - check->analyseWholeProgram(ctuFileInfo, fileInfoList, mSettings, mErrorLogger); + const std::string err = AnalyzerInformation::processFilesTxt(buildDir, handler, mSettings.debugainfo); + if (!err.empty()) { + const ErrorMessage errmsg({}, "", Severity::error, err, "internalError", Certainty::normal); + mErrorLogger.reportErr(errmsg); + } + else { + // Analyse the tokens + for (Check * const c : CheckInstances::get()) + c->analyseWholeProgram(ctuFileInfo, fileInfoList, mSettings, mErrorLogger); + } for (Check::FileInfo *fi : fileInfoList) delete fi; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 22423689cdf..94f2b721037 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -179,7 +179,7 @@ class CPPCHECKLIB CppCheck { * @param cfgname cfg name * @return number of errors found */ - unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname, int fileIndex); + unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname); void checkPlistOutput(const FileWithDetails& file, const std::vector& files); @@ -191,7 +191,7 @@ class CPPCHECKLIB CppCheck { * @param size the size of the data to be read * @return number of errors found */ - unsigned int checkBuffer(const FileWithDetails& file, const std::string &cfgname, int fileIndex, const char* data, std::size_t size); + unsigned int checkBuffer(const FileWithDetails& file, const std::string &cfgname, const char* data, std::size_t size); // TODO: should use simplecpp::OutputList using CreateTokenListFn = std::function&, std::list*)>; @@ -203,12 +203,12 @@ class CPPCHECKLIB CppCheck { * @param createTokenList a function to create the simplecpp::TokenList with * @return number of errors found */ - unsigned int checkInternal(const FileWithDetails& file, const std::string &cfgname, int fileIndex, const CreateTokenListFn& createTokenList); + unsigned int checkInternal(const FileWithDetails& file, const std::string &cfgname, const CreateTokenListFn& createTokenList); /** * @brief Check normal tokens * @param tokenizer tokenizer instance - * @param analyzerInformation the analyzer infomation + * @param analyzerInformation the analyzer information */ void checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation* analyzerInformation, const std::string& currentConfig); @@ -232,7 +232,7 @@ class CPPCHECKLIB CppCheck { void executeRules(const std::string &tokenlist, const TokenList &list); #endif - unsigned int checkClang(const FileWithDetails &file, int fileIndex); + unsigned int checkClang(const FileWithDetails &file); const Settings& mSettings; Suppressions& mSuppressions; diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index d0175b2997f..12bd4898d4a 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -18,8 +18,14 @@ - - + + NotUsing + + + + NotUsing + + @@ -51,6 +57,7 @@ + @@ -124,6 +131,7 @@ + diff --git a/lib/ctu.cpp b/lib/ctu.cpp index df8ee0f74b6..938bb2a4dcc 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -112,7 +112,7 @@ std::string CTU::FileInfo::FunctionCall::toXmlString() const out << ">\n"; for (const ErrorMessage::FileLocation &loc : callValuePath) out << " \n"; @@ -512,7 +512,7 @@ static bool findPath(const std::string &callId, if (index >= maxCtuDepth) return false; // TODO: add bailout message? - const auto it = utils::as_const(callsMap).find(callId); + const auto it = callsMap.find(callId); if (it == callsMap.end()) return false; @@ -559,6 +559,20 @@ static bool findPath(const std::string &callId, return false; } +static std::string getInvalidValueString(CTU::FileInfo::InvalidValueType invalidValue) +{ + using InvalidValueType = CTU::FileInfo::InvalidValueType; + switch (invalidValue) { + case InvalidValueType::null: + return "null"; + case InvalidValueType::uninit: + return "uninitialized"; + case InvalidValueType::bufferOverflow: + return "accessed out of bounds"; + } + cppcheck::unreachable(); +} + std::list CTU::FileInfo::getErrorPath(InvalidValueType invalidValue, const CTU::FileInfo::UnsafeUsage &unsafeUsage, const std::map> &callsMap, @@ -581,7 +595,7 @@ std::list CTU::FileInfo::getErrorPath(InvalidValueTy std::list locationList; - const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized"; + const std::string value1 = getInvalidValueString(invalidValue); for (int index = 9; index >= 0; index--) { if (!path[index]) diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index e62ed6b806d..3b05a7d5a8f 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -162,6 +162,7 @@ ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Seve // hash = calculateWarningHash(tokenList, hashWarning.str()); } +// TODO: improve errorhandling? ErrorMessage::ErrorMessage(const tinyxml2::XMLElement * const errmsg) : severity(Severity::none), cwe(0U), @@ -1079,8 +1080,15 @@ std::string getGuideline(const std::string &errId, ReportType reportType, case ReportType::misraC2012: case ReportType::misraC2023: case ReportType::misraC2025: - if (errId.rfind("misra-c20", 0) == 0 || errId.rfind("premium-misra-c-20", 0) == 0) - guideline = errId.substr(errId.rfind('-') + 1); + if (errId.rfind("misra-c20", 0) == 0 || errId.rfind("premium-misra-c-20", 0) == 0) { + auto pos1 = errId.find("20") + 5; + if (pos1 >= errId.size()) + break; + if (errId.compare(pos1,4,"dir-",0,4) == 0) + pos1 += 4; + const auto endpos = errId.find('-', pos1); + guideline = errId.substr(pos1, endpos-pos1); + } break; case ReportType::misraCpp2008: if (errId.rfind("premium-misra-cpp-2008", 0) == 0) diff --git a/lib/errorlogger.h b/lib/errorlogger.h index f8806bbbdca..d739cb3fbf9 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,11 +24,12 @@ #include "config.h" #include "errortypes.h" -#include #include +#include #include #include #include +#include #include #include @@ -286,6 +287,43 @@ class CPPCHECKLIB ErrorLogger { static const std::set mCriticalErrorIds; }; +/// RAII class for reporting progress messages +class CPPCHECKLIB ProgressReporter { +public: + ProgressReporter(ErrorLogger& e, int reportProgressInterval, std::string filename, std::string stage) : + mErrorLogger(e), + mReportProgressInterval(reportProgressInterval), + mFilename(std::move(filename)), + mStage(std::move(stage)) { + report(0); + } + + ~ProgressReporter() { + if (mReportProgressInterval < 0) + return; + mErrorLogger.reportProgress(mFilename, mStage.c_str(), 100); + } + + void report(int value) { + if (mReportProgressInterval < 0 || value == mLastValue) + return; + const std::time_t t = std::time(nullptr); + if (t >= mLastTime + mReportProgressInterval) { + mErrorLogger.reportProgress(mFilename, mStage.c_str(), value); + mLastTime = t; + mLastValue = value; + } + } + +private: + ErrorLogger& mErrorLogger; + const int mReportProgressInterval; + const std::string mFilename; + const std::string mStage; + std::time_t mLastTime{0}; + int mLastValue{-1}; +}; + /** Replace substring. Example replaceStr("1,NR,3", "NR", "2") => "1,2,3" */ std::string replaceStr(std::string s, const std::string &from, const std::string &to); @@ -298,12 +336,12 @@ CPPCHECKLIB void substituteTemplateLocationStatic(std::string& templateLocation, /** Get a classification string from the given guideline and reporttype */ CPPCHECKLIB std::string getClassification(const std::string &guideline, ReportType reportType); -/** Get a guidline string froM the given error id, reporttype, mapping and severity */ +/** Get a guideline string froM the given error id, reporttype, mapping and severity */ CPPCHECKLIB std::string getGuideline(const std::string &errId, ReportType reportType, const std::map &guidelineMapping, Severity severity); -/** Get a map from cppcheck error ids to guidlines matching the given report type */ +/** Get a map from cppcheck error ids to guidelines matching the given report type */ CPPCHECKLIB std::map createGuidelineMapping(ReportType reportType); /// @} diff --git a/lib/filesettings.h b/lib/filesettings.h index 3149421c629..183e38708fd 100644 --- a/lib/filesettings.h +++ b/lib/filesettings.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,16 +34,25 @@ class FileWithDetails { public: + /** + * @throws std::runtime_error thrown if given path is empty + */ FileWithDetails(std::string path, Standards::Language lang, std::size_t size) - : mPath(std::move(path)) - , mPathSimplified(Path::simplifyPath(mPath)) - , mLang(lang) + : mLang(lang) , mSize(size) { + setPath(std::move(path)); if (mPath.empty()) throw std::runtime_error("empty path specified"); } + void setPath(std::string path) + { + mPath = std::move(path); + mPathSimplified = Path::simplifyPath(mPath); + mPathAbsolute.clear(); + } + const std::string& path() const { return mPath; @@ -54,6 +63,14 @@ class FileWithDetails return mPathSimplified; } + const std::string& abspath() const + { + // use delayed resolution as it will fail for files which do not exist + if (mPathAbsolute.empty()) + mPathAbsolute = Path::getAbsoluteFilePath(mPath); + return mPathAbsolute; + } + std::size_t size() const { return mSize; @@ -68,11 +85,23 @@ class FileWithDetails { return mLang; } + + std::size_t fsFileId() const + { + return mFsFileId; + } + + void setFsFileId(std::size_t id) + { + mFsFileId = id; + } private: std::string mPath; std::string mPathSimplified; + mutable std::string mPathAbsolute; Standards::Language mLang = Standards::Language::None; std::size_t mSize; + std::size_t mFsFileId{0}; }; /** File settings. Multiple configurations for a file is allowed. */ @@ -81,14 +110,12 @@ struct CPPCHECKLIB FileSettings { : file(std::move(path), lang, size) {} - int fileIndex = 0; std::string cfg; FileWithDetails file; const std::string& filename() const { return file.path(); } - // cppcheck-suppress unusedFunction const std::string& sfilename() const { return file.spath(); diff --git a/lib/fwdanalysis.cpp b/lib/fwdanalysis.cpp index 11434e5356d..c45213a4be9 100644 --- a/lib/fwdanalysis.cpp +++ b/lib/fwdanalysis.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include "token.h" #include "vfvalue.h" +#include #include #include #include @@ -361,7 +362,7 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * while (argnr < args.size() && args[argnr] != parent) argnr++; if (argnr < args.size()) { - if (mSettings.library.getArgDirection(ftok->astOperand1(), argnr + 1) == Library::ArgumentChecks::Direction::DIR_OUT) + if (mSettings.library.getArgDirection(ftok->astOperand1(), argnr + 1, /*indirect*/ 1) == Library::ArgumentChecks::Direction::DIR_OUT) continue; } } @@ -409,6 +410,16 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * return Result(Result::Type::NONE); } +static bool isSimpleIndexExpression(const Token* tok) +{ + const Token* idx = tok->astOperand2(); + if (!idx) + return false; + if (idx->isIncDecOp()) + idx = idx->astOperand1(); + return idx->variable() && idx->variable()->scope() == tok->scope(); +} + std::set FwdAnalysis::getExprVarIds(const Token* expr, bool* localOut, bool* unknownVarIdOut) const { // all variable ids in expr. @@ -417,7 +428,7 @@ std::set FwdAnalysis::getExprVarIds(const Token* expr, bool* localOu bool unknownVarId = false; visitAstNodes(expr, [&](const Token *tok) { - if (tok->str() == "[" && mWhat == What::UnusedValue) + if (tok->str() == "[" && mWhat == What::UnusedValue && isSimpleIndexExpression(tok)) return ChildrenToVisit::op1; if (tok->varId() == 0 && tok->isName() && tok->strAt(-1) != ".") { // unknown variable @@ -478,9 +489,18 @@ bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const { if (!tok) return false; - if (isSameExpression(false, tok, lhs, mSettings, false, false, nullptr)) - return true; - return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs); + std::deque nodes{ tok }; + while (!nodes.empty()) { + const Token* node = nodes.front(); + if (isSameExpression(false, node, lhs, mSettings, false, false, nullptr)) + return true; + if (node->astOperand1()) + nodes.emplace_back(node->astOperand1()); + if (node->astOperand2()) + nodes.emplace_back(node->astOperand2()); + nodes.pop_front(); + } + return false; } const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, const Token *endToken) diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 2433cf6e0e4..ac19db922ed 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -103,7 +104,7 @@ std::string ImportProject::collectArgs(const std::string &cmd, std::vector variables; std::vector sharedItemsProjects; @@ -361,7 +367,7 @@ bool ImportProject::importCompileCommands(std::istream &istr) return false; } - std::map fileIndex; + std::map fsFileIds; for (const picojson::value &fileInfo : compileCommands.get()) { picojson::object obj = fileInfo.get(); @@ -444,7 +450,7 @@ bool ImportProject::importCompileCommands(std::istream &istr) fsSetIncludePaths(fs, directory, fs.includePaths, variables); // Assign a unique index to each file path. If the file path already exists in the map, // increment the index to handle duplicate file entries. - fs.fileIndex = fileIndex[path]++; + fs.file.setFsFileId(fsFileIds[path]++); fileSettings.push_back(std::move(fs)); } @@ -502,8 +508,57 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const return true; } +bool ImportProject::importSlnx(const std::string& filename, const std::vector& fileFilters) +{ + tinyxml2::XMLDocument doc; + const tinyxml2::XMLError error = doc.LoadFile(filename.c_str()); + if (error != tinyxml2::XML_SUCCESS) { + errors.emplace_back(std::string("Visual Studio solution file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error)); + return false; + } + + const tinyxml2::XMLElement* const rootnode = doc.FirstChildElement(); + if (rootnode == nullptr) { + errors.emplace_back("Visual Studio solution file has no XML root node"); + return false; + } + + std::map variables; + variables["SolutionDir"] = Path::simplifyPath(Path::getPathFromFilename(filename)); + + bool found = false; + std::vector sharedItemsProjects; + + for (const tinyxml2::XMLElement* node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) { + const char* name = node->Name(); + if (std::strcmp(name, "Project") == 0) { + const char* labelAttribute = node->Attribute("Path"); + if (labelAttribute) { + std::string vcxproj(labelAttribute); + vcxproj = Path::toNativeSeparators(std::move(vcxproj)); + if (!Path::isAbsolute(vcxproj)) + vcxproj = variables["SolutionDir"] + vcxproj; + vcxproj = Path::fromNativeSeparators(std::move(vcxproj)); + if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) { + errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution"); + return false; + } + found = true; + } + } + } + + if (!found) { + errors.emplace_back("no projects found in Visual Studio solution file"); + return false; + } + + return true; +} + namespace { struct ProjectConfiguration { + ProjectConfiguration() = default; explicit ProjectConfiguration(const tinyxml2::XMLElement *cfg) { const char *a = cfg->Attribute("Include"); if (a) @@ -549,18 +604,30 @@ namespace { // see https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions // properties are .NET String objects and you can call any of its members on them - bool conditionIsTrue(const ProjectConfiguration &p) const { + bool conditionIsTrue(const ProjectConfiguration &p, const std::string &filename, std::vector &errors) const { if (mCondition.empty()) return true; - std::string c = '(' + mCondition + ");"; + try { + return evalCondition(mCondition, p); + } + catch (const std::runtime_error& r) + { + errors.emplace_back(filename + ": Can not evaluate condition '" + mCondition + "': " + r.what()); + return false; + } + } + + static bool evalCondition(const std::string& condition, const ProjectConfiguration &p) { + std::string c = '(' + condition + ")"; replaceAll(c, "$(Configuration)", p.configuration); replaceAll(c, "$(Platform)", p.platformStr); - // TODO: improve evaluation const Settings s; TokenList tokenlist(s, Standards::Language::C); - tokenlist.createTokensFromBuffer(c.data(), c.size()); // TODO: check result - // TODO: put in a helper + if (!tokenlist.createTokensFromBuffer(c.data(), c.size())) { + throw std::runtime_error("Can not tokenize condition"); + } + // generate links { std::stack lpar; @@ -569,25 +636,88 @@ namespace { lpar.push(tok2); else if (tok2->str() == ")") { if (lpar.empty()) - break; + throw std::runtime_error("unmatched ')' in condition " + condition); Token::createMutualLinks(lpar.top(), tok2); lpar.pop(); } } + if (!lpar.empty()) + throw std::runtime_error("'(' without closing ')'!"); } + + // Replace "And" and "Or" with "&&" and "||" + for (Token *tok = tokenlist.front(); tok; tok = tok->next()) { + if (tok->str() == "And") + tok->str("&&"); + else if (tok->str() == "Or") + tok->str("||"); + } + tokenlist.createAst(); + + // Locate ast top and execute the condition for (const Token *tok = tokenlist.front(); tok; tok = tok->next()) { - if (tok->str() == "(" && tok->astOperand1() && tok->astOperand2()) { - // TODO: this is wrong - it is Contains() not Equals() - if (tok->astOperand1()->expressionString() == "Configuration.Contains") - return ('\'' + p.configuration + '\'') == tok->astOperand2()->str(); + if (tok->astParent()) { + return execute(tok->astTop(), p) == "True"; } - if (tok->str() == "==" && tok->astOperand1() && tok->astOperand2() && tok->astOperand1()->str() == tok->astOperand2()->str()) - return true; } - return false; + throw std::runtime_error("Invalid condition: '" + condition + "'"); } + + private: + + static std::string executeOp1(const Token* tok, const ProjectConfiguration &p) { + return execute(tok->astOperand1(), p); + } + + static std::string executeOp2(const Token* tok, const ProjectConfiguration &p) { + return execute(tok->astOperand2(), p); + } + + static std::string execute(const Token* tok, const ProjectConfiguration &p) { + if (!tok) + throw std::runtime_error("Missing operator"); + auto boolResult = [](bool b) -> std::string { + return b ? "True" : "False"; + }; + if (tok->isUnaryOp("!")) + return boolResult(executeOp1(tok, p) == "False"); + if (tok->str() == "==") + return boolResult(executeOp1(tok, p) == executeOp2(tok, p)); + if (tok->str() == "!=") + return boolResult(executeOp1(tok, p) != executeOp2(tok, p)); + if (tok->str() == "&&") + return boolResult(executeOp1(tok, p) == "True" && executeOp2(tok, p) == "True"); + if (tok->str() == "||") + return boolResult(executeOp1(tok, p) == "True" || executeOp2(tok, p) == "True"); + if (tok->str() == "(" && Token::Match(tok->previous(), "$ ( %name% . %name% (")) { + const std::string& propertyName = tok->strAt(1); + std::string propertyValue; + if (propertyName == "Configuration") + propertyValue = p.configuration; + else if (propertyName == "Platform") + propertyValue = p.platformStr; + else + throw std::runtime_error("Unhandled property '" + propertyName + "'"); + const std::string& method = tok->strAt(3); + std::string arg = executeOp2(tok->tokAt(4), p); + if (arg.size() >= 2 && arg[0] == '\'') + arg = arg.substr(1, arg.size() - 2); + if (method == "Contains") + return boolResult(propertyValue.find(arg) != std::string::npos); + if (method == "EndsWith") + return boolResult(endsWith(propertyValue,arg.c_str(),arg.size())); + if (method == "StartsWith") + return boolResult(startsWith(propertyValue,arg)); + throw std::runtime_error("Unhandled method '" + method + "'"); + } + if (tok->str().size() >= 2 && tok->str()[0] == '\'') // String Literal + return tok->str(); + + throw std::runtime_error("Unknown/unhandled operator/operand '" + tok->str() + "'"); + } + std::string mCondition; }; @@ -893,7 +1023,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X } std::string additionalIncludePaths; for (const ItemDefinitionGroup &i : itemDefinitionGroupList) { - if (!i.conditionIsTrue(p)) + if (!i.conditionIsTrue(p, cfilename, errors)) continue; fs.standard = Standards::getCPP(i.cppstd); fs.defines += ';' + i.preprocessorDefinitions; @@ -911,7 +1041,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X } bool useUnicode = false; for (const ConfigurationPropertyGroup &c : configurationPropertyGroups) { - if (!c.conditionIsTrue(p)) + if (!c.conditionIsTrue(p, cfilename, errors)) continue; // in msbuild the last definition wins useUnicode = c.useUnicode; @@ -1354,6 +1484,10 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti else if (strcmp(name, CppcheckXml::UndefinesElementName) == 0) { for (const std::string &u : readXmlStringList(node, "", CppcheckXml::UndefineName, nullptr)) temp.userUndefs.insert(u); + } else if (strcmp(name, CppcheckXml::UserIncludeElementName) == 0) { + const char* i = node->GetText(); + if (i) + temp.userIncludes.emplace_back(i); } else if (strcmp(name, CppcheckXml::ImportProjectElementName) == 0) { const std::string t_str = empty_if_null(node->GetText()); if (!t_str.empty()) @@ -1442,7 +1576,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti else if (strcmp(childname, Settings::SafeChecks::XmlExternalVariables) == 0) temp.safeChecks.externalVariables = true; else { - errors.emplace_back("Unknown '" + std::string(Settings::SafeChecks::XmlRootName) + "' element '" + childname + "' in Cppcheck project file"); + errors.emplace_back("Unknown '" + std::string(Settings::SafeChecks::XmlRootName) + "' element '" + childname + "' in Cppcheck GUI project file"); return false; } } @@ -1465,7 +1599,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti else if (strcmp(name, CppcheckXml::ProjectNameElementName) == 0) ; // no-op else { - errors.emplace_back("Unknown element '" + std::string(name) + "' in Cppcheck project file"); + errors.emplace_back("Unknown element '" + std::string(name) + "' in Cppcheck GUI project file"); return false; } } @@ -1475,6 +1609,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti settings.includePaths = temp.includePaths; // TODO: append instead of overwrite settings.userDefines = temp.userDefines; // TODO: append instead of overwrite settings.userUndefs = temp.userUndefs; // TODO: append instead of overwrite + settings.userIncludes = temp.userIncludes; // TODO: append instead of overwrite for (const std::string &addon : temp.addons) settings.addons.emplace(addon); settings.clang = temp.clang; @@ -1562,9 +1697,19 @@ void ImportProject::setRelativePaths(const std::string &filename) return; const std::vector basePaths{Path::fromNativeSeparators(Path::getCurrentPath())}; for (auto &fs: fileSettings) { - fs.file = FileWithDetails{Path::getRelativePath(fs.filename(), basePaths), Standards::Language::None, 0}; // file will be identified later on + fs.file.setPath(Path::getRelativePath(fs.filename(), basePaths)); for (auto &includePath: fs.includePaths) includePath = Path::getRelativePath(includePath, basePaths); } } +// only used by tests (testimportproject.cpp::testVcxprojConditions): +// cppcheck-suppress unusedFunction +bool cppcheck::testing::evaluateVcxprojCondition(const std::string& condition, const std::string& configuration, + const std::string& platform) +{ + ProjectConfiguration p; + p.configuration = configuration; + p.platformStr = platform; + return ConditionalGroup::evalCondition(condition, p); +} diff --git a/lib/importproject.h b/lib/importproject.h index 55b65bfa641..608af552408 100644 --- a/lib/importproject.h +++ b/lib/importproject.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,13 +49,17 @@ namespace cppcheck { return caseInsensitiveStringCompare(lhs,rhs) < 0; } }; + + namespace testing + { + CPPCHECKLIB bool evaluateVcxprojCondition(const std::string& condition, const std::string& configuration, const std::string& platform); + } } /** * @brief Importing project settings. */ class CPPCHECKLIB WARN_UNUSED ImportProject { - friend class TestImporter; public: enum class Type : std::uint8_t { NONE, @@ -64,14 +68,17 @@ class CPPCHECKLIB WARN_UNUSED ImportProject { FAILURE, COMPILE_DB, VS_SLN, + VS_SLNX, VS_VCXPROJ, BORLAND, CPPCHECK_GUI }; +protected: static void fsSetDefines(FileSettings& fs, std::string defs); static void fsSetIncludePaths(FileSettings& fs, const std::string &basepath, const std::list &in, std::map &variables); +public: std::list fileSettings; std::vector errors; @@ -103,9 +110,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject { bool importCompileCommands(std::istream &istr); bool importCppcheckGuiProject(std::istream &istr, Settings &settings, Suppressions &supprs); static std::string collectArgs(const std::string &cmd, std::vector &args); - static void parseArgs(FileSettings &fs, const std::vector &args); -private: struct SharedItemsProject { bool successful = false; std::string pathToProjectFile; @@ -113,14 +118,18 @@ class CPPCHECKLIB WARN_UNUSED ImportProject { std::vector sourceFiles; }; - bool importSln(std::istream &istr, const std::string &path, const std::vector &fileFilters); - SharedItemsProject importVcxitems(const std::string &filename, const std::vector &fileFilters, std::vector &cache); bool importVcxproj(const std::string &filename, std::map &variables, const std::string &additionalIncludeDirectories, const std::vector &fileFilters, std::vector &cache); bool importVcxproj(const std::string &filename, const tinyxml2::XMLDocument &doc, std::map &variables, const std::string &additionalIncludeDirectories, const std::vector &fileFilters, std::vector &cache); - bool importBcb6Prj(const std::string &projectFilename); +private: + static void parseArgs(FileSettings &fs, const std::vector &args); void setRelativePaths(const std::string &filename); + bool importSln(std::istream &istr, const std::string &path, const std::vector &fileFilters); + bool importSlnx(const std::string& filename, const std::vector& fileFilters); + SharedItemsProject importVcxitems(const std::string &filename, const std::vector &fileFilters, std::vector &cache); + bool importBcb6Prj(const std::string &projectFilename); + std::string mPath; std::set mAllVSConfigs; }; @@ -142,6 +151,7 @@ namespace CppcheckXml { static constexpr char DefineNameAttrib[] = "name"; static constexpr char UndefinesElementName[] = "undefines"; static constexpr char UndefineName[] = "undefine"; + static constexpr char UserIncludeElementName[] = "user-include"; static constexpr char PathsElementName[] = "paths"; static constexpr char PathName[] = "dir"; static constexpr char PathNameAttrib[] = "name"; @@ -188,10 +198,13 @@ namespace CppcheckXml { static constexpr char CodingStandardsElementName[] = "coding-standards"; static constexpr char CodingStandardElementName[] = "coding-standard"; static constexpr char CertIntPrecisionElementName[] = "cert-c-int-precision"; - static constexpr char LicenseFileElementName[] = "license-file"; static constexpr char ProjectNameElementName[] = "project-name"; } +namespace testing +{ + CPPCHECKLIB bool evaluateVcxprojCondition(const std::string& condition, const std::string& configuration, const std::string& platform); +} /// @} //--------------------------------------------------------------------------- #endif // importprojectH diff --git a/lib/json.h b/lib/json.h index 2bcfe102071..7f7107f7864 100644 --- a/lib/json.h +++ b/lib/json.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +28,7 @@ SUPPRESS_WARNING_CLANG_PUSH("-Wextra-semi-stmt") SUPPRESS_WARNING_CLANG_PUSH("-Wzero-as-null-pointer-constant") SUPPRESS_WARNING_CLANG_PUSH("-Wformat") SUPPRESS_WARNING_CLANG_PUSH("-Wfloat-conversion") +SUPPRESS_WARNING_CLANG_PUSH("-Wimplicit-float-conversion") #define PICOJSON_USE_INT64 #include // IWYU pragma: export @@ -37,6 +38,7 @@ SUPPRESS_WARNING_CLANG_POP SUPPRESS_WARNING_CLANG_POP SUPPRESS_WARNING_CLANG_POP SUPPRESS_WARNING_CLANG_POP +SUPPRESS_WARNING_CLANG_POP SUPPRESS_WARNING_GCC_POP SUPPRESS_WARNING_POP diff --git a/lib/library.cpp b/lib/library.cpp index ad5ea13a3ed..7520944d8ad 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,10 +46,10 @@ struct Library::LibraryData { struct Platform { const PlatformType *platform_type(const std::string &name) const { - const auto it = utils::as_const(mPlatformTypes).find(name); + const auto it = mPlatformTypes.find(name); return (it != mPlatformTypes.end()) ? &(it->second) : nullptr; } - std::map mPlatformTypes; + std::unordered_map mPlatformTypes; }; class ExportedFunctions { @@ -123,9 +123,9 @@ struct Library::LibraryData std::map mDealloc; // deallocation functions std::map mRealloc; // reallocation functions std::unordered_map mNoReturn; // is function noreturn? - std::map mReturnValue; - std::map mReturnValueType; - std::map mReturnValueContainer; + std::unordered_map mReturnValue; + std::unordered_map mReturnValueType; + std::unordered_map mReturnValueContainer; std::map> mUnknownReturnValues; std::map mReportErrors; std::map mProcessAfterCode; @@ -137,7 +137,7 @@ struct Library::LibraryData std::map mReflection; // invocation of reflection std::unordered_map mPodTypes; // pod types std::map mPlatformTypes; // platform independent typedefs - std::map mPlatforms; // platform dependent typedefs + std::unordered_map mPlatforms; // platform dependent typedefs std::map, TypeCheck> mTypeChecks; std::unordered_map mNonOverlappingData; std::unordered_set mEntrypoints; @@ -194,12 +194,13 @@ Library::Error Library::load(const char exename[], const char path[], bool debug } const bool is_abs_path = Path::isAbsolute(path); + const bool is_rel_path = Path::isRelative(path); std::string fullfilename(path); // TODO: what if the extension is not .cfg? - // only append extension when we provide the library name and not a path - TODO: handle relative paths? - if (!is_abs_path && Path::getFilenameExtension(fullfilename).empty()) + // only append extension when we provide the library name and not a path + if (!is_abs_path && !is_rel_path && Path::getFilenameExtension(fullfilename).empty()) fullfilename += ".cfg"; std::string absolute_path; @@ -210,7 +211,7 @@ Library::Error Library::load(const char exename[], const char path[], bool debug tinyxml2::XMLError error = xml_LoadFile(doc, fullfilename.c_str()); if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) { // only perform further lookups when the given path was not absolute - if (!is_abs_path && error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) + if (!is_abs_path) { std::list cfgfolders; #ifdef FILESDIR @@ -619,6 +620,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) container.startPattern2 = startPattern; if (!endsWith(container.startPattern, '<')) container.startPattern2 += " !!::"; + container.startPatternHasStd = startsWith(container.startPattern2, "std :: "); } const char* const endPattern = node->Attribute("endPattern"); if (endPattern) @@ -1322,10 +1324,10 @@ const Library::ArgumentChecks * Library::getarg(const Token *ftok, int argnr) co const Function* func = nullptr; if (isNotLibraryFunction(ftok, &func)) return nullptr; - const auto it2 = utils::as_const(func->argumentChecks).find(argnr); + const auto it2 = func->argumentChecks.find(argnr); if (it2 != func->argumentChecks.cend()) return &it2->second; - const auto it3 = utils::as_const(func->argumentChecks).find(-1); + const auto it3 = func->argumentChecks.find(-1); if (it3 != func->argumentChecks.cend()) return &it3->second; return nullptr; @@ -1395,12 +1397,18 @@ const Library::Container* Library::detectContainerInternal(const Token* const ty break; } + const bool hasScope = typeStart->strAt(1) == "::"; + const bool bailIfHasStd = !withoutStd && !hasScope; + for (const std::pair & c : mData->mContainers) { const Container& container = c.second; if (container.startPattern.empty()) continue; - const int offset = (withoutStd && startsWith(container.startPattern2, "std :: ")) ? 7 : 0; + if (bailIfHasStd && container.startPatternHasStd) + continue; + + const int offset = (withoutStd && container.startPatternHasStd) ? 7 : 0; // If endPattern is undefined, it will always match, but itEndPattern has to be defined. if (detect != IteratorOnly && container.endPattern.empty()) { @@ -1562,8 +1570,7 @@ bool Library::isCompliantValidationExpression(const char* p) error |= (*(p + 1) == '-'); } else if (*p == ':') { - // cppcheck-suppress bitwiseOnBoolean - TODO: fix this - error |= range | (*(p + 1) == '.'); + error |= range || (*(p + 1) == '.'); range = true; has_dot = false; has_E = false; @@ -1577,8 +1584,7 @@ bool Library::isCompliantValidationExpression(const char* p) has_dot = false; has_E = false; } else if (*p == '.') { - // cppcheck-suppress bitwiseOnBoolean - TODO: fix this - error |= has_dot | (!std::isdigit(*(p + 1))); + error |= has_dot || (!std::isdigit(*(p + 1))); has_dot = true; } else if (*p == 'E' || *p == 'e') { error |= has_E; diff --git a/lib/library.h b/lib/library.h index b5b19a197b2..709a0db2b90 100644 --- a/lib/library.h +++ b/lib/library.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,6 @@ #include "config.h" #include "mathlib.h" #include "standards.h" -#include "utils.h" #include #include @@ -239,23 +238,24 @@ class CPPCHECKLIB Library { bool unstableErase{}; bool unstableInsert{}; bool view{}; + bool startPatternHasStd{}; Action getAction(const std::string& function) const { - const auto i = utils::as_const(functions).find(function); + const auto i = functions.find(function); if (i != functions.end()) return i->second.action; return Action::NO_ACTION; } Yield getYield(const std::string& function) const { - const auto i = utils::as_const(functions).find(function); + const auto i = functions.find(function); if (i != functions.end()) return i->second.yield; return Yield::NO_YIELD; } const std::string& getReturnType(const std::string& function) const { - const auto i = utils::as_const(functions).find(function); + const auto i = functions.find(function); return (i != functions.end()) ? i->second.returnType : mEmptyString; } @@ -481,7 +481,7 @@ class CPPCHECKLIB Library { std::string getFunctionName(const Token *ftok, bool &error) const; static const AllocFunc* getAllocDealloc(const std::map &data, const std::string &name) { - const auto it = utils::as_const(data).find(name); + const auto it = data.find(name); return (it == data.end()) ? nullptr : &it->second; } diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index f065d63a935..403662f4df2 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1224,7 +1224,7 @@ std::string MathLib::calculate(const std::string &first, const std::string &seco return MathLib::toString(MathLib::toBigNumber(first) ^ MathLib::toBigNumber(second)) + intsuffix(first, second); default: - throw InternalError(nullptr, std::string("Unexpected action '") + action + "' in MathLib::calculate(). Please report this to Cppcheck developers."); + throw InternalError(nullptr, std::string("Unexpected action '") + action + "' in MathLib::calculate()."); } } diff --git a/lib/mathlib.h b/lib/mathlib.h index d4cc344ee7a..9b6b304501c 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -75,7 +75,7 @@ class CPPCHECKLIB MathLib { } /** - * @throws InternalError thrown on invalid/unhandled calculation or divison by zero + * @throws InternalError thrown on invalid/unhandled calculation or division by zero */ static value calc(char op, const value &v1, const value &v2); int compare(const value &v) const; @@ -138,7 +138,7 @@ class CPPCHECKLIB MathLib { static std::string subtract(const std::string & first, const std::string & second); static std::string multiply(const std::string & first, const std::string & second); /** - * @throws InternalError thrown on overflow or divison by zero + * @throws InternalError thrown on overflow or division by zero */ static std::string divide(const std::string & first, const std::string & second); /** diff --git a/lib/path.cpp b/lib/path.cpp index 4f18192c7c0..caa45898f99 100644 --- a/lib/path.cpp +++ b/lib/path.cpp @@ -189,6 +189,12 @@ bool Path::isAbsolute(const std::string& path) #endif } +bool Path::isRelative(const std::string& path) +{ + const std::string p = fromNativeSeparators(path); + return (p.find('/') != std::string::npos) && !isAbsolute(path); +} + std::string Path::getRelativePath(const std::string& absolutePath, const std::vector& basePaths) { for (const std::string &bp : basePaths) { @@ -387,7 +393,7 @@ std::string Path::getAbsoluteFilePath(const std::string& filePath) if (absolute) absolute_path = absolute; free(absolute); - // only throw on realpath() fialure to resolve a path when the given one was non-existent + // only throw on realpath() failure to resolve a path when the given one was non-existent if (!spath.empty() && absolute_path.empty() && !exists(spath)) throw std::runtime_error("path '" + filePath + "' does not exist"); #else @@ -458,3 +464,8 @@ std::string Path::join(std::string path1, std::string path2) return path2; return ((path1.back() == '/') ? path1 : (path1 + "/")) + path2; } + +std::string Path::join(std::string path1, std::string path2, std::string path3) +{ + return Path::join(Path::join(std::move(path1), std::move(path2)), std::move(path3)); +} diff --git a/lib/path.h b/lib/path.h index 23db06c4e50..22bfcf667f3 100644 --- a/lib/path.h +++ b/lib/path.h @@ -118,6 +118,13 @@ class CPPCHECKLIB Path { */ static bool isAbsolute(const std::string& path); + /** + * @brief Check if given path is relative + * @param path Path to check + * @return true if given path is relative + */ + static bool isRelative(const std::string& path); + /** * @brief Create a relative path from an absolute one, if absolute path is inside the basePaths. * @param absolutePath Path to be made relative. @@ -206,6 +213,13 @@ class CPPCHECKLIB Path { * @return the joined path with normalized slashes */ static std::string join(std::string path1, std::string path2); + + /** + * @brief join 3 paths with '/' separators + * if path2 is an absolute path path1 will be dismissed. + * @return the joined path with normalized slashes + */ + static std::string join(std::string path1, std::string path2, std::string path3); }; /// @} diff --git a/lib/pathmatch.cpp b/lib/pathmatch.cpp index 5dd11e1d755..87420828f17 100644 --- a/lib/pathmatch.cpp +++ b/lib/pathmatch.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -145,7 +145,7 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const continue; } - /* No more path seperators to try from */ + /* No more path separators to try from */ return false; } } diff --git a/lib/pathmatch.h b/lib/pathmatch.h index b89ddcbe40b..72fc89b7faa 100644 --- a/lib/pathmatch.h +++ b/lib/pathmatch.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -169,10 +169,10 @@ class CPPCHECKLIB PathMatch { return pattern; } -private: - friend class TestPathMatch; +protected: class PathIterator; +private: /* List of patterns */ std::vector mPatterns; /* Base path to with patterns and paths are relative */ @@ -274,9 +274,9 @@ class PathMatch::PathIterator { /* Position struct */ struct Pos { /* String pointer */ - const char *p; + const char *p{}; /* Raw characters left */ - std::size_t l; + std::size_t l{}; /* Buffered character */ int c {EOF}; }; @@ -324,7 +324,7 @@ class PathMatch::PathIterator { return c == '/' || (syntax == Syntax::windows && c == '\\'); } - /* Syntax helper, check if a chracter is a drive letter */ + /* Syntax helper, check if a character is a drive letter */ static bool isdrive(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); diff --git a/lib/platform.cpp b/lib/platform.cpp index 85614c6ea29..0e202b9f49a 100644 --- a/lib/platform.cpp +++ b/lib/platform.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,6 +40,7 @@ bool Platform::set(Type t) case Type::Unspecified: // unknown type sizes (sizes etc are set but are not known) case Type::Native: // same as system this code was compile on type = t; + windows = false; sizeof_bool = sizeof(bool); sizeof_short = sizeof(short); sizeof_int = sizeof(int); @@ -62,6 +63,7 @@ bool Platform::set(Type t) case Type::Win32W: case Type::Win32A: type = t; + windows = true; sizeof_bool = 1; // 4 in Visual C++ 4.2 sizeof_short = 2; sizeof_int = 4; @@ -79,6 +81,7 @@ bool Platform::set(Type t) return true; case Type::Win64: type = t; + windows = true; sizeof_bool = 1; sizeof_short = 2; sizeof_int = 4; @@ -96,6 +99,7 @@ bool Platform::set(Type t) return true; case Type::Unix32: type = t; + windows = false; sizeof_bool = 1; sizeof_short = 2; sizeof_int = 4; @@ -113,6 +117,7 @@ bool Platform::set(Type t) return true; case Type::Unix64: type = t; + windows = false; sizeof_bool = 1; sizeof_short = 2; sizeof_int = 4; @@ -138,6 +143,7 @@ bool Platform::set(Type t) bool Platform::set(const std::string& platformstr, std::string& errstr, const std::vector& paths, bool debug) { + // TODO: needs to be invalidated in case it was already set if (platformstr == "win32A") set(Type::Win32A); else if (platformstr == "win32W") @@ -170,11 +176,12 @@ bool Platform::loadFromFile(const std::vector& paths, const std::st std::cout << "looking for platform '" + filename + "'" << std::endl; const bool is_abs_path = Path::isAbsolute(filename); + const bool is_rel_path = Path::isRelative(filename); std::string fullfilename(filename); // TODO: what if extension is not .xml? // only append extension when we provide the library name is not a path - TODO: handle relative paths? - if (!is_abs_path && Path::getFilenameExtension(fullfilename).empty()) + if (!is_abs_path && !is_rel_path && Path::getFilenameExtension(fullfilename).empty()) fullfilename += ".xml"; // TODO: use native separators @@ -231,6 +238,14 @@ bool Platform::loadFromFile(const std::vector& paths, const std::st return loadFromXmlDocument(&doc); } +static const char* xmlText(const tinyxml2::XMLElement* node, bool& error) +{ + const char* const str = node->GetText(); + if (!str) + error = true; + return str; +} + static unsigned int xmlTextAsUInt(const tinyxml2::XMLElement* node, bool& error) { unsigned int retval = 0; @@ -239,6 +254,14 @@ static unsigned int xmlTextAsUInt(const tinyxml2::XMLElement* node, bool& error) return retval; } +static unsigned int xmlTextAsBool(const tinyxml2::XMLElement* node, bool& error) +{ + bool retval = false; + if (node->QueryBoolText(&retval) != tinyxml2::XML_SUCCESS) + error = true; + return retval; +} + bool Platform::loadFromXmlDocument(const tinyxml2::XMLDocument *doc) { const tinyxml2::XMLElement * const rootnode = doc->FirstChildElement(); @@ -250,11 +273,9 @@ bool Platform::loadFromXmlDocument(const tinyxml2::XMLDocument *doc) for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) { const char* name = node->Name(); if (std::strcmp(name, "default-sign") == 0) { - const char* str = node->GetText(); - if (str) + const char * const str = xmlText(node, error); + if (!error) defaultSign = *str; - else - error = true; } else if (std::strcmp(name, "char_bit") == 0) char_bit = xmlTextAsUInt(node, error); else if (std::strcmp(name, "sizeof") == 0) { @@ -284,6 +305,9 @@ bool Platform::loadFromXmlDocument(const tinyxml2::XMLDocument *doc) sizeof_wchar_t = xmlTextAsUInt(sz, error); } } + else if (std::strcmp(node->Name(), "windows") == 0) { + windows = xmlTextAsBool(node, error); + } } calculateBitMembers(); type = Type::File; diff --git a/lib/platform.h b/lib/platform.h index 4673c4859e6..97e7d296fba 100644 --- a/lib/platform.h +++ b/lib/platform.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ #include "config.h" #include "mathlib.h" #include "standards.h" +#include "utils.h" #include #include #include #include -#include #include #include @@ -132,6 +132,8 @@ class CPPCHECKLIB Platform { char defaultSign; // unsigned:'u', signed:'s', unknown:'\0' + bool windows{false}; // indicates if the platform is Windows + enum Type : std::uint8_t { Unspecified, // No platform specified Native, // whatever system this code was compiled on @@ -167,9 +169,7 @@ class CPPCHECKLIB Platform { * @return true if Windows platform type. */ bool isWindows() const { - return type == Type::Win32A || - type == Type::Win32W || - type == Type::Win64; + return windows; } const char *toString() const { @@ -194,9 +194,8 @@ class CPPCHECKLIB Platform { return "unix64"; case Type::File: return "platformFile"; - default: - throw std::runtime_error("unknown platform"); } + cppcheck::unreachable(); } long long unsignedCharMax() const { diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 123ef5ca898..4246da39c83 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include "errorlogger.h" #include "errortypes.h" #include "library.h" +#include "mathlib.h" #include "path.h" #include "platform.h" #include "settings.h" @@ -71,15 +72,13 @@ Preprocessor::Preprocessor(simplecpp::TokenList& tokens, const Settings& setting namespace { struct BadInlineSuppression { - BadInlineSuppression(std::string file, const int line, unsigned int col, std::string msg) : file(std::move(file)), line(line), col(col), errmsg(std::move(msg)) {} - std::string file; - int line; // TODO: needs to be unsigned - unsigned int col; + BadInlineSuppression(const simplecpp::Location& loc, std::string msg) : location(loc), errmsg(std::move(msg)) {} + simplecpp::Location location; std::string errmsg; }; } -static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &tokens, const simplecpp::Token *tok, std::list &inlineSuppressions, std::list &bad) +static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std::list &inlineSuppressions, std::list &bad) { const std::string cppchecksuppress("cppcheck-suppress"); @@ -92,7 +91,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token if (comment.substr(pos1, cppchecksuppress.size()) != cppchecksuppress) return false; if (pos1 + cppchecksuppress.size() >= comment.size()) { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "suppression without error ID"); + bad.emplace_back(tok->location, "suppression without error ID"); return false; } @@ -102,7 +101,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token // skip spaces after "cppcheck-suppress" and its possible prefix const std::string::size_type pos2 = comment.find_first_not_of(' ', posEndComment); if (pos2 == std::string::npos) { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "suppression without error ID"); + bad.emplace_back(tok->location, "suppression without error ID"); return false; } @@ -112,7 +111,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token if (posEndComment >= (pos1 + cppchecksuppress.size() + 1)) { const std::string suppressCmdString = comment.substr(pos1, pos2-pos1-1); if (comment.at(pos1 + cppchecksuppress.size()) != '-') { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "unknown suppression type '" + suppressCmdString + "'"); // TODO: set column + bad.emplace_back(tok->location, "unknown suppression type '" + suppressCmdString + "'"); return false; } @@ -131,7 +130,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token else if ("macro" == suppressTypeString) errorType = SuppressionList::Type::macro; else { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "unknown suppression type '" + suppressCmdString + "'"); // TODO: set column + bad.emplace_back(tok->location, "unknown suppression type '" + suppressCmdString + "'"); return false; } } @@ -145,11 +144,12 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token s.isInline = true; s.type = errorType; s.lineNumber = tok->location.line; + s.column = tok->location.col; } // TODO: return false? if (!errmsg.empty()) - bad.emplace_back(tokens.file(tok->location), tok->location.line, tok->location.col, std::move(errmsg)); + bad.emplace_back(tok->location, std::move(errmsg)); // TODO: report ones without ID - return false? std::copy_if(suppressions.cbegin(), suppressions.cend(), std::back_inserter(inlineSuppressions), [](const SuppressionList::Suppression& s) { @@ -165,6 +165,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token s.isInline = true; s.type = errorType; s.lineNumber = tok->location.line; + s.column = tok->location.col; // TODO: report when no ID - unreachable? if (!s.errorId.empty()) @@ -173,7 +174,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token // TODO: unreachable? // TODO: return false? if (!errmsg.empty()) - bad.emplace_back(tokens.file(tok->location), tok->location.line, tok->location.col, std::move(errmsg)); + bad.emplace_back(tok->location, std::move(errmsg)); } return true; @@ -200,6 +201,8 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett bool onlyComments = true; + polyspace::Parser polyspaceParser(settings); + for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) { if (!tok->comment) { onlyComments = false; @@ -207,20 +210,24 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } std::list inlineSuppressions; - if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad)) - continue; + if (polyspace::isPolyspaceComment(tok->str())) { + inlineSuppressions = polyspaceParser.parse(tok->str(), tok->location.line, getRelativeFilename(tokens, tok, settings)); + } else { + if (!parseInlineSuppressionCommentToken(tok, inlineSuppressions, bad)) + continue; - if (!sameline(tok->previous, tok)) { - // find code after comment.. - if (tok->next) { - tok = tok->next; + if (!sameline(tok->previous, tok)) { + // find code after comment.. + if (tok->next) { + tok = tok->next; - while (tok->comment) { - parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad); - if (tok->next) { - tok = tok->next; - } else { - break; + while (tok->comment) { + parseInlineSuppressionCommentToken(tok, inlineSuppressions, bad); + if (tok->next) { + tok = tok->next; + } else { + break; + } } } } @@ -248,9 +255,11 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett // Add the suppressions. for (SuppressionList::Suppression &suppr : inlineSuppressions) { suppr.fileName = relativeFilename; + suppr.fileIndex = tok->location.fileIndex; - if (SuppressionList::Type::blockBegin == suppr.type) - { + if (SuppressionList::Type::block == suppr.type) { + suppressions.addSuppression(std::move(suppr)); + } else if (SuppressionList::Type::blockBegin == suppr.type) { inlineSuppressionsBlockBegin.push_back(std::move(suppr)); } else if (SuppressionList::Type::blockEnd == suppr.type) { bool throwError = true; @@ -270,6 +279,7 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett suppr.lineBegin = supprBegin->lineNumber; suppr.lineEnd = suppr.lineNumber; suppr.lineNumber = supprBegin->lineNumber; + suppr.column = supprBegin->column; suppr.type = SuppressionList::Type::block; inlineSuppressionsBlockBegin.erase(supprBegin); suppressions.addSuppression(std::move(suppr)); // TODO: check result @@ -281,8 +291,12 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } if (throwError) { + simplecpp::Location loc; // NOLINTNEXTLINE(bugprone-use-after-move) - moved only when thrownError is false - bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "Suppress End: No matching begin"); // TODO: set column + loc.fileIndex = suppr.fileIndex; + loc.line = suppr.lineNumber; + loc.col = suppr.column; + bad.emplace_back(loc, "Suppress End: No matching begin"); } } else if (SuppressionList::Type::unique == suppr.type || suppr.type == SuppressionList::Type::macro) { // special handling when suppressing { warnings for backwards compatibility @@ -296,20 +310,30 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett suppr.thisAndNextLine = thisAndNextLine; suppr.lineNumber = tok->location.line; + suppr.column = tok->location.col; suppr.macroName = macroName; suppressions.addSuppression(std::move(suppr)); // TODO: check result } else if (SuppressionList::Type::file == suppr.type) { if (onlyComments) suppressions.addSuppression(std::move(suppr)); // TODO: check result - else - bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "File suppression should be at the top of the file"); // TODO: set column + else { + simplecpp::Location loc; + loc.fileIndex = suppr.fileIndex; + loc.line = suppr.lineNumber; + loc.col = suppr.column; + bad.emplace_back(loc, "File suppression should be at the top of the file"); + } } } } - for (const SuppressionList::Suppression & suppr: inlineSuppressionsBlockBegin) - // cppcheck-suppress useStlAlgorithm - bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "Suppress Begin: No matching end"); // TODO: set column + for (const SuppressionList::Suppression & suppr: inlineSuppressionsBlockBegin) { + simplecpp::Location loc; + loc.fileIndex = suppr.fileIndex; + loc.line = suppr.lineNumber; + loc.col = suppr.column; + bad.emplace_back(loc, "Suppress Begin: No matching end"); + } } void Preprocessor::inlineSuppressions(SuppressionList &suppressions) @@ -322,7 +346,7 @@ void Preprocessor::inlineSuppressions(SuppressionList &suppressions) ::addInlineSuppressions(filedata->tokens, mSettings, suppressions, err); } for (const BadInlineSuppression &bad : err) { - invalidSuppression(bad.file, bad.line, bad.col, bad.errmsg); // TODO: column is always 0 + invalidSuppression(bad.location, bad.errmsg); } } @@ -413,39 +437,75 @@ static std::string readcondition(const simplecpp::Token *iftok, const std::setname && (next1->str() == "==" || next1->str() == "<=" || next1->str() == ">=") && next2->number) { if (defined.find(cond->str()) == defined.end()) - return cond->str() + '=' + cond->next->next->str(); + return cond->str() + '=' + next1->next->str(); } + const auto lessGreaterThanConfig = [](const simplecpp::Token* dtok, const simplecpp::Token* ctok) { + auto v = MathLib::toBigNumber(ctok->next->str()); + if (ctok->op == '<') + v -= 1; + else + v += 1; + return dtok->str() + '=' + std::to_string(v); + }; + if (len == 3 && cond->name && (next1->op == '<' || next1->op == '>') && next2->number) { if (defined.find(cond->str()) == defined.end()) { - int v = strToInt(cond->next->next->str()); - if (next1->op == '<') - v -= 1; - else - v += 1; - return cond->str() + '=' + std::to_string(v); + return lessGreaterThanConfig(cond, next1); } } std::set configset; + bool isNotDefinedMacro = false; for (; sameline(iftok,cond); cond = cond->next) { if (cond->op == '!') { if (!sameline(iftok,cond->next) || !cond->next->name) break; - if (cond->next->str() == "defined") + if (cond->next->str() == "defined") { + isNotDefinedMacro = true; continue; + } configset.insert(cond->next->str() + "=0"); continue; } - if (cond->str() != "defined") + if (cond->str() == "==" || cond->str() == "<=" || cond->str() == ">=") { + if (!cond->next) + break; + if (cond->next->number) { + const simplecpp::Token *dtok = cond->previous; + if (sameline(iftok,dtok) && dtok->name && defined.find(dtok->str()) == defined.end() && undefined.find(dtok->str()) == undefined.end()) + configset.insert(dtok->str() + '=' + cond->next->str()); + } continue; - const simplecpp::Token *dtok = cond->next; - if (!dtok) - break; - if (dtok->op == '(') - dtok = dtok->next; - if (sameline(iftok,dtok) && dtok->name && defined.find(dtok->str()) == defined.end() && undefined.find(dtok->str()) == undefined.end()) - configset.insert(dtok->str()); + } + if (cond->op == '<' || cond->op == '>') { + if (!cond->next) + break; + if (cond->next->number) { + const simplecpp::Token *dtok = cond->previous; + if (sameline(iftok,dtok) && dtok->name && defined.find(dtok->str()) == defined.end() && undefined.find(dtok->str()) == undefined.end()) { + configset.insert(lessGreaterThanConfig(dtok, cond)); + } + } + continue; + } + if (cond->str() == "defined") { + const simplecpp::Token *dtok = cond->next; + if (!dtok) + break; + if (dtok->op == '(') + dtok = dtok->next; + + if (sameline(iftok,dtok) && dtok->name && defined.find(dtok->str()) == defined.end() && undefined.find(dtok->str()) == undefined.end()) { + if (!isNotDefinedMacro) { + configset.insert(dtok->str() + "=" + dtok->str()); // if defined is set to itself. + } else { + configset.insert(dtok->str()); + } + isNotDefinedMacro = false; + } + continue; + } } std::string cfgStr; for (const std::string &s : configset) { @@ -456,18 +516,19 @@ static std::string readcondition(const simplecpp::Token *iftok, const std::set const simplecpp::Token *expr1 = cmdtok->next; if (sameline(tok,expr1) && expr1->name && !sameline(tok,expr1->next)) config = expr1->str(); - if (defined.find(config) != defined.end()) + if (defined.find(config) != defined.end()) { config.clear(); + } else if ((cmdtok->str() == "ifdef") && sameline(cmdtok,expr1) && !config.empty()) { + config.append("=" + expr1->str()); //Set equal to itself if ifdef. + } } else if (cmdtok->str() == "if") { config = readcondition(cmdtok, defined, undefined); } @@ -594,6 +658,24 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set } } + // check if config already exists in the ret set, but as a more general or more specific version + if (cmdtok->str() != "ifndef") + { + const std::string::size_type eq = config.find('='); + const std::string config2 = (eq != std::string::npos) ? config.substr(0, eq) : config + "=" + config; + const std::set::iterator it2 = ret.find(config2); + if (it2 != ret.end()) { + if (eq == std::string::npos) { + // The instance in ret is more specific than the one in config (no =value), replace it with the one in config + ret.erase(it2); + } else { + // The instance in ret is more general than the one in config (have =value), keep the one in ret + config.clear(); + continue; + } + } + } + configs_if.push_back((cmdtok->str() == "ifndef") ? std::string() : config); configs_ifndef.push_back((cmdtok->str() == "ifndef") ? std::move(config) : std::string()); ret.insert(cfg(configs_if,userDefines)); @@ -627,8 +709,18 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set configs_if.push_back(std::move(config)); ret.insert(cfg(configs_if, userDefines)); } else if (!configs_ifndef.empty()) { - configs_if.push_back(configs_ifndef.back()); - ret.insert(cfg(configs_if, userDefines)); + //Check if ifndef already existing in ret as more general/specific version + const std::string &confCandidate = configs_ifndef.back(); + if (ret.find(confCandidate) == ret.end()) { + // No instance of config_ifndef in ret. Check if a more specific version exists, in that case replace it + const std::set::iterator it = ret.find(confCandidate + "=" + confCandidate); + if (it != ret.end()) { + // The instance in ret is more specific than the one in confCandidate (no =value), replace it with the one in confCandidate + ret.erase(it); + } + configs_if.push_back(configs_ifndef.back()); + ret.insert(cfg(configs_if, userDefines)); + } } } else if (cmdtok->str() == "endif" && !sameline(tok, cmdtok->next)) { if (!configs_if.empty()) @@ -709,11 +801,11 @@ std::set Preprocessor::getConfigs() const return ret; } -static void splitcfg(const std::string &cfg, std::list &defines, const std::string &defaultValue) +static void splitcfg(const std::string &cfgStr, std::list &defines, const std::string &defaultValue) { - for (std::string::size_type defineStartPos = 0U; defineStartPos < cfg.size();) { - const std::string::size_type defineEndPos = cfg.find(';', defineStartPos); - std::string def = (defineEndPos == std::string::npos) ? cfg.substr(defineStartPos) : cfg.substr(defineStartPos, defineEndPos - defineStartPos); + for (std::string::size_type defineStartPos = 0U; defineStartPos < cfgStr.size();) { + const std::string::size_type defineEndPos = cfgStr.find(';', defineStartPos); + std::string def = (defineEndPos == std::string::npos) ? cfgStr.substr(defineStartPos) : cfgStr.substr(defineStartPos, defineEndPos - defineStartPos); if (!defaultValue.empty() && def.find('=') == std::string::npos) def += '=' + defaultValue; defines.push_back(std::move(def)); @@ -723,14 +815,14 @@ static void splitcfg(const std::string &cfg, std::list &defines, co } } -static simplecpp::DUI createDUI(const Settings &mSettings, const std::string &cfg, Standards::Language lang) +static simplecpp::DUI createDUI(const Settings &mSettings, const std::string &cfgStr, Standards::Language lang) { // TODO: make it possible to specify platform-dependent sizes simplecpp::DUI dui; splitcfg(mSettings.userDefines, dui.defines, "1"); - if (!cfg.empty()) - splitcfg(cfg, dui.defines, ""); + if (!cfgStr.empty()) + splitcfg(cfgStr, dui.defines, ""); for (const std::string &def : mSettings.library.defines()) { const std::string::size_type pos = def.find_first_of(" ("); @@ -811,9 +903,9 @@ void Preprocessor::setPlatformInfo() mTokens.sizeOfType["long double *"] = mSettings.platform.sizeof_pointer; } -simplecpp::TokenList Preprocessor::preprocess(const std::string &cfg, std::vector &files, simplecpp::OutputList& outputList) +simplecpp::TokenList Preprocessor::preprocess(const std::string &cfgStr, std::vector &files, simplecpp::OutputList& outputList) { - const simplecpp::DUI dui = createDUI(mSettings, cfg, mLang); + const simplecpp::DUI dui = createDUI(mSettings, cfgStr, mLang); std::list macroUsage; std::list ifCond; @@ -827,10 +919,10 @@ simplecpp::TokenList Preprocessor::preprocess(const std::string &cfg, std::vecto return tokens2; } -std::string Preprocessor::getcode(const std::string &cfg, std::vector &files, const bool writeLocations) +std::string Preprocessor::getcode(const std::string &cfgStr, std::vector &files, const bool writeLocations) { simplecpp::OutputList outputList; - simplecpp::TokenList tokens2 = preprocess(cfg, files, outputList); + simplecpp::TokenList tokens2 = preprocess(cfgStr, files, outputList); handleErrors(outputList); unsigned int prevfile = 0; unsigned int line = 1; @@ -865,7 +957,7 @@ const simplecpp::Output* Preprocessor::reportOutput(const simplecpp::OutputList case simplecpp::Output::ERROR: out_ret = &out; if (!startsWith(out.msg,"#error") || showerror) - error(mTokens.file(out.location), out.location.line, out.location.col, out.msg, out.type); + error(out.location, out.msg, out.type); break; case simplecpp::Output::WARNING: case simplecpp::Output::PORTABILITY_BACKSLASH: @@ -875,20 +967,20 @@ const simplecpp::Output* Preprocessor::reportOutput(const simplecpp::OutputList const std::string::size_type pos1 = out.msg.find_first_of("<\""); const std::string::size_type pos2 = out.msg.find_first_of(">\"", pos1 + 1U); if (pos1 < pos2 && pos2 != std::string::npos) - missingInclude(mTokens.file(out.location), out.location.line, out.location.col, out.msg.substr(pos1+1, pos2-pos1-1), out.msg[pos1] == '\"' ? UserHeader : SystemHeader); + missingInclude(out.location, out.msg.substr(pos1+1, pos2-pos1-1), out.msg[pos1] == '\"' ? UserHeader : SystemHeader); } break; case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY: case simplecpp::Output::SYNTAX_ERROR: case simplecpp::Output::UNHANDLED_CHAR_ERROR: out_ret = &out; - error(mTokens.file(out.location), out.location.line, out.location.col, out.msg, out.type); + error(out.location, out.msg, out.type); break; case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND: case simplecpp::Output::FILE_NOT_FOUND: case simplecpp::Output::DUI_ERROR: out_ret = &out; - error("", 0, 0, out.msg, out.type); + error({}, out.msg, out.type); break; } } @@ -909,8 +1001,9 @@ static std::string simplecppErrToId(simplecpp::Output::Type type) return "includeNestedTooDeeply"; case simplecpp::Output::FILE_NOT_FOUND: return "missingFile"; - // should never occur case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND: + return "missingIncludeExplicit"; + // should never occur case simplecpp::Output::DUI_ERROR: // handled separately case simplecpp::Output::MISSING_HEADER: @@ -923,20 +1016,20 @@ static std::string simplecppErrToId(simplecpp::Output::Type type) cppcheck::unreachable(); } -void Preprocessor::error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, simplecpp::Output::Type type) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) { - error(filename, linenr, col, msg, simplecppErrToId(type)); + error(loc, msg, simplecppErrToId(type)); } -void Preprocessor::error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, const std::string& id) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) { std::list locationList; - if (!filename.empty()) { - std::string file = Path::fromNativeSeparators(filename); + if (!mTokens.file(loc).empty()) { + std::string file = Path::fromNativeSeparators(mTokens.file(loc)); if (mSettings.relativePaths) file = Path::getRelativePath(file, mSettings.basePaths); - locationList.emplace_back(file, linenr, col); + locationList.emplace_back(file, loc.line, loc.col); } mErrorLogger.reportErr(ErrorMessage(std::move(locationList), mFile0, @@ -947,28 +1040,28 @@ void Preprocessor::error(const std::string &filename, unsigned int linenr, unsig } // Report that include is missing -void Preprocessor::missingInclude(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &header, HeaderTypes headerType) +void Preprocessor::missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType) { if (!mSettings.checks.isEnabled(Checks::missingInclude)) return; std::list locationList; - if (!filename.empty()) { + if (!mTokens.file(loc).empty()) { // TODO: add relative path handling? - locationList.emplace_back(filename, linenr, col); + locationList.emplace_back(mTokens.file(loc), loc.line, loc.col); } ErrorMessage errmsg(std::move(locationList), mFile0, Severity::information, (headerType==SystemHeader) ? - "Include file: <" + header + "> not found. Please note: Cppcheck does not need standard library headers to get proper results." : + "Include file: <" + header + "> not found. Please note: Standard library headers do not need to be provided to get proper results." : "Include file: \"" + header + "\" not found.", (headerType==SystemHeader) ? "missingIncludeSystem" : "missingInclude", Certainty::normal); mErrorLogger.reportErr(errmsg); } -void Preprocessor::invalidSuppression(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg) +void Preprocessor::invalidSuppression(const simplecpp::Location& loc, const std::string &msg) { - error(filename, linenr, col, msg, "invalidSuppression"); + error(loc, msg, "invalidSuppression"); } void Preprocessor::getErrorMessages(ErrorLogger &errorLogger, const Settings &settings) @@ -976,14 +1069,18 @@ void Preprocessor::getErrorMessages(ErrorLogger &errorLogger, const Settings &se std::vector files; simplecpp::TokenList tokens(files); Preprocessor preprocessor(tokens, settings, errorLogger, Standards::Language::CPP); - preprocessor.missingInclude("", 1, 2, "", UserHeader); - preprocessor.missingInclude("", 1, 2, "", SystemHeader); - preprocessor.error("", 1, 2, "message", simplecpp::Output::ERROR); - preprocessor.error("", 1, 2, "message", simplecpp::Output::SYNTAX_ERROR); - preprocessor.error("", 1, 2, "message", simplecpp::Output::UNHANDLED_CHAR_ERROR); - preprocessor.error("", 1, 2, "message", simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY); - preprocessor.error("", 1, 2, "message", simplecpp::Output::FILE_NOT_FOUND); - preprocessor.invalidSuppression("", 1, 2, "message"); + simplecpp::Location loc; + loc.line = 1; + loc.col = 2; + preprocessor.missingInclude(loc, "", UserHeader); + preprocessor.missingInclude(loc, "", SystemHeader); + preprocessor.error(loc, "message", simplecpp::Output::ERROR); + preprocessor.error(loc, "message", simplecpp::Output::SYNTAX_ERROR); + preprocessor.error(loc, "message", simplecpp::Output::UNHANDLED_CHAR_ERROR); + preprocessor.error(loc, "message", simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY); + preprocessor.error(loc, "message", simplecpp::Output::FILE_NOT_FOUND); + preprocessor.error(loc, "message", simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND); + preprocessor.invalidSuppression(loc, "message"); } void Preprocessor::dump(std::ostream &out) const diff --git a/lib/preprocessor.h b/lib/preprocessor.h index f8f213b13df..9daabbf6ca8 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -118,9 +118,9 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { void setPlatformInfo(); - simplecpp::TokenList preprocess(const std::string &cfg, std::vector &files, simplecpp::OutputList& outputList); + simplecpp::TokenList preprocess(const std::string &cfgStr, std::vector &files, simplecpp::OutputList& outputList); - std::string getcode(const std::string &cfg, std::vector &files, bool writeLocations); + std::string getcode(const std::string &cfgStr, std::vector &files, bool writeLocations); /** * Calculate HASH. Using toolinfo, tokens1, filedata. @@ -141,7 +141,7 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { const simplecpp::Output* reportOutput(const simplecpp::OutputList &outputList, bool showerror); - void error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, simplecpp::Output::Type type); + void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type); const simplecpp::Output* handleErrors(const simplecpp::OutputList &outputList); @@ -156,9 +156,9 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { SystemHeader }; - void missingInclude(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &header, HeaderTypes headerType); - void invalidSuppression(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg); - void error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, const std::string& id); + void missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType); + void invalidSuppression(const simplecpp::Location& loc, const std::string &msg); + void error(const simplecpp::Location& loc, const std::string &msg, const std::string& id); void addRemarkComments(const simplecpp::TokenList &tokens, std::vector &remarkComments) const; diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 750fd6653e0..92952152ca5 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -150,11 +150,11 @@ bool ProgramMemory::getContainerEmptyValue(nonneg int exprid, MathLib::bigint& r return false; } -void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual) +void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint value, bool equal) { ValueFlow::Value v(value); v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; - if (!isEqual) + if (!equal) v.valueKind = ValueFlow::Value::ValueKind::Impossible; setValue(expr, v); } @@ -194,7 +194,7 @@ void ProgramMemory::erase_if(const std::function& pred if (mValues->empty()) return; - // TODO: how to delay until we actuallly modify? + // TODO: how to delay until we actually modify? copyOnWrite(); for (auto it = mValues->begin(); it != mValues->end();) { @@ -205,7 +205,7 @@ void ProgramMemory::erase_if(const std::function& pred } } -void ProgramMemory::swap(ProgramMemory &pm) NOEXCEPT +void ProgramMemory::swap(ProgramMemory &pm) noexcept { mValues.swap(pm.mValues); } @@ -632,10 +632,6 @@ static MathLib::bigint asInt(const ValueFlow::Value& value) return value.isFloatValue() ? static_cast(value.floatValue) : value.intvalue; } -static std::string removeAssign(const std::string& assign) { - return std::string{assign.cbegin(), assign.cend() - 1}; -} - namespace { struct assign { template @@ -651,22 +647,23 @@ static bool isIntegralValue(const ValueFlow::Value& value) return value.isIntValue() || value.isIteratorValue() || value.isSymbolicValue(); } -static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value& lhs, const ValueFlow::Value& rhs) +static ValueFlow::Value evaluate(const Token* op, const ValueFlow::Value& lhs, const ValueFlow::Value& rhs, bool removeAssign = false) { + const std::string opStr = removeAssign ? op->str().substr(0, op->str().size() - 1) : op->str(); ValueFlow::Value result; if (lhs.isImpossible() && rhs.isImpossible()) return ValueFlow::Value::unknown(); if (lhs.isImpossible() || rhs.isImpossible()) { // noninvertible - if (contains({"%", "/", "&", "|"}, op)) + if (contains({"%", "/", "&", "|"}, opStr)) return ValueFlow::Value::unknown(); result.setImpossible(); } if (isNumericValue(lhs) && isNumericValue(rhs)) { if (lhs.isFloatValue() || rhs.isFloatValue()) { - result.valueType = ValueFlow::Value::ValueType::FLOAT; + result.valueType = op->isArithmeticalOp() ? ValueFlow::Value::ValueType::FLOAT : ValueFlow::Value::ValueType::INT; bool error = false; - result.floatValue = calculate(op, asFloat(lhs), asFloat(rhs), &error); + result.floatValue = calculate(opStr, asFloat(lhs), asFloat(rhs), &error); if (error) return ValueFlow::Value::unknown(); return result; @@ -678,12 +675,12 @@ static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value& // If not the same type then one must be int if (lhs.valueType != rhs.valueType && !lhs.isIntValue() && !rhs.isIntValue()) return ValueFlow::Value::unknown(); - const bool compareOp = contains({"==", "!=", "<", ">", ">=", "<="}, op); + const bool compareOp = op->isComparisonOp(); // Comparison must be the same type if (compareOp && lhs.valueType != rhs.valueType) return ValueFlow::Value::unknown(); // Only add, subtract, and compare for non-integers - if (!compareOp && !contains({"+", "-"}, op) && !lhs.isIntValue() && !rhs.isIntValue()) + if (!compareOp && !contains({"+", "-"}, opStr) && !lhs.isIntValue() && !rhs.isIntValue()) return ValueFlow::Value::unknown(); // Both can't be iterators for non-compare if (!compareOp && lhs.isIteratorValue() && rhs.isIteratorValue()) @@ -701,10 +698,10 @@ static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value& result.valueType = ValueFlow::Value::ValueType::INT; } bool error = false; - result.intvalue = calculate(op, lhs.intvalue, rhs.intvalue, &error); + result.intvalue = calculate(opStr, lhs.intvalue, rhs.intvalue, &error); if (error) return ValueFlow::Value::unknown(); - if (result.isImpossible() && op == "!=") { + if (result.isImpossible() && opStr == "!=") { if (isTrue(result)) { result.intvalue = 1; } else if (isFalse(result)) { @@ -1501,7 +1498,7 @@ namespace { if (!pm->hasValue(expr->astOperand1()->exprId())) return unknown(); ValueFlow::Value& lhs = pm->at(expr->astOperand1()->exprId()); - rhs = evaluate(removeAssign(expr->str()), lhs, rhs); + rhs = evaluate(expr, lhs, rhs, /*removeAssign*/ true); if (lhs.isIntValue()) ValueFlow::Value::visitValue(rhs, std::bind(assign{}, std::ref(lhs.intvalue), std::placeholders::_1)); else if (lhs.isFloatValue()) @@ -1565,7 +1562,7 @@ namespace { ValueFlow::Value rhs = execute(expr->astOperand2()); if (rhs.isUninitValue()) return unknown(); - ValueFlow::Value r = evaluate(expr->str(), lhs, rhs); + ValueFlow::Value r = evaluate(expr, lhs, rhs); if (expr->isComparisonOp() && (r.isUninitValue() || r.isImpossible())) { if (rhs.isIntValue() && !expr->astOperand1()->values().empty()) { std::vector result = infer(makeIntegralInferModel(), diff --git a/lib/programmemory.h b/lib/programmemory.h index adb0d1469ce..21350d86d36 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -79,11 +79,11 @@ struct ExprIdToken { return !(lhs < rhs); } - const Token& operator*() const NOEXCEPT { + const Token& operator*() const noexcept { return *tok; } - const Token* operator->() const NOEXCEPT { + const Token* operator->() const noexcept { return tok; } @@ -102,7 +102,7 @@ struct ExprIdToken { }; struct CPPCHECKLIB ProgramMemory { - using Map = std::unordered_map; + using Map = std::map; ProgramMemory() : mValues(new Map()) {} @@ -116,7 +116,7 @@ struct CPPCHECKLIB ProgramMemory { bool getContainerSizeValue(nonneg int exprid, MathLib::bigint& result) const; bool getContainerEmptyValue(nonneg int exprid, MathLib::bigint& result) const; - void setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual = true); + void setContainerSizeValue(const Token* expr, MathLib::bigint value, bool equal = true); void setUnknown(const Token* expr); @@ -128,7 +128,7 @@ struct CPPCHECKLIB ProgramMemory { void erase_if(const std::function& pred); - void swap(ProgramMemory &pm) NOEXCEPT; + void swap(ProgramMemory &pm) noexcept; void clear(); diff --git a/lib/regex.cpp b/lib/regex.cpp index 6ad9ad440b0..0c8b0c9f188 100644 --- a/lib/regex.cpp +++ b/lib/regex.cpp @@ -167,7 +167,7 @@ namespace { ~PcreRegex() override { if (mExtra) { - pcre_free(mExtra); + pcre_free_study(mExtra); mExtra = nullptr; } if (mRe) { @@ -177,7 +177,7 @@ namespace { } std::string compile(); - std::string match(const std::string& str, const MatchFn& match) const override; + std::string match(const std::string& str, const MatchFn& matchFn) const override; private: std::string mPattern; @@ -188,15 +188,15 @@ namespace { std::string PcreRegex::compile() { if (mRe) - return "pcre_compile failed: regular expression has already been compiled"; + return "regular expression has already been compiled"; const char *pcreCompileErrorStr = nullptr; int erroffset = 0; pcre * const re = pcre_compile(mPattern.c_str(),0,&pcreCompileErrorStr,&erroffset,nullptr); if (!re) { if (pcreCompileErrorStr) - return "pcre_compile failed: " + std::string(pcreCompileErrorStr); - return "pcre_compile failed: unknown error"; + return pcreCompileErrorStr; + return "unknown error"; } // Optimize the regex, but only if PCRE_CONFIG_JIT is available @@ -209,7 +209,7 @@ namespace { if (pcreStudyErrorStr) { // pcre_compile() worked, but pcre_study() returned an error. Free the resources allocated by pcre_compile(). pcre_free(re); - return "pcre_study failed: " + std::string(pcreStudyErrorStr); + return std::string(pcreStudyErrorStr) + " (pcre_study)"; } mExtra = pcreExtra; #endif @@ -219,10 +219,10 @@ namespace { return ""; } - std::string PcreRegex::match(const std::string& str, const MatchFn& match) const + std::string PcreRegex::match(const std::string& str, const MatchFn& matchFn) const { if (!mRe) - return "pcre_exec failed: regular expression has not been compiled yet"; + return "regular expression has not been compiled yet"; int pos = 0; int ovector[30]= {0}; @@ -231,12 +231,12 @@ namespace { if (pcreExecRet == PCRE_ERROR_NOMATCH) return ""; if (pcreExecRet < 0) { - return "pcre_exec failed (pos: " + std::to_string(pos) + "): " + pcreErrorCodeToString(pcreExecRet); + return pcreErrorCodeToString(pcreExecRet) + " (pos: " + std::to_string(pos) + ")"; } const auto pos1 = static_cast(ovector[0]); const auto pos2 = static_cast(ovector[1]); - match(pos1, pos2); + matchFn(pos1, pos2); // jump to the end of the match for the next pcre_exec pos = static_cast(pos2); @@ -246,10 +246,22 @@ namespace { } } -std::shared_ptr Regex::create(std::string pattern, std::string& err) +template +static T* createAndCompileRegex(std::string pattern, std::string& err) { - auto* regex = new PcreRegex(std::move(pattern)); + T* regex = new T(std::move(pattern)); err = regex->compile(); + return regex; +} + +std::shared_ptr Regex::create(std::string pattern, Engine engine, std::string& err) +{ + Regex* regex = nullptr; + if (engine == Engine::Pcre) + regex = createAndCompileRegex(std::move(pattern), err); + else { + err = "unknown regular expression engine"; + } if (!err.empty()) { delete regex; return nullptr; diff --git a/lib/regex.h b/lib/regex.h index 5d89dc52054..afe92d92d40 100644 --- a/lib/regex.h +++ b/lib/regex.h @@ -25,6 +25,7 @@ #include "config.h" +#include #include #include #include @@ -37,7 +38,13 @@ class CPPCHECKLIB Regex using MatchFn = std::function; virtual std::string match(const std::string& str, const MatchFn& matchFn) const = 0; - static std::shared_ptr create(std::string pattern, std::string& err); + enum class Engine : std::uint8_t + { + Unknown = 0, + Pcre = 1 + }; + + static std::shared_ptr create(std::string pattern, Engine engine, std::string& err); }; #endif // HAVE_RULES diff --git a/lib/reverseanalyzer.cpp b/lib/reverseanalyzer.cpp index 671426f5d2d..4afd2556a24 100644 --- a/lib/reverseanalyzer.cpp +++ b/lib/reverseanalyzer.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -110,8 +110,11 @@ namespace { { if (Token::simpleMatch(tok->tokAt(-2), "} else {")) tok = tok->linkAt(-2); - if (Token::simpleMatch(tok->previous(), ") {")) + if (Token::simpleMatch(tok->previous(), ") {")) { + if (Token::simpleMatch(tok->linkAt(-1)->astOperand2(), ";")) + return tok->linkAt(-1)->astOperand2(); return tok->linkAt(-1); + } if (Token::simpleMatch(tok->previous(), "do {")) return tok->previous(); return tok; @@ -232,7 +235,7 @@ namespace { if (!Token::Match(assignTop->astOperand1(), "%assign%")) { continueB &= updateRecursive(assignTop->astOperand1()); } - if (!assignTop->astParent()) + if (!assignTop->astParent() || Token::simpleMatch(assignTop->astParent(), ";")) break; assignTop = assignTop->astParent(); } @@ -298,13 +301,13 @@ namespace { if (!condTok) break; Analyzer::Action condAction = analyzeRecursive(condTok); + if (condAction.isModified()) + break; const bool inLoop = Token::Match(condTok->astTop()->previous(), "for|while ("); // Evaluate condition of for and while loops first if (inLoop) { if (Token::findmatch(tok->link(), "goto|break", tok)) break; - if (condAction.isModified()) - break; valueFlowGenericForward(condTok, analyzer, tokenlist, errorLogger, settings); } Token* thenEnd; diff --git a/lib/sarifreport.cpp b/lib/sarifreport.cpp index ce142430f54..38eb9ea96ca 100644 --- a/lib/sarifreport.cpp +++ b/lib/sarifreport.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/lib/sarifreport.h b/lib/sarifreport.h index 90667322b2f..6baf88cb04d 100644 --- a/lib/sarifreport.h +++ b/lib/sarifreport.h @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/lib/settings.cpp b/lib/settings.cpp index 8e4b8d2a6d4..080946e07bc 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,7 +21,6 @@ #include "path.h" #include "summaries.h" #include "suppressions.h" -#include "utils.h" #include "vfvalue.h" #include @@ -29,7 +28,6 @@ #include #include #include -#include #include #include "json.h" @@ -109,7 +107,7 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress } const picojson::object& obj = json.get(); { - const auto it = utils::as_const(obj).find("productName"); + const auto it = obj.find("productName"); if (it != obj.cend()) { const auto& v = it->second; if (!v.is()) @@ -118,7 +116,7 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress } } { - const auto it = utils::as_const(obj).find("manualUrl"); + const auto it = obj.find("manualUrl"); if (it != obj.cend()) { const auto& v = it->second; if (!v.is()) @@ -127,7 +125,7 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress } } { - const auto it = utils::as_const(obj).find("about"); + const auto it = obj.find("about"); if (it != obj.cend()) { const auto& v = it->second; if (!v.is()) @@ -136,7 +134,7 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress } } { - const auto it = utils::as_const(obj).find("addons"); + const auto it = obj.find("addons"); if (it != obj.cend()) { const auto& entry = it->second; if (!entry.is()) @@ -154,7 +152,7 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress } } { - const auto it = utils::as_const(obj).find("suppressions"); + const auto it = obj.find("suppressions"); if (it != obj.cend()) { const auto& entry = it->second; if (!entry.is()) @@ -171,7 +169,7 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress } } { - const auto it = utils::as_const(obj).find("safety"); + const auto it = obj.find("safety"); if (it != obj.cend()) { const auto& v = it->second; if (!v.is()) @@ -354,7 +352,6 @@ static const std::set autosarCheckers{ "bufferAccessOutOfBounds", "comparePointers", "constParameter", - "cstyleCast", "ctuOneDefinitionRuleViolation", "doubleFree", "duplInheritedMember", @@ -396,7 +393,6 @@ static const std::set autosarCheckers{ "unsignedLessThanZero", "unusedFunction", "unusedStructMember", - "unusedValue", "unusedVariable", "useInitializationList", "variableScope", @@ -459,6 +455,14 @@ static const std::set certCCheckers{ static const std::set certCppCheckers{ "IOWithoutPositioning", "accessMoved", + "argumentSize", + "arrayIndexOutOfBounds", + "arrayIndexOutOfBoundsCond", + "arrayIndexThenCheck", + "autoVariables", + "autovarInvalidDeallocation", + "bitwiseOnBoolean", + "bufferAccessOutOfBounds", "comparePointers", "containerOutOfBounds", "ctuOneDefinitionRuleViolation", @@ -466,25 +470,50 @@ static const std::set certCppCheckers{ "danglingReference", "danglingTempReference", "danglingTemporaryLifetime", - "deallocThrow", + "deallocret", "deallocuse", "doubleFree", "eraseDereference", + "exceptDeallocThrow", "exceptThrowInDestructor", + "floatConversionOverflow", "initializerList", + "integerOverflow", "invalidContainer", + "invalidFunctionArg", + "invalidLengthModifierError", + "invalidLifetime", + "invalidScanfFormatWidth", + "invalidscanf", + "leakReturnValNotUsed", + "leakUnsafeArgAlloc", "memleak", + "memleakOnRealloc", "mismatchAllocDealloc", "missingReturn", + "negativeIndex", "nullPointer", + "nullPointerArithmetic", + "nullPointerArithmeticRedundantCheck", + "nullPointerDefaultArg", + "nullPointerRedundantCheck", + "objectIndex", "operatorEqToSelf", + "pointerOutOfBounds", + "pointerOutOfBoundsCond", + "preprocessorErrorDirective", + "resourceLeak", "returnDanglingLifetime", "sizeofCalculation", + "stringLiteralWrite", "uninitStructMember", "uninitdata", "uninitvar", + "useClosedFile", "virtualCallInConstructor", - "virtualDestructor" + "virtualDestructor", + "wrongPrintfScanfArgNum", + "wrongPrintfScanfParameterPositionError" }; static const std::set misrac2012Checkers{ @@ -524,6 +553,7 @@ static const std::set misrac2012Checkers{ "unknownEvaluationOrder", "unreachableCode", "unreadVariable", + "unusedFunction", "unusedLabel", "unusedVariable", "useClosedFile", @@ -567,6 +597,7 @@ static const std::set misrac2023Checkers{ "unknownEvaluationOrder", "unreachableCode", "unreadVariable", + "unusedFunction", "unusedLabel", "unusedVariable", "useClosedFile", @@ -610,6 +641,7 @@ static const std::set misrac2025Checkers{ "unknownEvaluationOrder", "unreachableCode", "unreadVariable", + "unusedFunction", "unusedLabel", "unusedVariable", "useClosedFile", @@ -623,6 +655,7 @@ static const std::set misracpp2008Checkers{ "constVariable", "cstyleCast", "ctuOneDefinitionRuleViolation", + "dangerousTypeCast", "danglingLifetime", "duplInheritedMember", "duplicateBreak", @@ -704,6 +737,8 @@ static const std::set misracpp2023Checkers{ bool Settings::isPremiumEnabled(const char id[]) const { + if (premiumArgs.empty()) + return false; if (premiumArgs.find("autosar") != std::string::npos && autosarCheckers.count(id)) return true; if (premiumArgs.find("cert-c-") != std::string::npos && certCCheckers.count(id)) @@ -735,3 +770,18 @@ bool Settings::unusedFunctionOnly() const char* unusedFunctionOnly = std::getenv("UNUSEDFUNCTION_ONLY"); return unusedFunctionOnly && (std::strcmp(unusedFunctionOnly, "1") == 0); } + +bool Settings::collectLogCheckers(bool* summary, bool* xmlReport, bool* textReport) const +{ + const bool s = safety || severity.isEnabled(Severity::information); + if (summary) + *summary = s; + const bool x = outputFormat == Settings::OutputFormat::xml && xml_version == 3; + if (xmlReport) + *xmlReport = x; + const bool t = !checkersReportFilename.empty(); + if (textReport) + *textReport = t; + + return s || x || t; +} diff --git a/lib/settings.h b/lib/settings.h index 04541cda08c..6c12c509701 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,6 +40,8 @@ #include #include +#include "regex.h" + #if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) #include #endif @@ -51,7 +53,6 @@ class Regex; #endif struct Suppressions; -enum class ShowTime : std::uint8_t; namespace ValueFlow { class Value; } @@ -189,6 +190,9 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief Are we running from DACA script? */ bool daca{}; + /** @brief Is --debug-analyzerinfo given? */ + bool debugainfo{}; + /** @brief Is --debug-ast given? */ bool debugast{}; @@ -198,6 +202,9 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief Is --debug-ignore given? */ bool debugignore{}; + /** @brief Is --debug-ipc given? */ + bool debugipc{}; + /** @brief Internal: Is --debug-lookup or --debug-lookup=all given? */ bool debuglookup{}; @@ -368,6 +375,7 @@ class CPPCHECKLIB WARN_UNUSED Settings { std::string id = "rule"; // default id std::string summary; Severity severity = Severity::style; // default severity + Regex::Engine engine = Regex::Engine::Pcre; std::shared_ptr regex; }; @@ -436,6 +444,15 @@ class CPPCHECKLIB WARN_UNUSED Settings { SimpleEnableGroup certainty; SimpleEnableGroup checks; + enum class ShowTime : std::uint8_t { + NONE, + FILE, + FILE_TOTAL, + SUMMARY, + TOP5_SUMMARY, + TOP5_FILE + }; + /** @brief show timing information (--showtime=file|summary|top5) */ ShowTime showtime{}; @@ -474,7 +491,7 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief the maximum iterations to execute */ std::size_t maxIterations = 4; - /** @brief maximum numer if-branches */ + /** @brief maximum number if-branches */ int maxIfCount = -1; /** @brief maximum number of sets of arguments to pass to subfuncions */ @@ -579,6 +596,8 @@ class CPPCHECKLIB WARN_UNUSED Settings { static bool unusedFunctionOnly(); + bool collectLogCheckers(bool* summary = nullptr, bool* xmlReport = nullptr, bool* textReport = nullptr) const; + private: static std::string parseEnabled(const std::string &str, std::tuple, SimpleEnableGroup> &groups); std::string applyEnabled(const std::string &str, bool enable); diff --git a/lib/summaries.cpp b/lib/summaries.cpp index a543fcc7065..fa5399fd73d 100644 --- a/lib/summaries.cpp +++ b/lib/summaries.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "summaries.h" #include "analyzerinfo.h" +#include "path.h" #include "settings.h" #include "symboldatabase.h" #include "token.h" @@ -34,7 +35,7 @@ -std::string Summaries::create(const Tokenizer &tokenizer, const std::string &cfg, int fileIndex) +std::string Summaries::create(const Tokenizer &tokenizer, const std::string &cfg, std::size_t fsFileId) { const SymbolDatabase *symbolDatabase = tokenizer.getSymbolDatabase(); const Settings &settings = tokenizer.getSettings(); @@ -82,7 +83,7 @@ std::string Summaries::create(const Tokenizer &tokenizer, const std::string &cfg } if (!settings.buildDir.empty()) { - std::string filename = AnalyzerInformation::getAnalyzerInfoFile(settings.buildDir, tokenizer.list.getSourceFilePath(), cfg, fileIndex); + std::string filename = AnalyzerInformation::getAnalyzerInfoFile(settings.buildDir, Path::simplifyPath(tokenizer.list.getSourceFilePath()), cfg, fsFileId); const std::string::size_type pos = filename.rfind(".a"); if (pos != std::string::npos) { filename[pos+1] = 's'; diff --git a/lib/summaries.h b/lib/summaries.h index ac3d40d840f..d720d023306 100644 --- a/lib/summaries.h +++ b/lib/summaries.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,13 +23,14 @@ #include "config.h" +#include #include #include class Tokenizer; namespace Summaries { - CPPCHECKLIB std::string create(const Tokenizer &tokenizer, const std::string &cfg, int fileIndex); + CPPCHECKLIB std::string create(const Tokenizer &tokenizer, const std::string &cfg, std::size_t fsFileId); CPPCHECKLIB void loadReturn(const std::string &buildDir, std::set &summaryReturn); } diff --git a/lib/suppressions.cpp b/lib/suppressions.cpp index b91db635478..70b689e2cdb 100644 --- a/lib/suppressions.cpp +++ b/lib/suppressions.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,20 +18,22 @@ #include "suppressions.h" +#include "addoninfo.h" #include "errorlogger.h" #include "filesettings.h" #include "path.h" #include "pathmatch.h" #include "utils.h" #include "token.h" -#include "tokenize.h" #include "tokenlist.h" +#include "settings.h" #include #include // std::isdigit, std::isalnum, etc #include #include // std::bind, std::placeholders #include +#include #include #include "xml.h" @@ -204,9 +206,8 @@ std::vector SuppressionList::parseMultiSuppressCom return suppressions; } -SuppressionList::Suppression SuppressionList::parseLine(const std::string &line) +SuppressionList::Suppression SuppressionList::parseLine(std::string line) { - std::istringstream lineStream; SuppressionList::Suppression suppression; // Strip any end of line comments @@ -215,13 +216,18 @@ SuppressionList::Suppression SuppressionList::parseLine(const std::string &line) while (endpos > 0 && std::isspace(line[endpos-1])) { endpos--; } - lineStream.str(line.substr(0, endpos)); - } else { - lineStream.str(line); + line.resize(endpos); } - if (std::getline(lineStream, suppression.errorId, ':')) { - if (std::getline(lineStream, suppression.fileName)) { + const auto parts = splitString(line, '\n'); + const std::string& suppr_l = parts[0]; + + const std::string::size_type first_sep = suppr_l.find(':'); + suppression.errorId = suppr_l.substr(0, first_sep); + if (first_sep != std::string::npos) { + suppression.fileName = suppr_l.substr(first_sep+1); + if (!suppression.fileName.empty()) { + // TODO: this only works with files which have an extension // If there is not a dot after the last colon in "file" then // the colon is a separator and the contents after the colon // is a line number.. @@ -231,30 +237,48 @@ SuppressionList::Suppression SuppressionList::parseLine(const std::string &line) // if a colon is found and there is no dot after it.. if (pos != std::string::npos && - suppression.fileName.find('.', pos) == std::string::npos) { - // Try to parse out the line number - try { - std::istringstream istr1(suppression.fileName.substr(pos+1)); - istr1 >> suppression.lineNumber; - } catch (...) { - suppression.lineNumber = SuppressionList::Suppression::NO_LINE; - } + suppression.fileName.find('.', pos) == std::string::npos) + { + // parse out the line number + const std::string line_s = suppression.fileName.substr(pos+1); + suppression.fileName.erase(pos); + + if (suppression.fileName.empty()) + throw std::runtime_error("filename is missing"); - if (suppression.lineNumber != SuppressionList::Suppression::NO_LINE) { - suppression.fileName.erase(pos); + try { + suppression.lineNumber = strToInt(line_s); + } catch (const std::runtime_error& e) { + throw std::runtime_error(std::string("invalid line number (") + e.what() + ")"); } } + suppression.fileName = Path::simplifyPath(suppression.fileName); + } else { + throw std::runtime_error("filename is missing"); } } - suppression.fileName = Path::simplifyPath(suppression.fileName); + // TODO: make this optional - do we even encounter this in production code? + // when parsing string generated internally by toString() there can be newline + for (std::size_t i = 1; i < parts.size(); ++i) { + if (startsWith(parts[i], "symbol=")) + suppression.symbolName = parts[i].substr(7); + else if (parts[i] == "polyspace=1") + suppression.isPolyspace = true; + else + throw std::runtime_error("unexpected extra '" + parts[i] + "'"); + } return suppression; } std::string SuppressionList::addSuppressionLine(const std::string &line) { - return addSuppression(parseLine(line)); + try { + return addSuppression(parseLine(line)); + } catch (const std::exception& e) { + return e.what(); + } } std::string SuppressionList::addSuppression(SuppressionList::Suppression suppression) @@ -448,6 +472,7 @@ bool SuppressionList::isSuppressed(const SuppressionList::ErrorMessage &errmsg, { std::lock_guard lg(mSuppressionsSync); + // TODO: handle unmatchedPolyspaceSuppression? const bool unmatchedSuppression(errmsg.errorId == "unmatchedSuppression"); bool returnValue = false; for (Suppression &s : mSuppressions) { @@ -603,25 +628,25 @@ std::list SuppressionList::getSuppressions() const return mSuppressions; } -void SuppressionList::markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &tokenizer) { +void SuppressionList::markUnmatchedInlineSuppressionsAsChecked(const TokenList &tokenlist) { std::lock_guard lg(mSuppressionsSync); int currLineNr = -1; int currFileIdx = -1; - for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { + for (const Token *tok = tokenlist.front(); tok; tok = tok->next()) { if (currFileIdx != tok->fileIndex() || currLineNr != tok->linenr()) { currLineNr = tok->linenr(); currFileIdx = tok->fileIndex(); for (auto &suppression : mSuppressions) { if (suppression.type == SuppressionList::Type::unique) { - if (!suppression.checked && (suppression.lineNumber == currLineNr) && (suppression.fileName == tokenizer.list.file(tok))) { + if (!suppression.checked && (suppression.lineNumber == currLineNr) && (suppression.fileName == tokenlist.file(tok))) { suppression.checked = true; } } else if (suppression.type == SuppressionList::Type::block) { - if ((!suppression.checked && (suppression.lineBegin <= currLineNr) && (suppression.lineEnd >= currLineNr) && (suppression.fileName == tokenizer.list.file(tok)))) { + if ((!suppression.checked && (suppression.lineBegin <= currLineNr) && (suppression.lineEnd >= currLineNr) && (suppression.fileName == tokenlist.file(tok)))) { suppression.checked = true; } - } else if (!suppression.checked && suppression.fileName == tokenizer.list.file(tok)) { + } else if (!suppression.checked && suppression.fileName == tokenlist.file(tok)) { suppression.checked = true; } } @@ -632,7 +657,7 @@ void SuppressionList::markUnmatchedInlineSuppressionsAsChecked(const Tokenizer & std::string SuppressionList::Suppression::toString() const { std::string s; - s+= errorId; + s += errorId; if (!fileName.empty()) { s += ':'; s += fileName; @@ -641,9 +666,250 @@ std::string SuppressionList::Suppression::toString() const s += std::to_string(lineNumber); } } - if (!symbolName.empty()) { - s += ':'; - s += symbolName; - } + if (!symbolName.empty()) + s += "\nsymbol=" + symbolName; + if (isPolyspace) + s += "\npolyspace=1"; return s; } + +polyspace::Parser::Parser(const Settings &settings) +{ + const bool haveMisraAddon = std::any_of(settings.addonInfos.cbegin(), + settings.addonInfos.cend(), + [] (const AddonInfo &info) { + return info.name == "misra"; + }); + + if (haveMisraAddon) { + mFamilyMap["MISRA-C3"] = "misra-c2012-"; + mFamilyMap["MISRA2012"] = "misra-c2012-"; + } + + const auto matchArg = [&](const std::string &arg) { + const std::string args = settings.premiumArgs; + const std::string::size_type pos = args.find(arg); + + if (pos == std::string::npos) + return false; + + const char prevChar = (pos > 0) ? args[pos - 1] : ' '; + const char nextChar = (pos + arg.size() < args.size()) ? args[pos + arg.size()] : ' '; + + return prevChar == ' ' && (nextChar == ' ' || nextChar == ':'); + }; + + if (matchArg("--misra-c-2012")) { + mFamilyMap["MISRA-C3"] = "premium-misra-c-2012-"; + mFamilyMap["MISRA2012"] = "premium-misra-c-2012-"; + } + + if (matchArg("--misra-c-2023")) + mFamilyMap["MISRA-C-2023"] = "premium-misra-c-2023-"; + + if (matchArg("--misra-cpp-2008") || matchArg("--misra-c++-2008")) + mFamilyMap["MISRA-CPP"] = "premium-misra-cpp-2008-"; + + if (matchArg("--misra-cpp-2023") || matchArg("--misra-c++-2023")) + mFamilyMap["MISRA-CPP-2023"] = "premium-misra-cpp-2023-"; + + if (matchArg("--cert-c") || matchArg("--cert-c-2016")) + mFamilyMap["CERT-C"] = "premium-cert-c-"; + + if (matchArg("--cert-cpp") || matchArg("--cert-c++") || + matchArg("--cert-cpp-2016") || matchArg("--cert-c++-2016")) + mFamilyMap["CERT-CPP"] = "premium-cert-cpp-"; + + if (matchArg("--autosar")) + mFamilyMap["AUTOSAR-CPP14"] = "premium-autosar-"; +} + +polyspace::CommentKind polyspace::Parser::parseKind(const std::string& comment, std::string::size_type& pos) +{ + const std::string::size_type pos1 = pos; + pos = comment.find_first_of(" \t", pos); + if (pos >= comment.size()) + return CommentKind::Invalid; + + const std::string token = comment.substr(pos1, pos-pos1); + + if (token == "polyspace") + return CommentKind::Regular; + + if (token == "polyspace-begin") + return CommentKind::Begin; + + if (token == "polyspace-end") + return CommentKind::End; + + return CommentKind::Invalid; +} + + +std::list polyspace::Parser::parse(const std::string &comment, int line, const std::string &filename) const +{ + // Syntax for a polyspace suppression: + // https://se.mathworks.com/help/bugfinder/ug/annotate-hide-known-acceptable-polyspace-results-web-browser.html + + std::list ret; + + if (mFamilyMap.empty()) + return ret; + + for (std::string::size_type pos = comment.find_first_not_of("/* "); pos < comment.size();) { + // polyspace + const auto polyspaceKind = parseKind(comment, pos); + if (polyspaceKind == CommentKind::Invalid) + break; + + // optional range + const int rangeValue = parseRange(comment, pos); + + // ids.. + const std::set ids = parseIds(comment, pos); + + // skip justification + if (pos < comment.size() && comment[pos] == '[') { + pos = comment.find(']',pos+1); + if (pos >= comment.size()) + break; + pos = comment.find_first_not_of(" \t", pos+1); + if (pos >= comment.size()) + break; + } + + // extra comment + std::string extraComment; + if (pos < comment.size() && comment[pos] == '\"') { + const std::string::size_type p1 = pos + 1; + pos = comment.find('\"',p1); + if (pos >= comment.size()) + break; + extraComment = comment.substr(p1, pos-p1); + } + + for (const std::string& errorId: ids) { + SuppressionList::Suppression suppr; + suppr.errorId = errorId; + suppr.isInline = true; + suppr.isPolyspace = true; + suppr.fileName = filename; + suppr.lineNumber = line; + suppr.extraComment = extraComment; + + if (rangeValue > 0) { + suppr.type = SuppressionList::Type::block; + suppr.lineBegin = line; + suppr.lineEnd = line + rangeValue; + } + else if (polyspaceKind == polyspace::CommentKind::Regular) + suppr.type = SuppressionList::Type::unique; + else if (polyspaceKind == polyspace::CommentKind::Begin) + suppr.type = SuppressionList::Type::blockBegin; + else + suppr.type = SuppressionList::Type::blockEnd; + + ret.emplace_back(suppr); + } + + // proceed to next "polyspace" if it exists + if (pos < comment.size()) + pos = comment.find("polyspace", pos); + } + + return ret; +} + + +int polyspace::Parser::parseRange(const std::string& comment, std::string::size_type& pos) { + pos = comment.find_first_not_of(" \t", pos); + if (pos >= comment.size()) + return 0; + if (comment[pos] != '+') + return 0; + const std::string::size_type startpos = pos + 1; + std::string::size_type endpos = comment.find_first_of(" \t", startpos); + if (endpos > comment.size()) + return 0; + const std::string range = comment.substr(startpos, endpos-startpos); + try { + int ret = std::stoi(range); + pos = endpos; + return ret; + } catch (const std::invalid_argument &) {} + return 0; +} + +std::vector> polyspace::Parser::parseFamilyRules(const std::string& comment, std::string::size_type& pos) { + std::vector> fr; + std::string family; + std::string rule; + enum class State: uint8_t { family, colon, rule, rule_or_family } state = State::family; + const std::string::size_type endpos = startsWith(comment, "/*") ? comment.size() - 2 : comment.size(); + for (; pos <= endpos; ++pos) { + const char c = comment[pos]; + if (std::strchr("[\"", c)) + break; + switch (state) { + case State::family: + if (std::isalnum(c) || std::strchr("-_.",c)) + family += c; + else if (!family.empty() && std::strchr(" \t:",c)) + state = State::colon; + break; + case State::colon: + if (!std::strchr(" \t:", c)) { + rule.clear(); + --pos; + state = State::rule; + } + break; + case State::rule: + if (std::strchr(", \t",c)) { + if (!rule.empty()) { + fr.emplace_back(family,rule); + rule.clear(); + if (c != ',') + state = State::rule_or_family; + } + } + else + rule += c; + break; + case State::rule_or_family: + rule.clear(); + if (std::isalnum(c)) { + --pos; + family.clear(); + state = State::family; + } else if (c == ',') { + --pos; + state = State::rule; + } + break; + } + } + if (!family.empty() && !rule.empty()) + fr.emplace_back(family,rule); + return fr; +} + +std::set polyspace::Parser::parseIds(const std::string& comment, std::string::size_type& pos) const { + std::set ids; + for (const auto& fr: parseFamilyRules(comment,pos)) { + const auto it = mFamilyMap.find(fr.first); + if (it != mFamilyMap.cend()) + ids.emplace(it->second + fr.second); + } + return ids; +} + + +bool polyspace::isPolyspaceComment(const std::string &comment) +{ + const std::string polyspace = "polyspace"; + const std::string::size_type pos = comment.find_first_not_of("/* "); + if (pos == std::string::npos) + return false; + return comment.compare(pos, polyspace.size(), polyspace, 0, polyspace.size()) == 0; +} diff --git a/lib/suppressions.h b/lib/suppressions.h index 022a492c51f..849c972d0a7 100644 --- a/lib/suppressions.h +++ b/lib/suppressions.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,11 +31,13 @@ #include #include #include +#include -class Tokenizer; +class TokenList; class ErrorMessage; enum class Certainty : std::uint8_t; class FileWithDetails; +class Settings; /// @addtogroup Core /// @{ @@ -149,9 +151,12 @@ class CPPCHECKLIB SuppressionList { std::string errorId; std::string fileName; std::string extraComment; + // TODO: use simplecpp::Location? + int fileIndex{}; int lineNumber = NO_LINE; // TODO: needs to be unsigned int lineBegin = NO_LINE; int lineEnd = NO_LINE; + int column{}; Type type = Type::unique; std::string symbolName; std::string macroName; @@ -160,6 +165,7 @@ class CPPCHECKLIB SuppressionList { bool matched{}; /** This suppression was fully matched in an isSuppressed() call */ bool checked{}; /** This suppression applied to code which was being analyzed but did not match the error in an isSuppressed() call */ bool isInline{}; + bool isPolyspace{}; enum : std::int8_t { NO_LINE = -1 }; }; @@ -190,8 +196,9 @@ class CPPCHECKLIB SuppressionList { * Create a Suppression object from a suppression line * @param line The line to parse. * @return a suppression object + * @throws std::runtime_error thrown if the given suppression is invalid */ - static Suppression parseLine(const std::string &line); + static Suppression parseLine(std::string line); /** * @brief Don't show the given error. @@ -278,7 +285,7 @@ class CPPCHECKLIB SuppressionList { /** * @brief Marks Inline Suppressions as checked if source line is in the token stream */ - void markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &tokenizer); + void markUnmatchedInlineSuppressionsAsChecked(const TokenList &tokenlist); private: mutable std::mutex mSuppressionsSync; @@ -294,6 +301,34 @@ struct Suppressions SuppressionList nofail; }; +namespace polyspace { + + enum class CommentKind : std::uint8_t { + Invalid, Regular, Begin, End, + }; + + class CPPCHECKLIB Parser { + public: + Parser() = delete; + explicit Parser(const Settings &settings); + + std::list parse(const std::string &comment, int line, const std::string &filename) const; + + static int parseRange(const std::string& comment, std::string::size_type& pos); + static std::vector> parseFamilyRules(const std::string& comment, std::string::size_type& pos); + + private: + std::set parseIds(const std::string& comment, std::string::size_type& pos) const; + + static CommentKind parseKind(const std::string& comment, std::string::size_type& pos); + + std::map mFamilyMap; + }; + + bool CPPCHECKLIB isPolyspaceComment(const std::string &comment); + +} + /// @} //--------------------------------------------------------------------------- #endif // suppressionsH diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 1c77a365a1b..dda3e9b1e0b 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -160,6 +160,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() }; std::stack inIfCondition; + std::stack pendingIfScopes; auto addLambda = [this, &scope](const Token* tok, const Token* lambdaEndToken) -> const Token* { const Token* lambdaStartToken = lambdaEndToken->link(); @@ -174,8 +175,6 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() // Store current access in each scope (depends on evaluation progress) std::map access; - const bool doProgress = (mSettings.reportProgress != -1); - std::map> forwardDecls; const std::function findForwardDeclScope = [&](const Token *tok, Scope *startScope) { @@ -200,13 +199,14 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() return it->second.count(tok->str()) > 0 ? startScope : nullptr; }; + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, mTokenizer.list.getSourceFilePath(), "SymbolDatabase (find all scopes)"); + // find all scopes for (const Token *tok = mTokenizer.tokens(); tok; tok = tok ? tok->next() : nullptr) { // #5593 suggested to add here: - if (doProgress) - mErrorLogger.reportProgress(mTokenizer.list.getSourceFilePath(), - "SymbolDatabase", - tok->progressValue()); + + progressReporter.report(tok->progressValue()); + // Locate next class if ((tok->isCpp() && tok->isKeyword() && ((Token::Match(tok, "class|struct|union|namespace ::| %name% final| {|:|::|<") && @@ -714,7 +714,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() } // function prototype? else if (declEnd && declEnd->str() == ";") { - if (tok->astParent() && tok->astParent()->str() == "::" && + if ((Token::simpleMatch(tok->tokAt(-1), "::") || (tok->tokAt(-1) && Token::simpleMatch(tok->tokAt(-2), ":: ~"))) && Token::Match(declEnd->previous(), "default|delete")) { addClassFunction(scope, tok, argStart); continue; @@ -767,13 +767,14 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() scopeList.emplace_back(*this, tok, scope, ScopeType::eSwitch, scopeStartTok); scope->nestedList.push_back(&scopeList.back()); - scope = &scopeList.back(); - if (scope->type == ScopeType::eFor) - scope->checkVariable(tok->tokAt(2), AccessControl::Local); // check for variable declaration and add it to new scope if found - else if (scope->type == ScopeType::eCatch) - scope->checkVariable(tok->tokAt(2), AccessControl::Throw); // check for variable declaration and add it to new scope if found + Scope* newScope = &scopeList.back(); + if (newScope->type == ScopeType::eFor) + newScope->checkVariable(tok->tokAt(2), AccessControl::Local); // check for variable declaration and add it to new scope if found + else if (newScope->type == ScopeType::eCatch) + newScope->checkVariable(tok->tokAt(2), AccessControl::Throw); // check for variable declaration and add it to new scope if found tok = tok->next(); inIfCondition.push(scopeStartTok); + pendingIfScopes.push(newScope); } else if (Token::Match(tok, "%var% {")) { endInitList.emplace(tok->linkAt(1), scope); tok = tok->next(); @@ -784,6 +785,8 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() endInitList.emplace(tok->link(), scope); } else if (!inIfCondition.empty() && tok == inIfCondition.top()) { inIfCondition.pop(); + scope = pendingIfScopes.top(); + pendingIfScopes.pop(); } else if (isExecutableScope(tok)) { scopeList.emplace_back(*this, tok, scope, ScopeType::eUnconditional, tok); scope->nestedList.push_back(&scopeList.back()); @@ -1023,7 +1026,7 @@ void SymbolDatabase::createSymbolDatabaseNeedInitialization() if (var.isClass() && !var.isReference()) { if (var.type()) { // does this type need initialization? - if (var.type()->needInitialization == Type::NeedInitialization::True && !var.hasDefault() && !var.isStatic()) + if (var.type()->needInitialization == Type::NeedInitialization::True && !var.hasDefault()) needInitialization = true; else if (var.type()->needInitialization == Type::NeedInitialization::Unknown) { if (!(var.valueType() && var.valueType()->type == ValueType::CONTAINER)) @@ -1200,7 +1203,7 @@ void SymbolDatabase::createSymbolDatabaseSetFunctionPointers(bool firstPass) tok->function(function); - if (tok->strAt(1) != "(") + if (!function->isConstructor() && tok->strAt(1) != "(") const_cast(function)->functionPointerUsage = tok; } } @@ -1608,6 +1611,26 @@ static std::string getIncompleteNameID(const Token* tok) } namespace { + int getExprIdForOperand(const Token* tok) { + if (!tok) + return 0; + + int otherExprId = 0; + + // Look through all referenced tokens. + // If two exprIds are found and one matches tok->exprId(), return the other. + // Otherwise, default to returning tok->exprId(). + for (const auto& ref: followAllReferences(tok)) { + const int refExprId = ref.token->exprId(); + if (refExprId != 0 && refExprId != tok->exprId()) { + if (otherExprId != 0 && otherExprId != refExprId) + return tok->exprId(); + otherExprId = refExprId; + } + } + return otherExprId != 0 ? otherExprId : tok->exprId(); + } + struct ExprIdKey { std::string parentOp; nonneg int operand1; @@ -1642,8 +1665,8 @@ namespace { ExprIdKey key; key.parentOp = tok->astParent()->str(); - key.operand1 = op1 ? op1->exprId() : 0; - key.operand2 = op2 ? op2->exprId() : 0; + key.operand1 = getExprIdForOperand(op1); + key.operand2 = getExprIdForOperand(op2); if (tok->astParent()->isCast() && tok->astParent()->str() == "(") { const Token* typeStartToken; @@ -1662,19 +1685,6 @@ namespace { key.parentOp += type; } - for (const auto& ref: followAllReferences(op1)) { - if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm - key.operand1 = ref.token->exprId(); - break; - } - } - for (const auto& ref: followAllReferences(op2)) { - if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm - key.operand2 = ref.token->exprId(); - break; - } - } - if (key.operand1 > key.operand2 && key.operand2 && Token::Match(tok->astParent(), "%or%|%oror%|+|*|&|&&|^|==|!=")) { // In C++ the order of operands of + might matter @@ -1915,7 +1925,10 @@ void SymbolDatabase::setArrayDimensionsUsingValueFlow() } if (bits > 0 && bits <= 62) { - if (dimension.tok->valueType()->sign == ValueType::Sign::UNSIGNED) + auto sign = dimension.tok->valueType()->sign; + if (sign == ValueType::Sign::UNKNOWN_SIGN && dimension.tok->valueType()->type == ValueType::Type::CHAR) + sign = mDefaultSignedness; + if (sign == ValueType::Sign::UNSIGNED) dimension.num = 1LL << bits; else dimension.num = 1LL << (bits - 1); @@ -2364,9 +2377,9 @@ void SymbolDatabase::validate() const validateVariables(); } -void SymbolDatabase::clangSetVariables(const std::vector &variableList) +void SymbolDatabase::clangSetVariables(const std::vector &vars) { - mVariableList = variableList; + mVariableList = vars; } void SymbolDatabase::debugSymbolDatabase() const @@ -2497,7 +2510,12 @@ bool Variable::isMember() const { bool Variable::isPointerArray() const { - return isArray() && nameToken() && nameToken()->previous() && (nameToken()->strAt(-1) == "*"); + if (!isArray()) + return false; + const Token* tok = nameToken() ? nameToken()->previous() : nullptr; + while (Token::Match(tok, "const|volatile")) + tok = tok->previous(); + return Token::simpleMatch(tok, "*"); } bool Variable::isUnsigned() const @@ -2630,16 +2648,16 @@ void Variable::evaluate(const Settings& settings) } } -void Variable::setValueType(const ValueType &valueType) +void Variable::setValueType(const ValueType &vt) { - if (valueType.type == ValueType::Type::UNKNOWN_TYPE) { + if (vt.type == ValueType::Type::UNKNOWN_TYPE) { const Token *declType = Token::findsimplematch(mTypeStartToken, "decltype (", mTypeEndToken); if (declType && !declType->next()->valueType()) return; } - const auto* vt = new ValueType(valueType); + const auto* tmp = new ValueType(vt); delete mValueType; - mValueType = vt; + mValueType = tmp; if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )"))) setFlag(fIsPointer, true); setFlag(fIsConst, mValueType->constness & (1U << mValueType->pointer)); @@ -3340,8 +3358,12 @@ static bool checkReturns(const Function* function, bool unknown, bool emptyEnabl assert(defEnd != defStart); if (pred(defStart, defEnd)) return true; - if (isUnknownType(defStart, defEnd)) + if (isUnknownType(defStart, defEnd)) { + const Token* tok = function->token ? function->token->next() : function->tokenDef->next(); + if (tok->valueType() && tok->valueType()->type >= ValueType::Type::RECORD) + return false; return unknown; + } return false; } @@ -3854,7 +3876,7 @@ void SymbolDatabase::returnImplicitIntError(const Token *tok) const const Function* Type::getFunction(const std::string& funcName) const { if (classScope) { - const auto it = utils::as_const(classScope->functionMap).find(funcName); + const auto it = classScope->functionMap.find(funcName); if (it != classScope->functionMap.end()) return it->second; } @@ -4065,9 +4087,8 @@ static const char* functionTypeToString(FunctionType type) return "Function"; case FunctionType::eLambda: return "Lambda"; - default: - return "Unknown"; } + cppcheck::unreachable(); } static std::string tokenToString(const Token* tok, const Tokenizer& tokenizer) @@ -4829,7 +4850,7 @@ std::vector Function::getOverloadedFunctions() const while (scope) { const bool isMemberFunction = scope->isClassOrStruct() && !isStatic(); - for (auto it = utils::as_const(scope->functionMap).find(tokenDef->str()); + for (auto it = scope->functionMap.find(tokenDef->str()); it != scope->functionMap.end() && it->first == tokenDef->str(); ++it) { const Function* func = it->second; @@ -4880,7 +4901,7 @@ const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType const Scope *parent = derivedFromType->classScope; // check if function defined in base class - auto range = utils::as_const(parent->functionMap).equal_range(tokenDef->str()); + auto range = parent->functionMap.equal_range(tokenDef->str()); for (auto it = range.first; it != range.second; ++it) { const Function * func = it->second; if (func->isImplicitlyVirtual()) { // Base is virtual and of same name @@ -5264,6 +5285,26 @@ const Variable *Scope::getVariable(const std::string &varname) const static const Token* skipPointers(const Token* tok) { + const Token *start = tok; + bool memberPointer = false; + while (tok) { + if (Token::simpleMatch(tok, "::")) { + tok = tok->next(); + continue; + } + if (Token::Match(tok, "%type% ::")) { + tok = tok->tokAt(2); + memberPointer = true; + continue; + } + if (Token::Match(tok, "%type% <") && tok->linkAt(1)) { + tok = tok->linkAt(1)->next(); + continue; + } + break; + } + if (memberPointer && !Token::simpleMatch(tok, "*")) + return start; while (Token::Match(tok, "*|&|&&") || (Token::Match(tok, "( [*&]") && Token::Match(tok->link()->next(), "(|["))) { tok = tok->next(); if (tok && tok->strAt(-1) == "(" && Token::Match(tok, "%type% ::")) @@ -5807,7 +5848,7 @@ void Scope::findFunctionInBase(const Token* tok, nonneg int args, std::vectorclassScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already continue; - auto range = utils::as_const(base->classScope->functionMap).equal_range(tok->str()); + auto range = base->classScope->functionMap.equal_range(tok->str()); for (auto it = range.first; it != range.second; ++it) { const Function *func = it->second; if (func->isDestructor() && !Token::simpleMatch(tok->tokAt(-1), "~")) @@ -5895,7 +5936,7 @@ static void checkVariableCallMatch(const Variable* callarg, const Variable* func callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()) { same++; } else if (callarg->isArrayOrPointer()) { - if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void") + if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void") // cppcheck-suppress knownConditionTrueFalse // #14418 fallback1++; else if (constEquals && funcarg->isStlStringType() && Token::Match(callarg->typeStartToken(), "char|wchar_t")) fallback2++; @@ -5969,7 +6010,7 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst, Referen const std::size_t args = arguments.size(); auto addMatchingFunctions = [&](const Scope *scope) { - auto range = utils::as_const(scope->functionMap).equal_range(tok->str()); + auto range = scope->functionMap.equal_range(tok->str()); for (auto it = range.first; it != range.second; ++it) { const Function *func = it->second; if (ref == Reference::LValue && func->hasRvalRefQualifier()) @@ -6401,7 +6442,7 @@ const Function* SymbolDatabase::findFunction(const Token* const tok) const } } // Check for constructor - if (Token::Match(tok, "%name% (|{")) { + if (!Token::simpleMatch(tok->tokAt(-2), "this .") && Token::Match(tok, "%name% (|{")) { ValueType vt = ValueType::parseDecl(tok, mSettings); if (vt.typeScope) return vt.typeScope->findFunction(tok, false); @@ -6508,7 +6549,7 @@ Type* Scope::findType(const std::string& name) //--------------------------------------------------------------------------- -Scope *Scope::findInNestedListRecursive(const std::string & name) +const Scope *Scope::findInNestedListRecursive(const std::string & name) const { auto it = std::find_if(nestedList.cbegin(), nestedList.cend(), [&](const Scope* s) { return s->className == name; @@ -6516,8 +6557,8 @@ Scope *Scope::findInNestedListRecursive(const std::string & name) if (it != nestedList.end()) return *it; - for (Scope* scope: nestedList) { - Scope *child = scope->findInNestedListRecursive(name); + for (const Scope* scope: nestedList) { + const Scope *child = scope->findInNestedListRecursive(name); if (child) return child; } @@ -6737,7 +6778,7 @@ Function * SymbolDatabase::findFunctionInScope(const Token *func, const Scope *n const Function * function = nullptr; const bool destructor = func->strAt(-1) == "~"; - auto range = utils::as_const(ns->functionMap).equal_range(func->str()); + auto range = ns->functionMap.equal_range(func->str()); for (auto it = range.first; it != range.second; ++it) { if (it->second->argsMatch(ns, it->second->argDef, func->next(), path, path_length) && it->second->isDestructor() == destructor) { @@ -6852,7 +6893,7 @@ void SymbolDatabase::setValueType(Token* tok, const Enumerator& enumerator, cons if (valuetype.type == ValueType::Type::UNKNOWN_TYPE) valuetype.fromLibraryType(type->expressionString(), mSettings); - if (valuetype.isIntegral()) { + if (valuetype.sign == ValueType::UNKNOWN_SIGN && valuetype.isIntegral()) { if (type->isSigned()) valuetype.sign = ValueType::Sign::SIGNED; else if (type->isUnsigned()) @@ -7636,9 +7677,7 @@ static const Token* parsedecl(const Token* type, // Set signedness for integral types.. if (valuetype->isIntegral() && valuetype->sign == ValueType::Sign::UNKNOWN_SIGN) { - if (valuetype->type == ValueType::Type::CHAR) - valuetype->sign = defaultSignedness; - else if (valuetype->type >= ValueType::Type::SHORT) + if (valuetype->type >= ValueType::Type::SHORT) valuetype->sign = ValueType::Sign::SIGNED; } @@ -7658,14 +7697,14 @@ static const Function *getOperatorFunction(const Token * const tok) const Scope *classScope = getClassScope(tok->astOperand1()); if (classScope) { - auto it = utils::as_const(classScope->functionMap).find(functionName); + auto it = classScope->functionMap.find(functionName); if (it != classScope->functionMap.end()) return it->second; } classScope = getClassScope(tok->astOperand2()); if (classScope) { - auto it = utils::as_const(classScope->functionMap).find(functionName); + auto it = classScope->functionMap.find(functionName); if (it != classScope->functionMap.end()) return it->second; } @@ -7851,6 +7890,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to else if (Token::simpleMatch(tok->previous(), "sizeof (")) { ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U); + // TODO: handle via sizeof_size_t instead if (mSettings.platform.type == Platform::Type::Win64) valuetype.type = ValueType::Type::LONGLONG; @@ -8007,17 +8047,20 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to } } //Is iterator fetching function called? - } else if (Token::simpleMatch(tok->astOperand1(), "::") && - tok->astOperand2() && - tok->astOperand2()->isVariable()) { - const auto* const paramVariable = tok->astOperand2()->variable(); + } else if (Token::simpleMatch(tok->astOperand1(), "::") && Token::Match(tok->astOperand2(), "%var%|.|[")) { + const Token* varTok = tok->astOperand2(); + while (Token::simpleMatch(varTok, "[")) + varTok = varTok->astOperand1(); + while (Token::simpleMatch(varTok, ".")) + varTok = varTok->astOperand2(); + const Variable* const paramVariable = varTok ? varTok->variable() : nullptr; if (!paramVariable || !paramVariable->valueType() || !paramVariable->valueType()->container) { continue; } - const auto yield = astFunctionYield(tok->previous(), mSettings); + const auto yield = astFunctionYield(tok->previous(), mSettings.library); if (yield == Library::Container::Yield::START_ITERATOR || yield == Library::Container::Yield::END_ITERATOR || yield == Library::Container::Yield::ITERATOR) { @@ -8480,7 +8523,7 @@ static size_t bitCeil(size_t x) static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueType::Accuracy accuracy, ValueType::SizeOf sizeOf, int maxRecursion = 0) { - if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) { + if (maxRecursion > settings.vfOptions.maxAlignOfRecursion) { // TODO: add bailout message return 0; } @@ -8511,7 +8554,7 @@ static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueTyp size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf sizeOf, int maxRecursion) const { - if (maxRecursion == settings.vfOptions.maxSizeOfRecursion) { + if (maxRecursion > settings.vfOptions.maxSizeOfRecursion) { // TODO: add bailout message return 0; } @@ -8755,7 +8798,7 @@ ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Va return ValueType::MatchResult::UNKNOWN; } - if (call->isIntegral() && func->isIntegral() && call->sign != ValueType::Sign::UNKNOWN_SIGN && func->sign != ValueType::Sign::UNKNOWN_SIGN && call->sign != func->sign) + if (call->isIntegral() && func->isIntegral() && call->sign != func->sign) return ValueType::MatchResult::FALLBACK1; if (func->reference != Reference::None && (func->constness > call->constness || func->volatileness > call->volatileness)) diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 954b31cc05b..a4a07fd2083 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -651,7 +651,7 @@ class CPPCHECKLIB Variable { return mValueType; } - void setValueType(const ValueType &valueType); + void setValueType(const ValueType &vt); AccessControl accessControl() const { return mAccess; @@ -1157,7 +1157,7 @@ class CPPCHECKLIB Scope { * @brief find if name is in nested list * @param name name of nested scope */ - Scope *findInNestedListRecursive(const std::string & name); + const Scope *findInNestedListRecursive(const std::string & name) const; void addVariable(const Token *token_, const Token *start_, const Token *end_, AccessControl access_, const Type *type_, @@ -1424,13 +1424,13 @@ class CPPCHECKLIB SymbolDatabase { /** Set array dimensions when valueflow analysis is completed */ void setArrayDimensionsUsingValueFlow(); - void clangSetVariables(const std::vector &variableList); + void clangSetVariables(const std::vector &vars); void createSymbolDatabaseExprIds(); /* returns the opening { if tok points to enum */ static const Token* isEnumDefinition(const Token* tok); - static void getErrorMessages(ErrorLogger &errorLogger); + static void getErrorMessages(ErrorLogger& /*errorLogger*/); // check if type has no side effects (no constructors and no members with constructors) /** @todo false negative: check constructors for side effects */ diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 023fe5618ad..1fe1df10037 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2085,8 +2085,11 @@ void TemplateSimplifier::expandTemplate( std::stack templates; int scopeCount = 0; for (; tok3; tok3 = tok3->next()) { - if (tok3->str() == "{") + if (tok3->str() == "{") { + if (isFunction && isSpecialization && inTemplateDefinition) + break; ++scopeCount; + } else if (tok3->str() == "}") --scopeCount; if (scopeCount < 0) @@ -2104,8 +2107,6 @@ void TemplateSimplifier::expandTemplate( Token * const beforeTypeToken = mTokenList.back(); bool pointerType = false; const bool isVariadicTemplateArg = templateDeclaration.isVariadic() && itype + 1 == typeParametersInDeclaration.size(); - if (isVariadicTemplateArg && mTypesUsedInTemplateInstantiation.size() > 1 && !Token::Match(tok3->next(), "...|<")) - continue; if (isVariadicTemplateArg && Token::Match(tok3, "%name% ... %name%")) tok3 = tok3->tokAt(2); if (!isVariadicTemplateArg && copy && Token::Match(mTypesUsedInTemplateInstantiation[itype].token(), "%num% ,|>|>>") && @@ -2130,6 +2131,7 @@ void TemplateSimplifier::expandTemplate( } } const std::string endStr(isVariadicTemplateArg ? ">" : ",>"); + Token* begPar = nullptr; for (Token *typetok = mTypesUsedInTemplateInstantiation[itype].token(); typetok && (typeindentlevel > 0 || endStr.find(typetok->str()[0]) == std::string::npos); typetok = typetok->next()) { @@ -2153,6 +2155,10 @@ void TemplateSimplifier::expandTemplate( --typeindentlevel; Token *back; if (copy) { + if (isVariadicTemplateArg && typetok == mTypesUsedInTemplateInstantiation[itype].token() && typetok->isLiteral()) { + mTokenList.addtoken("(", mTokenList.back()); + begPar = mTokenList.back(); + } mTokenList.addtoken(typetok, tok3); back = mTokenList.back(); } else @@ -2181,6 +2187,10 @@ void TemplateSimplifier::expandTemplate( if (copy) back->templateArgFrom(typetok); } + if (begPar) { + mTokenList.addtoken(")", mTokenList.back()); + Token::createMutualLinks(begPar, mTokenList.back()); + } if (pointerType && Token::simpleMatch(beforeTypeToken, "const")) { mTokenList.addtoken(beforeTypeToken); beforeTypeToken->deleteThis(); @@ -3152,7 +3162,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( "templateRecursion", "TemplateSimplifier: max template recursion (" + std::to_string(mSettings.maxTemplateRecursion) - + ") reached for template '"+typeForNewName+"'. You might want to limit Cppcheck recursion.", + + ") reached for template '"+typeForNewName+"'.", Certainty::normal); mErrorLogger.reportErr(errmsg); } diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index b5285071841..f6e507459a9 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/lib/timer.cpp b/lib/timer.cpp index 9e2dd901bea..275acc06078 100644 --- a/lib/timer.cpp +++ b/lib/timer.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,60 +19,69 @@ #include "timer.h" #include -#include #include +#include #include #include namespace { - using dataElementType = std::pair; - bool more_second_sec(const dataElementType& lhs, const dataElementType& rhs) - { - return lhs.second.getSeconds() > rhs.second.getSeconds(); - } - // TODO: remove and print through (synchronized) ErrorLogger instead std::mutex stdCoutLock; } // TODO: this does not include any file context when SHOWTIME_FILE thus rendering it useless - should we include the logging with the progress logging? // that could also get rid of the broader locking -void TimerResults::showResults(ShowTime mode) const +void TimerResults::showResults(size_t max_results, bool metrics) const { - if (mode == ShowTime::NONE || mode == ShowTime::FILE_TOTAL) - return; - std::vector data; + using dataElementType = std::pair>; + std::vector data; { std::lock_guard l(mResultsSync); data.reserve(mResults.size()); data.insert(data.begin(), mResults.cbegin(), mResults.cend()); } - std::sort(data.begin(), data.end(), more_second_sec); + + const auto asSeconds = [](std::chrono::milliseconds ms) -> std::chrono::duration { + return std::chrono::duration_cast>(ms); + }; + + const auto getSeconds = [&asSeconds](const std::vector& results) -> std::chrono::duration { + return std::accumulate(results.cbegin(), results.cend(), std::chrono::duration{}, [&asSeconds](std::chrono::duration secs, std::chrono::milliseconds duration) { + return secs + asSeconds(duration); + }); + }; + + std::sort(data.begin(), data.end(), [&getSeconds](const dataElementType& lhs, const dataElementType& rhs) -> bool { + return getSeconds(lhs.second) > getSeconds(rhs.second); + }); // lock the whole logging operation to avoid multiple threads printing their results at the same time std::lock_guard l(stdCoutLock); - std::cout << std::endl; - size_t ordinal = 1; // maybe it would be nice to have an ordinal in output later! for (auto iter=data.cbegin(); iter!=data.cend(); ++iter) { - const double sec = iter->second.getSeconds().count(); - const double secAverage = sec / static_cast(iter->second.mNumberOfResults); - if ((mode != ShowTime::TOP5_FILE && mode != ShowTime::TOP5_SUMMARY) || (ordinal<=5)) { - std::cout << iter->first << ": " << sec << "s (avg. " << secAverage << "s - " << iter->second.mNumberOfResults << " result(s))" << std::endl; + if (ordinal <= max_results) { + const double sec = getSeconds(iter->second).count(); + std::cout << iter->first << ": " << sec << "s"; + if (metrics) { + const double secAverage = sec / static_cast(iter->second.size()); + const double secMin = asSeconds(*std::min_element(iter->second.cbegin(), iter->second.cend())).count(); + const double secMax = asSeconds(*std::max_element(iter->second.cbegin(), iter->second.cend())).count(); + std::cout << " (avg. " << secAverage << "s / min " << secMin << "s / max " << secMax << "s - " << iter->second.size() << " result(s))"; + } + std::cout << std::endl; } ++ordinal; } } -void TimerResults::addResults(const std::string& str, std::chrono::milliseconds duration) +void TimerResults::addResults(const std::string& name, std::chrono::milliseconds duration) { std::lock_guard l(mResultsSync); - mResults[str].mDuration += duration; - mResults[str].mNumberOfResults++; + mResults[name].push_back(duration); } void TimerResults::reset() @@ -81,13 +90,14 @@ void TimerResults::reset() mResults.clear(); } -Timer::Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults, Type type) +Timer::Timer(std::string str, TimerResultsIntf* timerResults) : mName(std::move(str)) - , mMode(showtimeMode) - , mType(type) - , mStart(Clock::now()) , mResults(timerResults) -{} +{ + if (!mResults) + return; + mStart = Clock::now(); +} Timer::~Timer() { @@ -96,29 +106,16 @@ Timer::~Timer() void Timer::stop() { - if (mMode == ShowTime::NONE) - return; - if (mType == Type::OVERALL && mMode != ShowTime::TOP5_SUMMARY && mMode != ShowTime::SUMMARY) { - mMode = ShowTime::NONE; - return; - } - if (mType == Type::FILE && mMode != ShowTime::TOP5_FILE && mMode != ShowTime::FILE && mMode != ShowTime::FILE_TOTAL) { - mMode = ShowTime::NONE; + if (mStart == TimePoint{}) return; - } - if (mStart != TimePoint{}) { - auto diff = std::chrono::duration_cast(Clock::now() - mStart); - if (!mResults) { - std::lock_guard l(stdCoutLock); - std::cout << (mType == Type::OVERALL ? "Overall time: " : "Check time: " + mName + ": ") << TimerResultsData::durationToString(diff) << std::endl; - } else { - mResults->addResults(mName, diff); - } - } - mMode = ShowTime::NONE; // prevent multiple stops + + const auto diff = std::chrono::duration_cast(Clock::now() - mStart); + mResults->addResults(mName, diff); + + mStart = TimePoint{}; // prevent multiple stops } -std::string TimerResultsData::durationToString(std::chrono::milliseconds duration) +static std::string durationToString(std::chrono::milliseconds duration) { // Extract hours auto hours = std::chrono::duration_cast(duration); @@ -142,3 +139,21 @@ std::string TimerResultsData::durationToString(std::chrono::milliseconds duratio secondsStr.resize(pos + 4); // keep three decimal return (ellapsedTime + secondsStr + "s"); } + +OneShotTimer::OneShotTimer(std::string name) +{ + class MyResults : public TimerResultsIntf + { + private: + void addResults(const std::string &name, std::chrono::milliseconds duration) override + { + std::lock_guard l(stdCoutLock); + + // TODO: do not use std::cout directly + std::cout << name << ": " << durationToString(duration) << std::endl; + } + }; + + mResults.reset(new MyResults); + mTimer.reset(new Timer(std::move(name), mResults.get())); +} diff --git a/lib/timer.h b/lib/timer.h index c3d477d5802..1ee7fde52f9 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,50 +23,38 @@ #include "config.h" #include -#include +#include +#include #include +#include #include #include #include - -enum class ShowTime : std::uint8_t { - NONE, - FILE, - FILE_TOTAL, - SUMMARY, - TOP5_SUMMARY, - TOP5_FILE -}; +#include class CPPCHECKLIB TimerResultsIntf { public: virtual ~TimerResultsIntf() = default; - virtual void addResults(const std::string& timerName, std::chrono::milliseconds duation) = 0; -}; - -struct TimerResultsData { - std::chrono::milliseconds mDuration; - long mNumberOfResults{}; - - std::chrono::duration getSeconds() const { - return std::chrono::duration_cast>(mDuration); - } - - static std::string durationToString(std::chrono::milliseconds duration); + virtual void addResults(const std::string& name, std::chrono::milliseconds duration) = 0; }; class CPPCHECKLIB WARN_UNUSED TimerResults : public TimerResultsIntf { public: TimerResults() = default; - void showResults(ShowTime mode) const; - void addResults(const std::string& str, std::chrono::milliseconds duration) override; + void showResults(size_t max_results = std::numeric_limits::max(), bool metrics = true) const; + void addResults(const std::string& name, std::chrono::milliseconds duration) override; void reset(); -private: - std::map mResults; + std::map> getResults() const { + std::lock_guard l(mResultsSync); + return mResults; + } + +protected: + std::map> mResults; mutable std::mutex mResultsSync; }; @@ -75,13 +63,7 @@ class CPPCHECKLIB Timer { using Clock = std::chrono::high_resolution_clock; using TimePoint = std::chrono::time_point; - enum class Type : std::uint8_t { - FILE, - OVERALL, - OTHER - }; - - Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults = nullptr, Type type = Type::OTHER); + explicit Timer(std::string str, TimerResultsIntf* timerResults = nullptr); ~Timer(); Timer(const Timer&) = delete; @@ -90,18 +72,25 @@ class CPPCHECKLIB Timer { void stop(); template - static void run(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults, const TFunc& f) { - Timer t(std::move(str), showtimeMode, timerResults); + static void run(std::string str, TimerResultsIntf* timerResults, const TFunc& f) { + Timer t(std::move(str), timerResults); f(); } private: const std::string mName; - ShowTime mMode{}; - Type mType{}; TimePoint mStart; TimerResultsIntf* mResults{}; }; +class CPPCHECKLIB OneShotTimer +{ +public: + explicit OneShotTimer(std::string name); +private: + std::unique_ptr mResults; + std::unique_ptr mTimer; +}; + //--------------------------------------------------------------------------- #endif // timerH diff --git a/lib/token.cpp b/lib/token.cpp index f55fcc14830..539141c0b0f 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -211,9 +211,9 @@ static const std::unordered_set stdTypes = { "bool" , "unsigned" }; -bool Token::isStandardType(const std::string& str) +bool Token::isStandardType(const std::string& s) { - return stdTypes.find(str) != stdTypes.end(); + return stdTypes.find(s) != stdTypes.end(); } void Token::update_property_isStandardType() @@ -424,7 +424,7 @@ int multiComparePercent(const Token *tok, const char*& haystack, nonneg int vari return 1; } else { // %varid% if (varid == 0) { - throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers"); + throw InternalError(tok, "Internal error. Token::Match called with varid 0."); } haystack += 6; @@ -554,7 +554,7 @@ int multiCompareImpl(const Token *tok, const char *haystack, nonneg int varid) const char *needle = tok->str().c_str(); const char *needlePointer = needle; for (;;) { - if (needlePointer == needle && haystack[0] == '%' && haystack[1] != '|' && haystack[1] != '\0' && haystack[1] != ' ') { + if (needlePointer == needle && haystack[0] == '%' && haystack[1] != '|' && haystack[1] != '\0' && haystack[1] != ' ' && haystack[1] != '=') { const int ret = multiComparePercent(tok, haystack, varid); if (ret < 2) return ret; @@ -637,31 +637,31 @@ bool Token::simpleMatch(const Token *tok, const char pattern[], size_t pattern_l return true; } -bool Token::firstWordEquals(const char *str, const char *word) +bool Token::firstWordEquals(const char *s, const char *word) { for (;;) { - if (*str != *word) - return (*str == ' ' && *word == 0); - if (*str == 0) + if (*s != *word) + return (*s == ' ' && *word == 0); + if (*s == 0) break; - ++str; + ++s; ++word; } return true; } -const char *Token::chrInFirstWord(const char *str, char c) +const char *Token::chrInFirstWord(const char *s, char c) { for (;;) { - if (*str == ' ' || *str == 0) + if (*s == ' ' || *s == 0) return nullptr; - if (*str == c) - return str; + if (*s == c) + return s; - ++str; + ++s; } } @@ -1014,41 +1014,41 @@ Token *Token::findsimplematch(Token * const startTok, const char pattern[], size } template )> -static T *findmatchImpl(T * const startTok, const char pattern[], const nonneg int varId) +static T *findmatchImpl(T * const startTok, const char pattern[], const nonneg int varid) { for (T* tok = startTok; tok; tok = tok->next()) { - if (Token::Match(tok, pattern, varId)) + if (Token::Match(tok, pattern, varid)) return tok; } return nullptr; } -const Token *Token::findmatch(const Token * const startTok, const char pattern[], const nonneg int varId) +const Token *Token::findmatch(const Token * const startTok, const char pattern[], const nonneg int varid) { - return findmatchImpl(startTok, pattern, varId); + return findmatchImpl(startTok, pattern, varid); } -Token *Token::findmatch(Token * const startTok, const char pattern[], const nonneg int varId) { - return findmatchImpl(startTok, pattern, varId); +Token *Token::findmatch(Token * const startTok, const char pattern[], const nonneg int varid) { + return findmatchImpl(startTok, pattern, varid); } template )> -static T *findmatchImpl(T * const startTok, const char pattern[], const Token * const end, const nonneg int varId) +static T *findmatchImpl(T * const startTok, const char pattern[], const Token * const end, const nonneg int varid) { for (T* tok = startTok; tok && tok != end; tok = tok->next()) { - if (Token::Match(tok, pattern, varId)) + if (Token::Match(tok, pattern, varid)) return tok; } return nullptr; } -const Token *Token::findmatch(const Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId) +const Token *Token::findmatch(const Token * const startTok, const char pattern[], const Token * const end, const nonneg int varid) { - return findmatchImpl(startTok, pattern, end, varId); + return findmatchImpl(startTok, pattern, end, varid); } -Token *Token::findmatch(Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId) { - return findmatchImpl(startTok, pattern, end, varId); +Token *Token::findmatch(Token * const startTok, const char pattern[], const Token * const end, const nonneg int varid) { + return findmatchImpl(startTok, pattern, end, varid); } void Token::function(const Function *f) @@ -1421,11 +1421,6 @@ std::string Token::stringifyList(const Token* end, bool attributes) const return stringifyList(false, attributes, false, false, false, nullptr, end); } -std::string Token::stringifyList(bool varid) const -{ - return stringifyList(varid, false, true, true, true, nullptr, nullptr); -} - void Token::astParent(Token* tok) { const Token* tok2 = tok; @@ -1821,7 +1816,7 @@ void Token::printValueFlow(const std::vector& files, bool xml, std: outs += " valueType() && tok->valueType()->sign == ValueType::UNSIGNED) { + if (tok->valueType() && tok->valueType()->sign == ValueType::UNSIGNED && value.toString() != "!<=-1") { outs += "intvalue=\""; outs += MathLib::toString(static_cast(value.intvalue)); outs += '\"'; @@ -2361,6 +2356,8 @@ const ::Type* Token::typeOf(const Token* tok, const Token** typeTok) return tok->variable()->type(); if (tok->function()) return tok->function()->retType; + if (tok->valueType() && tok->valueType()->typeScope && tok->valueType()->typeScope->definedType) + return tok->valueType()->typeScope->definedType; if (Token::simpleMatch(tok, "return")) { // cppcheck-suppress shadowFunction - TODO: fix this const Scope *scope = tok->scope(); @@ -2664,26 +2661,26 @@ Token::Impl::~Impl() } } -void Token::Impl::setCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint value) +void Token::Impl::setCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint value) { CppcheckAttributes *attr = mCppcheckAttributes; - while (attr && attr->type != type) + while (attr && attr->type != attrType) attr = attr->next; if (attr) attr->value = value; else { attr = new CppcheckAttributes; - attr->type = type; + attr->type = attrType; attr->value = value; attr->next = mCppcheckAttributes; mCppcheckAttributes = attr; } } -bool Token::Impl::getCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint &value) const +bool Token::Impl::getCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint &value) const { const CppcheckAttributes *attr = mCppcheckAttributes; - while (attr && attr->type != type) + while (attr && attr->type != attrType) attr = attr->next; if (attr) value = attr->value; diff --git a/lib/token.h b/lib/token.h index 74e81354f9a..ca945fcab22 100644 --- a/lib/token.h +++ b/lib/token.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -80,7 +80,6 @@ enum class TokenDebug : std::uint8_t { None, ValueFlow, ValueType }; * The Token class also has other functions for management of token list, matching tokens, etc. */ class CPPCHECKLIB Token { - friend class TestToken; public: enum CppcheckAttributesType : std::uint8_t { LOW, HIGH }; @@ -175,8 +174,8 @@ class CPPCHECKLIB Token { std::int8_t mMutableExpr{-1}; - void setCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint value); - bool getCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint &value) const; + void setCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint value); + bool getCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint &value) const; Impl() = default; ~Impl(); @@ -873,8 +872,8 @@ class CPPCHECKLIB Token { } static const Token *findsimplematch(const Token * startTok, const char pattern[], size_t pattern_len, const Token * end); - static const Token *findmatch(const Token * startTok, const char pattern[], nonneg int varId = 0); - static const Token *findmatch(const Token * startTok, const char pattern[], const Token * end, nonneg int varId = 0); + static const Token *findmatch(const Token * startTok, const char pattern[], nonneg int varid = 0); + static const Token *findmatch(const Token * startTok, const char pattern[], const Token * end, nonneg int varid = 0); template static Token *findsimplematch(Token * const startTok, const char (&pattern)[count]) { @@ -887,8 +886,8 @@ class CPPCHECKLIB Token { } static Token *findsimplematch(Token * startTok, const char pattern[], size_t pattern_len, const Token * end); - static Token *findmatch(Token * startTok, const char pattern[], nonneg int varId = 0); - static Token *findmatch(Token * startTok, const char pattern[], const Token * end, nonneg int varId = 0); + static Token *findmatch(Token * startTok, const char pattern[], nonneg int varid = 0); + static Token *findmatch(Token * startTok, const char pattern[], const Token * end, nonneg int varid = 0); private: template )> @@ -918,6 +917,7 @@ class CPPCHECKLIB Token { return tok->link(); } +protected: /** * Needle is build from multiple alternatives. If one of * them is equal to haystack, return value is 1. If there @@ -1110,7 +1110,7 @@ class CPPCHECKLIB Token { options.files = true; return options; } - // cppcheck-suppress unusedFunction + // cppcheck-suppress unusedFunction - used in tests only static stringifyOptions forDebugVarId() { stringifyOptions options = forDebug(); options.varid = true; @@ -1142,7 +1142,6 @@ class CPPCHECKLIB Token { std::string stringifyList(const stringifyOptions& options, const std::vector* fileNames = nullptr, const Token* end = nullptr) const; std::string stringifyList(const Token* end, bool attributes = true) const; - std::string stringifyList(bool varid = false) const; /** * Stringify a list of token, from current instance on. @@ -1268,7 +1267,7 @@ class CPPCHECKLIB Token { static std::string typeStr(const Token* tok); - static bool isStandardType(const std::string& str); + static bool isStandardType(const std::string& s); /** * @return a pointer to the Enumerator associated with this token. @@ -1440,17 +1439,17 @@ class CPPCHECKLIB Token { /** * Works almost like strcmp() except returns only true or false and - * if str has empty space ' ' character, that character is handled + * if s has empty space ' ' character, that character is handled * as if it were '\\0' */ - static bool firstWordEquals(const char *str, const char *word); + static bool firstWordEquals(const char *s, const char *word); /** * Works almost like strchr() except - * if str has empty space ' ' character, that character is handled + * if s has empty space ' ' character, that character is handled * as if it were '\\0' */ - static const char *chrInFirstWord(const char *str, char c); + static const char *chrInFirstWord(const char *s, char c); RET_NONNULL Token* insertToken(const std::string& tokenStr, bool prepend); RET_NONNULL Token* insertToken(const std::string& tokenStr, const std::string& originalNameStr, bool prepend); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 27dfe9ebadc..6f9cf90a852 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -103,14 +103,14 @@ static void skipEnumBody(T *&tok) /** * is tok the start brace { of a class, struct, union, or enum */ -static bool isClassStructUnionEnumStart(const Token * tok) +static const Token* isClassStructUnionEnumStart(const Token* tok) { if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {")) - return false; + return nullptr; const Token * tok2 = tok->previous(); - while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|)|;|>|>>")) + while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|)|;")) tok2 = tok2->previous(); - return Token::Match(tok2, "class|struct|union|enum") && !Token::simpleMatch(tok2->tokAt(-1), "->"); + return (Token::Match(tok2, "class|struct|union|enum") && !Token::simpleMatch(tok2->tokAt(-1), "->")) ? tok2 : nullptr; } //--------------------------------------------------------------------------- @@ -135,7 +135,7 @@ Tokenizer::~Tokenizer() nonneg int Tokenizer::sizeOfType(const std::string& type) const { - const auto it = utils::as_const(mTypeSize).find(type); + const auto it = mTypeSize.find(type); if (it == mTypeSize.end()) { const Library::PodType* podtype = mSettings.library.podtype(type); if (!podtype) @@ -154,7 +154,7 @@ nonneg int Tokenizer::sizeOfType(const Token *type) const if (type->tokType() == Token::eString) return Token::getStrLength(type) + 1U; - const auto it = utils::as_const(mTypeSize).find(type->str()); + const auto it = mTypeSize.find(type->str()); if (it == mTypeSize.end()) { const Library::PodType* podtype = mSettings.library.podtype(type->str()); if (!podtype) @@ -1025,7 +1025,21 @@ namespace { } bool Tokenizer::isFunctionPointer(const Token* tok) { - return Token::Match(tok, "%name% ) ("); + if (!Token::Match(tok, "%name%")) + return false; + tok = tok->next(); + while (Token::Match(tok, "[")) + tok = tok->link()->next(); + return Token::simpleMatch(tok, ") ("); +} + +static bool matchCurrentType(const Token* tok, std::map& types) +{ + if (tok->isC()) + return false; + return std::any_of(types.begin(), types.end(), [&](const std::pair& element) { + return tok->str() == element.second; + }); } void Tokenizer::simplifyTypedef() @@ -1043,19 +1057,26 @@ void Tokenizer::simplifyTypedef() if (t != ts.nameToken()) existing_data_type += t->str() + " "; } - numberOfTypedefs[ts.name()].insert(existing_data_type); + numberOfTypedefs[ts.name()].emplace(std::move(existing_data_type)); continue; } } int indentlevel = 0; std::map typedefs; + std::map inType; for (Token* tok = list.front(); tok; tok = tok->next()) { if (!tok->isName()) { - if (tok->str()[0] == '{') + if (tok->str()[0] == '{') { ++indentlevel; - else if (tok->str()[0] == '}') + if (const Token* typeStart = isClassStructUnionEnumStart(tok)) { + inType.emplace(indentlevel, typeStart->strAt(1)); + } + } + else if (tok->str()[0] == '}') { + inType.erase(indentlevel); --indentlevel; + } continue; } @@ -1072,7 +1093,7 @@ void Tokenizer::simplifyTypedef() } auto it = typedefs.find(tok->str()); - if (it != typedefs.end() && it->second.canReplace(tok)) { + if (it != typedefs.end() && it->second.canReplace(tok) && !matchCurrentType(tok, inType)) { std::set r; std::string originalname; while (it != typedefs.end() && r.insert(tok->str()).second) { @@ -1099,14 +1120,18 @@ void Tokenizer::simplifyTypedef() syntaxError(t.second.getTypedefToken()); } else { const Token* const typedefToken = t.second.getTypedefToken(); + const Token* const nameToken = t.second.nameToken(); TypedefInfo typedefInfo; typedefInfo.name = t.second.name(); - typedefInfo.filename = list.file(typedefToken); - typedefInfo.lineNumber = typedefToken->linenr(); - typedefInfo.column = typedefToken->column(); - if (Token::Match(typedefToken->next(), "struct|enum|class|union %name% {") && typedefToken->strAt(2) == typedefInfo.name) { - typedefInfo.tagLine = typedefToken->tokAt(2)->linenr(); - typedefInfo.tagColumn = typedefToken->tokAt(2)->column(); + typedefInfo.filename = list.file(nameToken); + typedefInfo.lineNumber = nameToken->linenr(); + typedefInfo.column = nameToken->column(); + if (Token::Match(typedefToken->next(), "struct|enum|class|union %name% {")) { + typedefInfo.originalName = typedefToken->strAt(2); + if (typedefToken->strAt(2) == typedefInfo.name) { + typedefInfo.tagLine = typedefToken->tokAt(2)->linenr(); + typedefInfo.tagColumn = typedefToken->tokAt(2)->column(); + } } typedefInfo.used = t.second.isUsed(); typedefInfo.isFunctionPointer = isFunctionPointer(t.second.nameToken()); @@ -1167,11 +1192,10 @@ void Tokenizer::simplifyTypedefCpp() std::vector spaceInfo(1); const std::time_t maxTime = mSettings.typedefMaxTime > 0 ? std::time(nullptr) + mSettings.typedefMaxTime: 0; - const bool doProgress = (mSettings.reportProgress != -1) && !list.getFiles().empty(); + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, list.getSourceFilePath(), "Tokenize (typedef)"); for (Token *tok = list.front(); tok; tok = tok->next()) { - if (doProgress) - mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue()); + progressReporter.report(tok->progressValue()); if (Settings::terminated()) return; @@ -2419,7 +2443,8 @@ namespace { while (scope && scope->parent) { if (scope->name.empty()) break; - fullName = scope->name + " :: " + fullName; + fullName.insert(0, " :: "); + fullName.insert(0, scope->name); scope = scope->parent; } } @@ -2697,6 +2722,9 @@ namespace { return false; } + if (tok1->tokAt(-1)->tokType() == Token::eType || tok1->tokAt(-1)->tokType() == Token::eName) + return false; + if (Token::Match(tok1->tokAt(-1), "class|struct|union|enum|namespace")) { // fixme return false; @@ -2888,7 +2916,7 @@ static const Token* skipConstVolatileBackwards(const Token* tok) { bool Tokenizer::simplifyUsing() { - if (!isCPP() || mSettings.standards.cpp < Standards::CPP11) + if (!isCPP()) return false; // simplify using N::x; to using x = N::x; @@ -2929,11 +2957,10 @@ bool Tokenizer::simplifyUsing() }; std::list usingList; - const bool doProgress = (mSettings.reportProgress != -1) && !list.getFiles().empty(); + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, list.getSourceFilePath(), "Tokenize (using)"); for (Token *tok = list.front(); tok; tok = tok->next()) { - if (doProgress) - mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (using)", tok->progressValue()); + progressReporter.report(tok->progressValue()); if (Settings::terminated()) return substitute; @@ -2997,6 +3024,9 @@ bool Tokenizer::simplifyUsing() if (!usingEnd) continue; + for (Token *typeTok = start; typeTok != usingEnd; typeTok = typeTok->next()) + typeTok->isSimplifiedTypedef(true); + // Move struct defined in using out of using. // using T = struct t { }; => struct t { }; using T = struct t; // fixme: this doesn't handle attributes @@ -3483,7 +3513,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration, int fileIndex) mConfiguration = configuration; if (mTimerResults) { - Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mSettings.showtime, mTimerResults); + Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mTimerResults); if (!simplifyTokenList1(list.getFiles().front().c_str())) return false; } else { @@ -3491,18 +3521,16 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration, int fileIndex) return false; } - const ShowTime showTime = mTimerResults ? mSettings.showtime : ShowTime::NONE; - - Timer::run("Tokenizer::simplifyTokens1::createAst", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::createAst", mTimerResults, [&]() { list.createAst(); list.validateAst(mSettings.debugnormal); }); - Timer::run("Tokenizer::simplifyTokens1::createSymbolDatabase", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::createSymbolDatabase", mTimerResults, [&]() { createSymbolDatabase(); }); - Timer::run("Tokenizer::simplifyTokens1::setValueType", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::setValueType", mTimerResults, [&]() { mSymbolDatabase->setValueTypeInTokenList(false); mSymbolDatabase->setValueTypeInTokenList(true); }); @@ -3517,7 +3545,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration, int fileIndex) const bool doValueFlow = !disableValueflowEnv || (std::strcmp(disableValueflowEnv, "1") != 0); if (doValueFlow) { - Timer::run("Tokenizer::simplifyTokens1::ValueFlow", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::ValueFlow", mTimerResults, [&]() { ValueFlow::setValues(list, *mSymbolDatabase, mErrorLogger, mSettings, mTimerResults); }); @@ -3787,7 +3815,7 @@ void Tokenizer::simplifyParenthesizedLibraryFunctions() if (!Token::simpleMatch(tok, ") (")) continue; Token *rpar = tok, *lpar = tok->link(); - if (!lpar || Token::Match(lpar->previous(), "%name%")) + if (!lpar || (Token::Match(lpar->previous(), "%name%") && !Token::Match(lpar->previous(), "return|delete|throw"))) continue; const Token *ftok = rpar->previous(); if (mSettings.library.isNotLibraryFunction(ftok)) @@ -4230,10 +4258,13 @@ void Tokenizer::simplifyTemplates() namespace { /** Class used in Tokenizer::setVarIdPass1 */ class VariableMap { + public: + struct VarInfo { nonneg int id{}; bool assigned{}; }; + using MapType = std::unordered_map; private: - std::unordered_map mVariableId; - std::unordered_map mVariableId_global; - std::stack>> mScopeInfo; + MapType mVariableId; + MapType mVariableId_global; + std::stack> mScopeInfo; mutable nonneg int mVarId{}; public: VariableMap() = default; @@ -4244,7 +4275,10 @@ namespace { return mVariableId.find(varname) != mVariableId.end(); } - const std::unordered_map& map(bool global) const { + const MapType& map(bool global) const { + return global ? mVariableId_global : mVariableId; + } + MapType& map(bool global) { return global ? mVariableId_global : mVariableId; } nonneg int& getVarId() { @@ -4264,8 +4298,8 @@ bool VariableMap::leaveScope() if (mScopeInfo.empty()) return false; - for (const std::pair& outerVariable : mScopeInfo.top()) { - if (outerVariable.second != 0) + for (const MapType::value_type& outerVariable : mScopeInfo.top()) { + if (outerVariable.second.id != 0) mVariableId[outerVariable.first] = outerVariable.second; else mVariableId.erase(outerVariable.first); @@ -4277,21 +4311,22 @@ bool VariableMap::leaveScope() void VariableMap::addVariable(const std::string& varname, bool globalNamespace) { if (mScopeInfo.empty()) { - mVariableId[varname] = ++mVarId; + mVariableId[varname].id = ++mVarId; if (globalNamespace) mVariableId_global[varname] = mVariableId[varname]; return; } const auto it = mVariableId.find(varname); if (it == mVariableId.end()) { - mScopeInfo.top().emplace_back(varname, 0); - mVariableId[varname] = ++mVarId; + mScopeInfo.top().emplace_back(varname, VarInfo{}); + mVariableId[varname].id = ++mVarId; if (globalNamespace) mVariableId_global[varname] = mVariableId[varname]; return; } mScopeInfo.top().emplace_back(varname, it->second); - it->second = ++mVarId; + it->second.id = ++mVarId; + it->second.assigned = false; } /** @@ -4468,6 +4503,10 @@ static void setVarIdStructMembers(Token *&tok1, tok->varId(it->second); } } + if (Token::Match(tok, "%name% = { . %name% =|{")) { + setVarIdStructMembers(tok, structMembers, varId); + tok = tok->linkAt(2); + } tok = tok->next(); } @@ -4508,14 +4547,14 @@ static void setVarIdStructMembers(Token *&tok1, static void addTemplateVarIdUsage(const std::string &tokstr, const std::map>& templateVarUsage, - const std::unordered_map& variableMap, + const VariableMap::MapType& variableMap, std::set& templateVarIdUsage) { const auto v = templateVarUsage.find(tokstr); if (v != templateVarUsage.end()) { for (const std::string& varname: v->second) { const auto it = variableMap.find(varname); if (it != variableMap.end()) - templateVarIdUsage.insert(it->second); + templateVarIdUsage.insert(it->second.id); } } } @@ -4572,7 +4611,7 @@ static bool setVarIdClassDeclaration(Token* const startToken, } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) { const auto it = variableMap.map(false).find(tok->str()); if (it != variableMap.map(false).end()) { - tok->varId(it->second); + tok->varId(it->second.id); } } else if (tok->isName() && tok->varId() <= scopeStartVarId) { if (indentlevel > 0 || initList) { @@ -4590,7 +4629,7 @@ static bool setVarIdClassDeclaration(Token* const startToken, if (!inEnum) { const auto it = variableMap.map(false).find(tok->str()); if (it != variableMap.map(false).end()) { - tok->varId(it->second); + tok->varId(it->second.id); setVarIdStructMembers(tok, structMembers, variableMap.getVarId()); } else if (tok->str().back() == '>') { addTemplateVarIdUsage(tok->str(), templateVarUsage, variableMap.map(false), templateVarIdUsage); @@ -4628,7 +4667,7 @@ void Tokenizer::setVarIdClassFunction(const std::string &classname, if (Token::Match(tok2, "%name% ::")) continue; - const auto it = utils::as_const(varlist).find(tok2->str()); + const auto it = varlist.find(tok2->str()); if (it != varlist.end()) { tok2->varId(it->second); setVarIdStructMembers(tok2, structMembers, varId_); @@ -4871,6 +4910,8 @@ void Tokenizer::setVarIdPass1() mTemplateSimplifier->getUsedVariables(), variableMap.map(true), mTemplateVarIdUsage); + if (!tok3->next()) + syntaxError(tok3); } } @@ -4884,7 +4925,7 @@ void Tokenizer::setVarIdPass1() if (declTypeTok) { for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) { if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str())) - declTok->varId(variableMap.map(false).find(declTok->str())->second); + declTok->varId(variableMap.map(false).find(declTok->str())->second.id); } } @@ -4934,7 +4975,7 @@ void Tokenizer::setVarIdPass1() decl = false; } else if (cpp && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style if (tok2->link() != tok2->next() && // add value-initialized variable T x{}; - (Token::Match(prev2, "do|try|else") || Token::Match(prev2->tokAt(-2), "struct|class|:"))) + (Token::Match(prev2, "do|try|else") || Token::simpleMatch(prev2->tokAt(-2), ":"))) continue; } else decl = false; @@ -4964,7 +5005,7 @@ void Tokenizer::setVarIdPass1() Token::Match(tok->tokAt(-1), ":: %name%"))) { const auto it = variableMap.map(false).find(tok->str()); if (it != variableMap.map(false).end()) - tok->varId(it->second); + tok->varId(it->second.id); } tok = tok->next(); } @@ -5027,8 +5068,8 @@ void Tokenizer::setVarIdPass1() // there are tokens which can't appear at the begin of a function declaration such as "return" const bool isNotstartKeyword = start->next() && notstart.find(start->strAt(1)) != notstart.end(); - // now check if it is a function declaration - if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword) { + // now check if it is a function (pointer) declaration + if ((Token::simpleMatch(start, ") (") || Token::Match(start, "[;{}] %type% %name%|*")) && par && Token::Match(end, ") [;=]") && !isNotstartKeyword) { // function declaration => don't set varid tok = end; continue; @@ -5039,8 +5080,11 @@ void Tokenizer::setVarIdPass1() !Token::simpleMatch(tok->next(), ": ;") && !(tok->tokAt(-1) && Token::Match(tok->tokAt(-2), "{|, ."))) { const auto it = variableMap.map(globalNamespace).find(tok->str()); if (it != variableMap.map(globalNamespace).end()) { - tok->varId(it->second); - setVarIdStructMembers(tok, structMembers, variableMap.getVarId()); + if (!it->second.assigned || !Token::Match(tok->previous(), "%type% %name% (") || tok->previous()->isKeyword()) { + it->second.assigned = true; + tok->varId(it->second.id); + setVarIdStructMembers(tok, structMembers, variableMap.getVarId()); + } } } } else if (Token::Match(tok, "::|. %name%") && Token::Match(tok->previous(), ")|]|>|%name%")) { @@ -5540,7 +5584,7 @@ void Tokenizer::createLinks2() while (!type.empty() && type.top()->str() == "<") { const Token* end = type.top()->findClosingBracket(); - if (Token::Match(end, "> %comp%|;|.|=|{|(|::")) + if (Token::Match(end, "> %comp%|;|.|=|{|}|(|)|::")) break; // Variable declaration if (Token::Match(end, "> %var% ;") && (type.top()->tokAt(-2) == nullptr || Token::Match(type.top()->tokAt(-2), ";|}|{"))) @@ -5712,25 +5756,11 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) validate(); - const ShowTime showTime = mTimerResults ? mSettings.showtime : ShowTime::NONE; - // Bail out if code is garbage - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", mTimerResults, [&]() { findGarbageCode(); }); - // if (x) MACRO() .. - for (const Token *tok = list.front(); tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "if (")) { - tok = tok->linkAt(1); - if (Token::Match(tok, ") %name% (") && - tok->next()->isUpperCaseName() && - Token::Match(tok->linkAt(2), ") {|else")) { - syntaxError(tok->next()); - } - } - } - if (Settings::terminated()) return false; @@ -5761,14 +5791,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // simplify compound statements: "[;{}] ( { code; } ) ;"->"[;{}] code;" simplifyCompoundStatements(); - // check for simple syntax errors.. - for (const Token *tok = list.front(); tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "> struct {") && - Token::simpleMatch(tok->linkAt(2), "} ;")) { - syntaxError(tok); - } - } - if (!simplifyAddBraces()) return false; @@ -5872,7 +5894,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) simplifyTypedefLHS(); // typedef.. - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", mTimerResults, [&]() { simplifyTypedef(); }); @@ -5966,7 +5988,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) simplifyTypeIntrinsics(); // Handle templates.. - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", mTimerResults, [&]() { simplifyTemplates(); }); @@ -5993,13 +6015,16 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId" - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", showTime, mTimerResults, [&](){ + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", mTimerResults, [&](){ setVarId(); }); // Link < with > createLinks2(); + // Handle std::aligned_storage<...> + simplifyAlignedStorage(); + // Mark C++ casts markCppCasts(); @@ -6360,6 +6385,12 @@ std::string Tokenizer::dumpTypedefInfo() const outs += typedefInfo.name; outs += "\""; + if (!typedefInfo.originalName.empty()) { + outs += " originalName=\""; + outs += typedefInfo.originalName; + outs += "\""; + } + outs += " file=\""; outs += ErrorLogger::toxml(typedefInfo.filename); outs += "\""; @@ -7816,12 +7847,12 @@ bool Tokenizer::simplifyCAlternativeTokens() if (!tok->isName()) continue; - const auto cOpIt = utils::as_const(cAlternativeTokens).find(tok->str()); + const auto cOpIt = cAlternativeTokens.find(tok->str()); if (cOpIt != cAlternativeTokens.end()) { alt.push_back(tok); // Is this a variable declaration.. - if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=]")) + if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=)]")) return false; if (!Token::Match(tok->previous(), "%name%|%num%|%char%|%str%|)|]|> %name% %name%|%num%|%char%|%op%|%str%|(")) @@ -7839,6 +7870,10 @@ bool Tokenizer::simplifyCAlternativeTokens() } else if (Token::Match(tok, "not|compl")) { alt.push_back(tok); + // Is this a variable/parameter declaration + if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=)]")) + return false; + if ((Token::Match(tok->previous(), "%assign%") || Token::Match(tok->next(), "%num%")) && !Token::Match(tok->next(), ".|->")) { replaceAll = true; continue; @@ -7858,7 +7893,7 @@ bool Tokenizer::simplifyCAlternativeTokens() return false; for (Token *tok: alt) { - const auto cOpIt = utils::as_const(cAlternativeTokens).find(tok->str()); + const auto cOpIt = cAlternativeTokens.find(tok->str()); if (cOpIt != cAlternativeTokens.end()) tok->str(cOpIt->second); else if (tok->str() == "not") @@ -7979,8 +8014,8 @@ void Tokenizer::elseif() if (Token::Match(tok2, "}|;")) { if (tok2->next() && tok2->strAt(1) != "else") { - tok->insertToken("{"); - tok2->insertToken("}"); + tok->insertToken("{")->isSimplifiedScope(true); + tok2->insertToken("}")->isSimplifiedScope(true); Token::createMutualLinks(tok->next(), tok2->next()); break; } @@ -8758,6 +8793,13 @@ void Tokenizer::findGarbageCode() const if (!Token::simpleMatch(tok->linkAt(1)->linkAt(2), ") ;")) syntaxError(tok->linkAt(1)->linkAt(2)); } + // if (x) MACRO() .. + if (Token::simpleMatch(tok, "if (")) { + const Token* tok2 = tok->linkAt(1); + if (Token::Match(tok2, ") %name% (") && tok2->next()->isUpperCaseName() && + Token::Match(tok2->linkAt(2), ") {|else")) + syntaxError(tok2->next()); + } } // keyword keyword @@ -8774,6 +8816,8 @@ void Tokenizer::findGarbageCode() const syntaxError(tok, prev == tok->previous() ? (prev->str() + " " + tok->str()) : (prev->str() + " .. " + tok->str())); } } + else if (tok->isStandardType() && tok->next() && tok->str() == tok->strAt(1) && tok->str() != "long") + syntaxError(tok); } // invalid struct declaration @@ -8971,7 +9015,7 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "[;([{] %comp%|%oror%|%or%|%|/")) syntaxError(tok); - if (Token::Match(tok, "%cop%|= ]") && !Token::simpleMatch(tok, "*") && !(cpp && Token::Match(tok->previous(), "%type%|[|,|%num% &|=|> ]"))) + if (Token::Match(tok, "%cop%|= ]") && !Token::simpleMatch(tok, "*") && !(cpp && Token::Match(tok->previous(), "<|%type%|[|,|%num% &|=|> ]"))) syntaxError(tok); if (Token::Match(tok, "[+-] [;,)]}]") && !(cpp && Token::simpleMatch(tok->previous(), "operator"))) syntaxError(tok); @@ -8995,6 +9039,8 @@ void Tokenizer::findGarbageCode() const if (!Token::Match(tok->next(), "%name%|*|~")) syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1)); } + if (Token::Match(tok, ".|-> .|->")) + syntaxError(tok); if (Token::Match(tok, "[{,] . %name%") && !Token::Match(tok->tokAt(3), "[.=[{]")) syntaxError(tok->next()); if (Token::Match(tok, "%name% %op% %name%") && !tok->isKeyword() && tok->next()->isIncDecOp()) @@ -9024,8 +9070,8 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "? %assign%")) syntaxError(tok); - if (Token::Match(tok, "!|~ %comp%") && - !(cpp && tok->strAt(1) == ">" && Token::simpleMatch(tok->tokAt(-1), "operator"))) + if (Token::Match(tok, "[!~+-/] %comp%") && + !(cpp && Token::Match(tok->next(), "[<>]") && Token::simpleMatch(tok->tokAt(-1), "operator"))) syntaxError(tok); if (Token::Match(tok, "%comp% {") && (!cpp || tok->str() != ">")) syntaxError(tok); @@ -9118,6 +9164,8 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::simpleMatch(tok, ": template") && !Token::Match(tok->tokAt(-1), "public|private|protected")) syntaxError(tok); + if (Token::Match(tok, "> class|struct|union {") && Token::simpleMatch(tok->linkAt(2), "} ;")) + syntaxError(tok); if (!Token::simpleMatch(tok, "template <")) continue; if (!tok->tokAt(2) || tok->tokAt(2)->isLiteral()) @@ -9767,10 +9815,19 @@ void Tokenizer::simplifyCPPAttribute() Token* atok = nullptr; if (Token::Match(tok->previous(), "%name%")) atok = tok->previous(); - else { + else if (Token::simpleMatch(tok->previous(), "]")) { + atok = tok; + while (atok && Token::simpleMatch(atok->previous(), "]")) { + atok = atok->linkAt(-1); + atok = atok ? atok->previous() : nullptr; + } + if (!Token::Match(atok, "%name%")) + atok = nullptr; + } else { atok = tok; while (isCPPAttribute(atok) || isAlignAttribute(atok)) atok = skipCPPOrAlignAttribute(atok)->next(); + atok = atok ? getVariableTokenAfterAttributes(atok) : atok; } if (atok) { std::string a; @@ -10276,18 +10333,25 @@ void Tokenizer::simplifyBitfields() } } -static bool isStdContainerOrIterator(const Token* tok, const Settings& settings) +static bool isStdContainerOrIterator(const Token* tok, const Library& library) { - const Library::Container* ctr = settings.library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true); + const Library::Container* ctr = library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true); return ctr && startsWith(ctr->startPattern, "std ::"); } -static bool isStdSmartPointer(const Token* tok, const Settings& settings) +static bool isStdSmartPointer(const Token* tok, const Library& library) { - const Library::SmartPointer* ptr = settings.library.detectSmartPointer(tok, /*withoutStd*/ true); + const Library::SmartPointer* ptr = library.detectSmartPointer(tok, /*withoutStd*/ true); return ptr && startsWith(ptr->name, "std::"); } +static bool isLibraryType(const Token* tok, const Library& library) +{ + return library.hasAnyTypeCheck("std::" + tok->str()) || + library.podtype("std::" + tok->str()) || + isStdContainerOrIterator(tok, library); +} + // Add std:: in front of std classes, when using namespace std; was given void Tokenizer::simplifyNamespaceStd() { @@ -10315,14 +10379,15 @@ void Tokenizer::simplifyNamespaceStd() if (start != tok && start->isName() && !start->isKeyword() && (!start->previous() || Token::Match(start->previous(), "[;{}]"))) userFunctions.insert(tok->str()); } - if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings.library.matchArguments(tok, "std::" + tok->str())) + if ((userFunctions.find(tok->str()) == userFunctions.end() && mSettings.library.matchArguments(tok, "std::" + tok->str())) || + (tok->tokAt(-1)->isKeyword() && isLibraryType(tok, mSettings.library))) insert = true; } else if (Token::simpleMatch(tok->next(), "<") && - (isStdContainerOrIterator(tok, mSettings) || isStdSmartPointer(tok, mSettings))) + (isStdContainerOrIterator(tok, mSettings.library) || isStdSmartPointer(tok, mSettings.library))) insert = true; - else if (mSettings.library.hasAnyTypeCheck("std::" + tok->str()) || - mSettings.library.podtype("std::" + tok->str()) || - isStdContainerOrIterator(tok, mSettings)) + else if (isLibraryType(tok, mSettings.library)) + insert = true; + else if (Token::simpleMatch(tok, "aligned_storage")) insert = true; if (insert) { @@ -10443,12 +10508,12 @@ void Tokenizer::simplifyMicrosoftStringFunctions() if (!mSettings.platform.isWindows()) return; - const bool ansi = mSettings.platform.type == Platform::Type::Win32A; + const bool ansi = (mSettings.platform.type == Platform::Type::Win32A); // TODO: check for UNICODE define instead for (Token *tok = list.front(); tok; tok = tok->next()) { if (tok->strAt(1) != "(") continue; - const auto match = utils::as_const(apis).find(tok->str()); + const auto match = apis.find(tok->str()); if (match!=apis.end()) { tok->str(ansi ? match->second.mbcs : match->second.unicode); tok->originalName(match->first); @@ -11139,6 +11204,57 @@ void Tokenizer::simplifyNamespaceAliases() } } +void Tokenizer::simplifyAlignedStorage() +{ + if (!isCPP()) + return; + + const Standards::cppstd_t std = mSettings.standards.cpp; + if (std < Standards::CPP11 || std >= Standards::CPP23) + return; + + for (Token *tok = list.front(); tok; tok = tok->next()) { + if (!Token::simpleMatch(tok, "std :: aligned_storage <")) + continue; + + tok = tok->tokAt(3); + const Token *end = tok->link(); + tok = tok->next(); + + if (!tok) + break; + + if (!end) + continue; + + for (; tok != end; tok = tok->next()) { + if (Token::simpleMatch(tok, ",")) { + tok = tok->next(); + break; + } + + if (Token::Match(tok, "(|<")) + tok = tok->link(); + } + + std::string str; + for (; tok != end; tok = tok->next()) { + str += " " + tok->str(); + } + + if (str.empty()) + continue; + + if (!Token::Match(tok, "> :: type %name%")) + continue; + + str = str.substr(1); + + tok = tok->tokAt(3); + tok->addAttributeAlignas(str); + } +} + void Tokenizer::setDirectives(std::list directives) { mDirectives = std::move(directives); diff --git a/lib/tokenize.h b/lib/tokenize.h index 61d1003f316..f7f6ddbecae 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ class Settings; class SymbolDatabase; -class TimerResults; +class TimerResultsIntf; class Token; class TemplateSimplifier; class ErrorLogger; @@ -53,7 +53,7 @@ class CPPCHECKLIB Tokenizer { Tokenizer(TokenList tokenList, ErrorLogger &errorLogger); ~Tokenizer(); - void setTimerResults(TimerResults *tr) { + void setTimerResults(TimerResultsIntf *tr) { mTimerResults = tr; } @@ -528,6 +528,11 @@ class CPPCHECKLIB Tokenizer { */ void simplifyNamespaceAliases(); + /** + * Handle std::aligned_storage<...> + */ + void simplifyAlignedStorage(); + /** * Convert C++17 style nested namespace to older style */ @@ -693,13 +698,14 @@ class CPPCHECKLIB Tokenizer { }; struct TypedefInfo { std::string name; + std::string originalName; std::string filename; - int lineNumber; - int column; + int lineNumber{}; + int column{}; int tagLine{-1}; int tagColumn{-1}; - bool used; - bool isFunctionPointer; + bool used{}; + bool isFunctionPointer{}; std::vector typedefInfoTokens; }; std::vector mTypedefInfo; @@ -713,9 +719,9 @@ class CPPCHECKLIB Tokenizer { nonneg int mUnnamedCount{}; /** - * TimerResults + * timer results */ - TimerResults* mTimerResults{}; + TimerResultsIntf* mTimerResults{}; }; /// @} diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 7fccbb89f1d..6c4cd7eb981 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -198,6 +198,7 @@ void TokenList::addtoken(const Token * tok, const nonneg int lineno, const nonne mTokensFrontBack->back->column(column); mTokensFrontBack->back->fileIndex(fileno); mTokensFrontBack->back->flags(tok->flags()); + mTokensFrontBack->back->tokType(tok->tokType()); } void TokenList::addtoken(const Token *tok, const Token *locationTok) @@ -219,6 +220,7 @@ void TokenList::addtoken(const Token *tok, const Token *locationTok) mTokensFrontBack->back->linenr(locationTok->linenr()); mTokensFrontBack->back->column(locationTok->column()); mTokensFrontBack->back->fileIndex(locationTok->fileIndex()); + mTokensFrontBack->back->tokType(tok->tokType()); } void TokenList::addtoken(const Token *tok) @@ -242,6 +244,7 @@ void TokenList::addtoken(const Token *tok) mTokensFrontBack->back->linenr(tok->linenr()); mTokensFrontBack->back->column(tok->column()); mTokensFrontBack->back->fileIndex(tok->fileIndex()); + mTokensFrontBack->back->tokType(tok->tokType()); } @@ -330,8 +333,26 @@ bool TokenList::createTokensFromBuffer(const char* data, size_t size) //--------------------------------------------------------------------------- +#ifdef STORE_INPUT_DIR +#include +#include + +static void storeInput(const char* data, size_t size) +{ + static std::atomic_uint64_t num(0); + { + std::ofstream out(STORE_INPUT_DIR "/" + std::to_string(num++)); + out.write(data, size); + } +} +#endif + bool TokenList::createTokensFromBufferInternal(const char* data, size_t size, const std::string& file0) { +#ifdef STORE_INPUT_DIR + storeInput(data, size); +#endif + simplecpp::OutputList outputList; simplecpp::TokenList tokens({data, size}, mFiles, file0, &outputList); @@ -443,7 +464,7 @@ static Token* skipDecl(Token* tok, std::vector* inner = nullptr) if (!Token::Match(tok->previous(), "( %name%")) return tok; Token *vartok = tok; - while (Token::Match(vartok, "%name%|*|&|::|<")) { + while (Token::Match(vartok, "%name%|*|&|&&|::|<")) { if (vartok->str() == "<") { if (vartok->link()) vartok = vartok->link(); @@ -586,10 +607,16 @@ static bool iscpp11init_impl(const Token * const tok) if (nameToken->str() == ">" && nameToken->link()) nameToken = nameToken->link()->previous(); if (Token::Match(nameToken, "]|*")) { - const Token* newTok = nameToken->link() ? nameToken->link()->previous() : nameToken->previous(); - while (Token::Match(newTok, "%type%|::|*") && !newTok->isKeyword()) - newTok = newTok->previous(); - if (Token::simpleMatch(newTok, "new")) + const Token* tok2 = nameToken; + if (tok2->link()) { + while (tok2 && tok2->link()) + tok2 = tok2->link()->previous(); + } + else + tok2 = tok2->previous(); + while (Token::Match(tok2, "%type%|::|*") && !tok2->isKeyword()) + tok2 = tok2->previous(); + if (Token::Match(tok2, "new|%var%")) return true; } @@ -731,6 +758,8 @@ static void compileBinOp(Token *&tok, AST_state& state, void (*f)(Token *&tok, A binop->astOperand1(state.op.top()); state.op.pop(); } + if (!state.op.empty() && state.op.top() == binop) + throw InternalError(tok, "Syntax Error: Infinite loop when creating AST.", InternalError::AST); state.op.push(binop); } @@ -873,7 +902,7 @@ static void compileTerm(Token *&tok, AST_state& state) state.inArrayAssignment--; tok = tok1->link()->next(); } - } else if (!state.inArrayAssignment && !Token::simpleMatch(prev, "=")) { + } else if ((!state.inArrayAssignment && !Token::simpleMatch(prev, "=")) || Token::simpleMatch(prev, "?")) { state.op.push(tok); tok = tok->link()->next(); } else { @@ -1055,7 +1084,12 @@ static void compilePrecedence2(Token *&tok, AST_state& state) else compileUnaryOp(tok, state, compileExpression); tok = tok2->link()->next(); - } else if (Token::simpleMatch(tok->previous(), "requires {")) { + } else if ((Token::simpleMatch(tok->tokAt(-1), "requires {") && tok->tokAt(-1)->isKeyword()) + || (Token::simpleMatch(tok->tokAt(-1), ")") + && tok->linkAt(-1) + && Token::simpleMatch(tok->linkAt(-1)->tokAt(-1), "requires (") && tok->linkAt(-1)->tokAt(-1)->isKeyword())) { + if (!tok->link()) + throw InternalError(tok, "Syntax error, token has no link.", InternalError::AST); tok->astOperand1(state.op.top()); state.op.pop(); state.op.push(tok); @@ -1585,6 +1619,13 @@ static Token * createAstAtToken(Token *tok) if (Token::Match(tok2, "%var% [;,)]")) return tok2; } + if (Token::Match(tok, "enum class| %name%| :")) { + if (Token::simpleMatch(tok->next(), "class")) + tok = tok->next(); + if (Token::Match(tok->next(), "%name%")) + tok = tok->next(); + return tok->next(); + } if (Token *const endTok = skipMethodDeclEnding(tok)) { Token *tok2 = tok; do { @@ -1602,7 +1643,7 @@ static Token * createAstAtToken(Token *tok) if (Token::Match(tok, "%type%") && !Token::Match(tok, "return|throw|if|while|new|delete")) { bool isStandardTypeOrQualifier = false; Token* type = tok; - while (Token::Match(type, "%type%|*|&|<")) { + while (Token::Match(type, "%type%|*|&|&&|<")) { if (type->isName() && (type->isStandardType() || Token::Match(type, "const|mutable|static|volatile"))) isStandardTypeOrQualifier = true; if (type->str() == "<") { @@ -1780,8 +1821,9 @@ static Token * createAstAtToken(Token *tok) } } - if (Token::Match(tok, "%type% %name%|*|&|&&|::") && !Token::Match(tok, "return|new|delete")) { - int typecount = 0; + if ((Token::Match(tok, "%type% %name%|*|&|&&|::") && !Token::Match(tok, "return|new|delete")) || + (Token::Match(tok, ":: %type%") && !tok->next()->isKeyword())) { + int typecount = tok->str() == "::" ? 1 : 0; Token *typetok = tok; while (Token::Match(typetok, "%type%|::|*|&|&&|<")) { if (typetok->isName() && !Token::simpleMatch(typetok->previous(), "::")) @@ -1795,7 +1837,7 @@ static Token * createAstAtToken(Token *tok) } typetok = typetok->next(); } - if (Token::Match(typetok, "%var% =") && typetok->varId()) + if (Token::Match(typetok, "%var% [={]")) tok = typetok; // Do not create AST for function declaration @@ -1804,7 +1846,7 @@ static Token * createAstAtToken(Token *tok) !Token::Match(tok, "return|throw") && Token::Match(typetok->previous(), "%name% ( !!*") && typetok->previous()->varId() == 0 && - !typetok->previous()->isKeyword() && + (!typetok->previous()->isKeyword() || typetok->previous()->isOperatorKeyword()) && (skipMethodDeclEnding(typetok->link()) || Token::Match(typetok->link(), ") ;|{"))) return typetok; } @@ -2285,7 +2327,7 @@ bool TokenList::isCPP() const return mLang == Standards::Language::CPP; } -const Token * TokenList::isFunctionHead(const Token *tok, const std::string &endsWith) +const Token * TokenList::isFunctionHead(const Token *tok, const std::string &suffix) { if (!tok) return nullptr; @@ -2298,11 +2340,11 @@ const Token * TokenList::isFunctionHead(const Token *tok, const std::string &end if (Token::Match(tok, ") ;|{|[")) { tok = tok->next(); while (tok && tok->str() == "[" && tok->link()) { - if (endsWith.find(tok->str()) != std::string::npos) + if (suffix.find(tok->str()) != std::string::npos) return tok; tok = tok->link()->next(); } - return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr; + return (tok && suffix.find(tok->str()) != std::string::npos) ? tok : nullptr; } if (tok->isCpp() && tok->str() == ")") { tok = tok->next(); @@ -2337,7 +2379,7 @@ const Token * TokenList::isFunctionHead(const Token *tok, const std::string &end } if (tok && tok->str() == ":" && !Token::Match(tok->next(), "%name%|::")) return nullptr; - return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr; + return (tok && suffix.find(tok->str()) != std::string::npos) ? tok : nullptr; } return nullptr; } diff --git a/lib/tokenlist.h b/lib/tokenlist.h index 764eb67bdee..f5b652f3506 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,7 +56,7 @@ class CPPCHECKLIB TokenList { TokenList(const TokenList &) = delete; TokenList &operator=(const TokenList &) = delete; - TokenList(TokenList&& other) NOEXCEPT = default; + TokenList(TokenList&& other) noexcept = default; /** @return the source file path. e.g. "file.cpp" */ const std::string& getSourceFilePath() const; @@ -206,10 +206,10 @@ class CPPCHECKLIB TokenList { /** * is token pointing at function head? * @param tok A '(' or ')' token in a possible function head - * @param endsWith string after function head - * @return token matching with endsWith if syntax seems to be a function head else nullptr + * @param suffix string after function head + * @return token matching with suffix if syntax seems to be a function head else nullptr */ - static const Token * isFunctionHead(const Token *tok, const std::string &endsWith); + static const Token * isFunctionHead(const Token *tok, const std::string &suffix); const Settings& getSettings() const { return mSettings; diff --git a/lib/utils.h b/lib/utils.h index c59e4d3a32c..3f9c4ab949f 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -124,6 +124,11 @@ bool endsWith(const std::string& str, const char (&end)[N]) return endsWith(str, end, N - 1); } +inline bool endsWith(const std::string& str, const std::string& end) +{ + return endsWith(str, end.c_str(), end.length()); +} + inline static bool isPrefixStringCharLiteral(const std::string &str, char q, const std::string& p) { // str must be at least the prefix plus the start and end quote @@ -215,7 +220,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) tmp = std::stoll(str, &idx); if (idx != str.size()) { if (err) - *err = "not an integer"; + *err = "not an integer (pos)"; return false; } } catch (const std::out_of_range&) { @@ -224,7 +229,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) return false; } catch (const std::invalid_argument &) { if (err) - *err = "not an integer"; + *err = "not an integer (invalid_argument)"; return false; } if (str.front() == '-' && std::numeric_limits::min() == 0) { @@ -232,6 +237,16 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) *err = "needs to be positive"; return false; } + if (str.front() != '+' && str.front() != '-' && isdigit(str.front()) == 0) { + if (err) + *err = "not an integer"; + return false; + } + if (str.size() > 1 && str.front() == '0') { + if (err) + *err = "not an integer"; + return false; + } if (tmp < std::numeric_limits::min() || tmp > std::numeric_limits::max()) { if (err) *err = "out of range (limits)"; @@ -250,7 +265,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) tmp = std::stoull(str, &idx); if (idx != str.size()) { if (err) - *err = "not an integer"; + *err = "not an integer (pos)"; return false; } } catch (const std::out_of_range&) { @@ -259,7 +274,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) return false; } catch (const std::invalid_argument &) { if (err) - *err = "not an integer"; + *err = "not an integer (invalid_argument)"; return false; } if (str.front() == '-') { @@ -267,6 +282,16 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) *err = "needs to be positive"; return false; } + if (str.front() != '+' && isdigit(str.front()) == 0) { + if (err) + *err = "not an integer"; + return false; + } + if (str.size() > 1 && str.front() == '0') { + if (err) + *err = "not an integer"; + return false; + } if (tmp > std::numeric_limits::max()) { if (err) *err = "out of range (limits)"; @@ -276,6 +301,9 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) return true; } +/** + * @throws std::runtime_error thrown if conversion failed + */ template T strToInt(const std::string& str) { @@ -395,17 +423,23 @@ static inline T* empty_if_null(T* p) } /** - * Split string by given sperator. + * Split string by given separator. * @param str The string to split - * @param sep The seperator - * @return The list of seperate strings (including empty ones). The whole input string if no seperator found. + * @param sep The separator + * @return The list of separate strings (including empty ones). The whole input string if no separator found. */ CPPCHECKLIB std::vector splitString(const std::string& str, char sep); namespace utils { + /** + * Drop-in replacement for C++17's std::as_const + * @param t The function forms the lvalue reference to const type of this argument. + */ template constexpr typename std::add_const::type & as_const(T& t) noexcept { + static_assert(!std::is_const::value, "object is already const"); + static_assert(!std::is_pointer::value, "object is a pointer"); // NOLINTNEXTLINE(bugprone-return-const-ref-from-parameter) - potential false positive return t; } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index edd6634a0ea..3819bfc4b41 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -365,7 +365,7 @@ const Token *ValueFlow::parseCompareInt(const Token *tok, ValueFlow::Value &true }); } -static bool isEscapeScope(const Token* tok, const Settings& settings, bool unknown = false) +static bool isEscapeScope(const Token* tok, const Library& library, bool unknown = false) { if (!Token::simpleMatch(tok, "{")) return false; @@ -374,7 +374,7 @@ static bool isEscapeScope(const Token* tok, const Settings& settings, bool unkno if (termTok && termTok->scope() == tok->scope()) return true; std::string unknownFunction; - if (settings.library.isScopeNoReturn(tok->link(), &unknownFunction)) + if (library.isScopeNoReturn(tok->link(), &unknownFunction)) return unknownFunction.empty() || unknown; return false; } @@ -430,12 +430,7 @@ static void valueFlowNumber(TokenList &tokenlist, const Settings& settings) if (tokenlist.isCPP() || settings.standards.c >= Standards::C23) { for (Token *tok = tokenlist.front(); tok; tok = tok->next()) { - if (tok->isName() && !tok->varId() && Token::Match(tok, "%bool%")) { - ValueFlow::Value value(tok->str() == "true"); - if (!tok->isTemplateArg()) - value.setKnown(); - setTokenValue(tok, std::move(value), settings); - } else if (Token::Match(tok, "[(,] NULL [,)]")) { + if (Token::Match(tok, "[(,] NULL [,)]")) { // NULL function parameters are not simplified in the // normal tokenlist ValueFlow::Value value(0); @@ -504,7 +499,7 @@ static std::vector evaluateType(const Token* start, const Token* e return {}; result.insert(result.end(), inner.begin(), inner.end()); } else { - // We cant evaluate the decltype so bail + // We can't evaluate the decltype so bail return {}; } tok = tok->linkAt(1); @@ -903,10 +898,10 @@ static void valueFlowSameExpressions(TokenList& tokenlist, const Settings& setti long long val; - if (Token::Match(tok, "==|>=|<=|/")) { + if (Token::Match(tok, "==|>=|<=|/|/=")) { val = 1; } - else if (Token::Match(tok, "!=|>|<|%|-")) { + else if (Token::Match(tok, "!=|>|<|%|%=|-|-=|^|^=")) { val = 0; } else @@ -1210,6 +1205,12 @@ static void valueFlowEnumValue(SymbolDatabase & symboldatabase, const Settings & } } +// trampoline to generate unique timer results entry +static void valueFlowEnumValueEarly(SymbolDatabase & symboldatabase, const Settings & settings) +{ + valueFlowEnumValue(symboldatabase, settings); +} + static void valueFlowGlobalConstVar(TokenList& tokenList, const Settings& settings) { // Get variable values... @@ -1511,7 +1512,7 @@ ValueFlow::Value ValueFlow::getLifetimeObjValue(const Token *tok, bool inconclus // There should only be one lifetime if (values.size() != 1) return ValueFlow::Value{}; - return values.front(); + return std::move(values.front()); } template @@ -3043,7 +3044,7 @@ static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, co // Skip if its a free function that doesnt yield an iterator to the container if (Token::Match(parent->previous(), "%name% (") && !contains({Library::Container::Yield::START_ITERATOR, Library::Container::Yield::END_ITERATOR}, - astFunctionYield(parent->previous(), settings))) + astFunctionYield(parent->previous(), settings.library))) continue; ValueFlow::Value master; @@ -3055,7 +3056,7 @@ static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, co master.lifetimeKind = ValueFlow::Value::LifetimeKind::Iterator; } else if (astIsIterator(parent) && Token::Match(parent->previous(), "%name% (") && contains({Library::Container::Yield::START_ITERATOR, Library::Container::Yield::END_ITERATOR}, - astFunctionYield(parent->previous(), settings))) { + astFunctionYield(parent->previous(), settings.library))) { master.errorPath.emplace_back(parent, "Iterator to container is created here."); master.lifetimeKind = ValueFlow::Value::LifetimeKind::Iterator; } else if ((astIsPointer(parent->tokAt(2)) && @@ -3217,6 +3218,14 @@ static Token* findEndOfFunctionCallForParameter(Token* parameterToken) return nextAfterAstRightmostLeaf(parent); } +static bool isTryEmplace(const Token* tok) +{ + if (tok->str() != "(" || !Token::simpleMatch(tok->astOperand1(), ".") || !tok->astOperand1()->astOperand1() || !Token::simpleMatch(tok->astOperand1()->astOperand2(), "try_emplace")) + return false; + const ValueType* vt = tok->astOperand1()->astOperand1()->valueType(); + return vt && vt->container && vt->container->stdAssociativeLike; +} + static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings) { if (!tokenlist.isCPP() || settings.standards.cpp < Standards::CPP11) @@ -3259,9 +3268,17 @@ static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase& const nonneg int varId = varTok->varId(); // x is not MOVED after assignment if code is: x = ... std::move(x) .. ; const Token *parent = tok->astParent(); + bool bail = false; while (parent && parent->str() != "=" && parent->str() != "return" && - !(parent->str() == "(" && isOpenParenthesisMemberFunctionCallOfVarId(parent, varId))) + !(parent->str() == "(" && isOpenParenthesisMemberFunctionCallOfVarId(parent, varId))) { + if (isTryEmplace(parent)) { + bail = true; + break; + } parent = parent->astParent(); + } + if (bail) + continue; if (parent && (parent->str() == "return" || // MOVED in return statement parent->str() == "(")) // MOVED in self assignment, isOpenParenthesisMemberFunctionCallOfVarId == true @@ -3462,7 +3479,7 @@ static void valueFlowConditionExpressions(const TokenList& tokenlist, } // Check if the block terminates early - if (isEscapeScope(blockTok, settings)) { + if (isEscapeScope(blockTok, settings.library)) { const Scope* scope2 = scope; // If escaping a loop then only use the loop scope if (isBreakOrContinueScope(blockTok->link())) { @@ -3652,7 +3669,7 @@ static void valueFlowSymbolicOperators(const SymbolDatabase& symboldatabase, con continue; ValueFlow::Value v = makeSymbolic(arg); - v.errorPath = c.errorPath; + v.errorPath = std::move(c.errorPath); v.errorPath.emplace_back(tok, "Passed to " + tok->str()); if (c.intvalue == 0) v.setImpossible(); @@ -3682,7 +3699,7 @@ static void valueFlowSymbolicOperators(const SymbolDatabase& symboldatabase, con continue; if (vartok->exprId() == 0) continue; - if (Token::Match(tok, "<<|>>|/") && !astIsLHS(vartok)) + if (Token::Match(tok, "<<|>>|/|-") && !astIsLHS(vartok)) continue; if (Token::Match(tok, "<<|>>|^|+|-|%or%") && constant->intvalue != 0) continue; @@ -4101,7 +4118,7 @@ static bool intersects(const C1& c1, const C2& c2) return false; } -static void valueFlowAfterAssign(TokenList &tokenlist, +static void valueFlowAfterAssign(const TokenList &tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger &errorLogger, const Settings &settings, @@ -4531,7 +4548,7 @@ struct ConditionHandler { } // Variable changed in loop code - const Token* const start = top; + const Token* const start = top->strAt(-1) == "for" ? top->astOperand2() : top; // skip init statement const Token* const block = top->link()->next(); const Token* const end = block->link(); @@ -4944,6 +4961,24 @@ static void valueFlowCondition(const ValuePtr& handler, handler->afterCondition(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions); } +static const Token* getConditionVariable(const Token* tok) +{ + if (tok->str() == "!") + return tok->astOperand1(); + + if (const Token* parent = tok->astParent()) { + if (Token::Match(parent, "%oror%|&&|?") || + Token::Match(parent->previous(), "if|while (") || + (parent->str() == ";" && astIsLHS(tok) && Token::simpleMatch(parent->astParent(), ";"))) { // for loop condition + if (Token::simpleMatch(tok, "=")) + return tok->astOperand1(); + if (!Token::Match(tok, "%comp%|%assign%")) + return tok; + } + } + return nullptr; +} + struct SimpleConditionHandler : ConditionHandler { std::vector parse(const Token* tok, const Settings& /*settings*/) const override { @@ -4962,19 +4997,7 @@ struct SimpleConditionHandler : ConditionHandler { if (!conds.empty()) return conds; - const Token* vartok = nullptr; - - if (tok->str() == "!") { - vartok = tok->astOperand1(); - - } else if (tok->astParent() && (Token::Match(tok->astParent(), "%oror%|&&|?") || - Token::Match(tok->astParent()->previous(), "if|while ("))) { - if (Token::simpleMatch(tok, "=")) - vartok = tok->astOperand1(); - else if (!Token::Match(tok, "%comp%|%assign%")) - vartok = tok; - } - + const Token* vartok = getConditionVariable(tok); if (!vartok) return {}; Condition cond; @@ -5070,8 +5093,7 @@ static void valueFlowInferCondition(TokenList& tokenlist, const Settings& settin std::vector result = infer(makeIntegralInferModel(), "!=", tok->values(), 0); if (result.size() != 1) continue; - ValueFlow::Value value = result.front(); - setTokenValue(tok, std::move(value), settings); + setTokenValue(tok, std::move(result.front()), settings); } } } @@ -5142,9 +5164,9 @@ struct SymbolicConditionHandler : SimpleConditionHandler { }; static bool valueFlowForLoop2(const Token *tok, - ProgramMemory *memory1, - ProgramMemory *memory2, - ProgramMemory *memoryAfter, + ProgramMemory &memory1, + ProgramMemory &memory2, + ProgramMemory &memoryAfter, const Settings& settings) { // for ( firstExpression ; secondExpression ; thirdExpression ) @@ -5187,13 +5209,10 @@ static bool valueFlowForLoop2(const Token *tok, } // TODO: add bailout message - if (memory1) - memory1->swap(startMemory); + memory1.swap(startMemory); if (!error) { - if (memory2) - memory2->swap(endMemory); - if (memoryAfter) - memoryAfter->swap(programMemory); + memory2.swap(endMemory); + memoryAfter.swap(programMemory); } return true; @@ -5368,7 +5387,7 @@ static void valueFlowForLoop(const TokenList &tokenlist, const SymbolDatabase& s valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, errorLogger, settings); } else { ProgramMemory mem1, mem2, memAfter; - if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter, settings)) { + if (valueFlowForLoop2(tok, mem1, mem2, memAfter, settings)) { for (const auto& p : mem1) { if (!p.second.isIntValue()) continue; @@ -5490,7 +5509,7 @@ static void valueFlowInjectParameter(const TokenList& tokenlist, const Settings& settings, const Variable* arg, const Scope* functionScope, - const std::list& argvalues) + std::list argvalues) { // Is argument passed by value or const reference, and is it a known non-class type? if (arg->isReference() && !arg->isConst() && !arg->isClass()) @@ -5504,7 +5523,7 @@ static void valueFlowInjectParameter(const TokenList& tokenlist, valueFlowForward(const_cast(functionScope->bodyStart->next()), functionScope->bodyEnd, arg->nameToken(), - argvalues, + std::move(argvalues), tokenlist, errorLogger, settings); @@ -5731,7 +5750,7 @@ static void valueFlowFunctionDefaultParameter(const TokenList& tokenlist, const argvalues.push_back(std::move(v)); } if (!argvalues.empty()) - valueFlowInjectParameter(tokenlist, errorLogger, settings, var, scope, argvalues); + valueFlowInjectParameter(tokenlist, errorLogger, settings, var, scope, std::move(argvalues)); } } } @@ -5959,9 +5978,12 @@ static Token* findStartToken(const Variable* var, Token* start, const Library& l })) return first->previous(); // Compute the outer scope - while (scope && scope->nestedIn != var->scope()) + while (scope && scope->nestedIn != var->scope()) { + if (scope->type == ScopeType::eLambda && !Token::simpleMatch(scope->bodyEnd, "} (")) + return start; scope = scope->nestedIn; - if (!scope) + } + if (!scope || (scope->type == ScopeType::eLambda && !Token::simpleMatch(scope->bodyEnd, "} ("))) return start; auto* tok = const_cast(scope->bodyStart); if (!tok) @@ -6199,6 +6221,8 @@ bool ValueFlow::isContainerSizeChanged(const Token* tok, int indirect, const Set return true; if (astIsLHS(tok) && Token::simpleMatch(tok->astParent(), "[")) return tok->valueType()->container->stdAssociativeLike; + if (Token::simpleMatch(tok->astParent(), "*") && indirect > 0) + return isContainerSizeChanged(tok->astParent(), indirect - 1, settings, depth + 1); const Library::Container::Action action = astContainerAction(tok, settings.library); switch (action) { case Library::Container::Action::RESIZE: @@ -6317,9 +6341,9 @@ static void valueFlowSmartPointer(TokenList &tokenlist, ErrorLogger & errorLogge } } -static Library::Container::Yield findIteratorYield(Token* tok, const Token*& ftok, const Settings& settings) +static Library::Container::Yield findIteratorYield(Token* tok, const Token*& ftok, const Library& library) { - auto yield = astContainerYield(tok, settings.library, &ftok); + auto yield = astContainerYield(tok, library, &ftok); if (ftok) return yield; @@ -6327,7 +6351,7 @@ static Library::Container::Yield findIteratorYield(Token* tok, const Token*& fto return yield; // begin/end free functions - return astFunctionYield(tok->astParent()->previous(), settings, &ftok); + return astFunctionYield(tok->astParent()->previous(), library, &ftok); } static void valueFlowIterators(TokenList& tokenlist, const Settings& settings) @@ -6340,7 +6364,7 @@ static void valueFlowIterators(TokenList& tokenlist, const Settings& settings) if (!astIsContainer(tok)) continue; const Token* ftok = nullptr; - const Library::Container::Yield yield = findIteratorYield(tok, ftok, settings); + const Library::Container::Yield yield = findIteratorYield(tok, ftok, settings.library); if (!ftok) continue; if (yield == Library::Container::Yield::START_ITERATOR) { @@ -6491,6 +6515,9 @@ static std::vector getContainerSizeFromConstructorArgs(const s if (astIsPointer(args[0])) { if (args.size() == 1 && args[0]->tokType() == Token::Type::eString) return {makeContainerSizeValue(Token::getStrLength(args[0]), known)}; + if (args.size() == 1 && args[0]->variable() && args[0]->variable()->isArray() && + args[0]->variable()->isConst() && args[0]->variable()->dimensions().size() == 1 && args[0]->variable()->dimensions()[0].known) + return {makeContainerSizeValue(args[0]->variable()->dimensions()[0].num, known)}; if (args.size() == 2 && astIsIntegral(args[1], false)) // { char*, count } return {makeContainerSizeValue(args[1], known)}; } else if (astIsContainer(args[0])) { @@ -6504,10 +6531,12 @@ static std::vector getContainerSizeFromConstructorArgs(const s return {}; } -static bool valueFlowIsSameContainerType(const ValueType& contType, const Token* tok, const Settings& settings) +static bool valueFlowIsSameContainerType(const ValueType& contType, const Token* tok, bool isView, const Settings& settings) { - if (!tok || !tok->valueType() || !tok->valueType()->containerTypeToken) + if (!tok || !tok->valueType()) return true; + if (!tok->valueType()->containerTypeToken) + return !isView; const ValueType tokType = ValueType::parseDecl(tok->valueType()->containerTypeToken, settings); return contType.isTypeEqual(&tokType) || tokType.type == ValueType::Type::UNKNOWN_TYPE; @@ -6536,7 +6565,7 @@ static std::vector getInitListSize(const Token* tok, initList = true; else if (vt.isIntegral() && astIsIntegral(args[0], false)) initList = true; - else if (args.size() == 1 && valueFlowIsSameContainerType(vt, tok->astOperand2(), settings)) + else if (args.size() == 1 && valueFlowIsSameContainerType(vt, tok->astOperand2(), valueType->container->view, settings)) initList = false; // copy ctor else if (args.size() == 2 && (!args[0]->valueType() || !args[1]->valueType())) // might be unknown iterators initList = false; @@ -6706,23 +6735,25 @@ static void valueFlowContainerSize(const TokenList& tokenlist, for (const ValueFlow::Value& value : values) setTokenValue(tok, value, settings); } - else if (Token::Match(tok->previous(), ",|( {|%str%")) { - int nArg{}; - if (const Token* funcTok = getTokenArgumentFunction(tok, nArg)) { - if (const Function* func = funcTok->function()) { - if (const Variable* var = func->getArgumentVar(nArg)) { - if (var->valueType() && var->valueType()->container && var->valueType()->container->size_templateArgNo < 0) { - auto values = tok->tokType() == Token::Type::eString - ? std::vector{makeContainerSizeValue(Token::getStrLength(tok))} - : getInitListSize(tok, var->valueType(), settings, true); - ValueFlow::Value tokValue; - tokValue.valueType = ValueFlow::Value::ValueType::TOK; - tokValue.tokvalue = tok; - tokValue.setKnown(); - values.push_back(std::move(tokValue)); - - for (const ValueFlow::Value &value : values) - setTokenValue(tok, value, settings); + else if (Token::Match(tok->previous(), ",|(") && (Token::Match(tok, "{|%str%") || settings.library.detectContainer(tok))) { + if (Token* argTok = tok->previous()->astOperand2()) { + int nArg{}; + if (const Token* funcTok = getTokenArgumentFunction(argTok, nArg)) { + if (const Function* func = funcTok->function()) { + if (const Variable* var = func->getArgumentVar(nArg)) { + if (var->valueType() && var->valueType()->container && var->valueType()->container->size_templateArgNo < 0) { + auto values = argTok->tokType() == Token::Type::eString + ? std::vector{makeContainerSizeValue(Token::getStrLength(argTok))} + : getInitListSize(argTok, var->valueType(), settings, true); + ValueFlow::Value tokValue; + tokValue.valueType = ValueFlow::Value::ValueType::TOK; + tokValue.tokvalue = argTok; + tokValue.setKnown(); + values.push_back(std::move(tokValue)); + + for (const ValueFlow::Value& value : values) + setTokenValue(argTok, value, settings); + } } } } @@ -6772,17 +6803,17 @@ static void valueFlowContainerSize(const TokenList& tokenlist, } else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) { const Token* containerTok = tok->astOperand1(); const Token* valueTok = tok->astOperand2(); - const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok); + const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok, settings); forwardMinimumContainerSize(size, tok, containerTok); } else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) { const Token* tok2 = tok->astOperand2(); MathLib::bigint size = 0; while (Token::simpleMatch(tok2, "+") && tok2->astOperand2()) { - size += ValueFlow::valueFlowGetStrLength(tok2->astOperand2()); + size += ValueFlow::valueFlowGetStrLength(tok2->astOperand2(), settings); tok2 = tok2->astOperand1(); } - size += ValueFlow::valueFlowGetStrLength(tok2); + size += ValueFlow::valueFlowGetStrLength(tok2, settings); forwardMinimumContainerSize(size, tok, tok->astOperand1()); } } @@ -7191,7 +7222,7 @@ struct ValueFlowPassRunner { bool run_once(std::initializer_list> passes) const { return std::any_of(passes.begin(), passes.end(), [&](const ValuePtr& pass) { - return run(pass); + return run(pass, 0); }); } @@ -7199,10 +7230,16 @@ struct ValueFlowPassRunner { { std::size_t values = 0; std::size_t n = state.settings.vfOptions.maxIterations; + const bool doProgress = state.settings.reportProgress >= 0; while (n > 0 && values != getTotalValues()) { values = getTotalValues(); + const std::size_t passnum = state.settings.vfOptions.maxIterations - n + 1; + const std::string passnum_s = std::to_string(passnum); if (std::any_of(passes.begin(), passes.end(), [&](const ValuePtr& pass) { - return run(pass); + // the string concatination is a hot spot in TestIO::testScanfArgument and TestIO::testPrintfArgumentVariables + std::string stage = doProgress ? std::string("ValueFlow::") + pass->name() + (' ' + passnum_s) : ""; + ProgressReporter progressReporter(state.errorLogger, state.settings.reportProgress, state.tokenlist.getSourceFilePath(), std::move(stage)); + return run(pass, passnum); })) return true; --n; @@ -7222,7 +7259,7 @@ struct ValueFlowPassRunner { return false; } - bool run(const ValuePtr& pass) const + bool run(const ValuePtr& pass, std::size_t it) const { auto start = Clock::now(); if (start > stop) { @@ -7232,7 +7269,12 @@ struct ValueFlowPassRunner { if (!state.tokenlist.isCPP() && pass->cpp()) return false; if (timerResults) { - Timer t(pass->name(), state.settings.showtime, timerResults); + std::string name = pass->name(); + if (it > 0) { + name += ' '; + name += std::to_string(it); + } + Timer t(name, timerResults); pass->run(state); } else { pass->run(state); @@ -7345,6 +7387,8 @@ void ValueFlow::setValues(TokenList& tokenlist, const Settings& settings, TimerResultsIntf* timerResults) { + ProgressReporter progressReporter(errorLogger, settings.reportProgress, tokenlist.getSourceFilePath(), "ValueFlow"); + for (Token* tok = tokenlist.front(); tok; tok = tok->next()) tok->clearValueFlow(); @@ -7362,7 +7406,7 @@ void ValueFlow::setValues(TokenList& tokenlist, ValueFlowPassRunner runner{ValueFlowState{tokenlist, symboldatabase, errorLogger, settings}, timerResults}; runner.run_once({ - VFA(valueFlowEnumValue(symboldatabase, settings)), + VFA(valueFlowEnumValueEarly(symboldatabase, settings)), VFA(valueFlowNumber(tokenlist, settings)), VFA(valueFlowString(tokenlist, settings)), VFA(valueFlowTypeTraits(tokenlist, settings)), diff --git a/lib/valueflow.h b/lib/valueflow.h index a813ff8d286..f701f55c418 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/lib/valueptr.h b/lib/valueptr.h index 5e0bea0196b..270b5f58fc6 100644 --- a/lib/valueptr.h +++ b/lib/valueptr.h @@ -53,12 +53,12 @@ class CPPCHECKLIB ValuePtr { mPtr.reset(mClone(rhs.get())); } } - ValuePtr(ValuePtr&& rhs) NOEXCEPT : mPtr(std::move(rhs.mPtr)), mClone(std::move(rhs.mClone)) {} + ValuePtr(ValuePtr&& rhs) noexcept : mPtr(std::move(rhs.mPtr)), mClone(std::move(rhs.mClone)) {} - T* get() NOEXCEPT { + T* get() noexcept { return mPtr.get(); } - const T* get() const NOEXCEPT { + const T* get() const noexcept { return mPtr.get(); } @@ -69,14 +69,14 @@ class CPPCHECKLIB ValuePtr { return *get(); } - T* operator->() NOEXCEPT { + T* operator->() noexcept { return get(); } - const T* operator->() const NOEXCEPT { + const T* operator->() const noexcept { return get(); } - void swap(ValuePtr& rhs) NOEXCEPT { + void swap(ValuePtr& rhs) noexcept { using std::swap; swap(mPtr, rhs.mPtr); swap(mClone, rhs.mClone); @@ -88,7 +88,7 @@ class CPPCHECKLIB ValuePtr { } // NOLINTNEXTLINE(google-explicit-constructor) - operator bool() const NOEXCEPT { + operator bool() const noexcept { return !!mPtr; } diff --git a/lib/version.h b/lib/version.h index 3a7c5918b45..2a64885ffa8 100644 --- a/lib/version.h +++ b/lib/version.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +20,9 @@ #ifndef versionH #define versionH -#define CPPCHECK_VERSION_STRING "2.19 dev" -#define CPPCHECK_VERSION 2,18,99,0 +#define CPPCHECK_VERSION_STRING "2.21 dev" +#define CPPCHECK_VERSION 2,20,99,0 -#define LEGALCOPYRIGHT L"Copyright (C) 2007-2025 Cppcheck team." +#define LEGALCOPYRIGHT L"Copyright (C) 2007-2026 Cppcheck team." #endif diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index e14af7a9c98..a50a3b1d4a4 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -139,7 +139,7 @@ struct ValueFlowAnalyzer : Analyzer { return result; } ConditionState lhs = analyzeCondition(tok->astOperand1(), depth - 1); - if (lhs.isUnknownDependent()) + if (lhs.isUnknownDependent() || !tok->astOperand2()) return lhs; ConditionState rhs = analyzeCondition(tok->astOperand2(), depth - 1); if (rhs.isUnknownDependent()) @@ -673,12 +673,12 @@ struct ValueFlowAnalyzer : Analyzer { } template - std::vector evaluateInt(const Token* tok, F getProgramMemory) const + std::vector evaluateInt(const Token* tok, F getProgramMemoryFunc) const { if (const ValueFlow::Value* v = tok->getKnownValue(ValueFlow::Value::ValueType::INT)) - return {static_cast(v->intvalue)}; + return {v->intvalue}; std::vector result; - ProgramMemory pm = getProgramMemory(); + ProgramMemory pm = getProgramMemoryFunc(); if (Token::Match(tok, "&&|%oror%")) { if (conditionIsTrue(tok, pm, getSettings())) result.push_back(1); @@ -717,7 +717,7 @@ struct ValueFlowAnalyzer : Analyzer { ProgramMemory pm = pms.get(tok, ctx, getProgramState()); MathLib::bigint out = 0; if (pm.getContainerEmptyValue(tok->exprId(), out)) - return {static_cast(out)}; + return {out}; return {}; } return {}; @@ -1202,7 +1202,7 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer { return false; if (value.isImpossible()) return false; - if (isConditional() && !value.isKnown() && !value.isImpossible()) + if (isConditional() && !value.isKnown()) return true; if (value.isSymbolicValue()) return false; @@ -1547,7 +1547,7 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer { case Library::Container::Action::APPEND: { std::vector args = getArguments(tok->astParent()->tokAt(2)); if (args.size() == 1) // TODO: handle overloads - n = ValueFlow::valueFlowGetStrLength(tok->astParent()->tokAt(3)); + n = ValueFlow::valueFlowGetStrLength(tok->astParent()->tokAt(3), settings); if (n == 0) // TODO: handle known empty append val->setPossible(); break; diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 333f850d07d..261972cba63 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -101,7 +101,7 @@ namespace ValueFlow return value; const MathLib::biguint unsignedMaxValue = std::numeric_limits::max() >> ((sizeof(unsignedMaxValue) - value_size) * 8); - const MathLib::biguint signBit = 1ULL << (value_size * 8 - 1); + const MathLib::biguint signBit = 1ULL << ((value_size * 8) - 1); value &= unsignedMaxValue; if (dst_sign == ValueType::Sign::SIGNED && (value & signBit)) value |= ~unsignedMaxValue; @@ -154,6 +154,11 @@ namespace ValueFlow if (!tok->isTemplateArg()) value.setKnown(); setTokenValue(tok, std::move(value), settings); + } else if ((tok->isCpp() || settings.standards.c >= Standards::C23) && (tok->isName() && tok->varId() == 0 && Token::Match(tok, "%bool%"))) { + Value value(tok->str() == "true"); + if (!tok->isTemplateArg()) + value.setKnown(); + setTokenValue(tok, std::move(value), settings); } else if (Token::simpleMatch(tok, "sizeof (")) { if (tok->next()->astOperand2() && !tok->next()->astOperand2()->isLiteral() && tok->next()->astOperand2()->valueType() && (tok->next()->astOperand2()->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions @@ -230,9 +235,7 @@ namespace ValueFlow setTokenValue(tok->tokAt(4), std::move(value), settings); } } else if (Token::Match(tok2, "%var% )")) { - const Variable *var = tok2->variable(); - // only look for single token types (no pointers or references yet) - if (var && var->typeStartToken() == var->typeEndToken()) { + if (const Variable *var = tok2->variable()) { // find the size of the type size_t size = 0; if (var->isEnumType()) { @@ -323,7 +326,7 @@ namespace ValueFlow if (!tok->isTemplateArg()) value.setKnown(); setTokenValue(tok->next(), std::move(value), settings); - } else if (Token::simpleMatch(tok, "= { } ;")) { + } else if (Token::simpleMatch(tok, "= { }")) { const Token* lhs = tok->astOperand1(); if (lhs && lhs->valueType() && (lhs->valueType()->isIntegral() || lhs->valueType()->pointer > 0)) { Value value(0); @@ -386,7 +389,7 @@ namespace ValueFlow v.debugPath.emplace_back(tok, std::move(s)); } - MathLib::bigint valueFlowGetStrLength(const Token* tok) + MathLib::bigint valueFlowGetStrLength(const Token* tok, const Settings& settings) { if (tok->tokType() == Token::eString) return Token::getStrLength(tok); @@ -396,8 +399,10 @@ namespace ValueFlow return v->intvalue; if (const Value* v = tok->getKnownValue(Value::ValueType::TOK)) { if (v->tokvalue != tok) - return valueFlowGetStrLength(v->tokvalue); + return valueFlowGetStrLength(v->tokvalue, settings); } + if (const Token* cont = settings.library.getContainerFromYield(tok, Library::Container::Yield::BUFFER_NT)) + return valueFlowGetStrLength(cont, settings); return 0; } } diff --git a/lib/vf_common.h b/lib/vf_common.h index 3ed36e6c47f..64e394b2979 100644 --- a/lib/vf_common.h +++ b/lib/vf_common.h @@ -53,7 +53,7 @@ namespace ValueFlow const Token* tok, SourceLocation local = SourceLocation::current()); - MathLib::bigint valueFlowGetStrLength(const Token* tok); + MathLib::bigint valueFlowGetStrLength(const Token* tok, const Settings& settings); } #endif // vfCommonH diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index 4d39d35daae..c5fe519b720 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ namespace ValueFlow { - static Library::Container::Yield getContainerYield(Token* tok, const Settings& settings, Token*& parent) + static Library::Container::Yield getContainerYield(Token* tok, const Library& library, Token*& parent) { if (Token::Match(tok, ". %name% (") && tok->astParent() == tok->tokAt(2) && tok->astOperand1() && tok->astOperand1()->valueType()) { @@ -57,7 +57,7 @@ namespace ValueFlow } if (Token::Match(tok->previous(), "%name% (")) { parent = tok; - if (const Library::Function* f = settings.library.getFunction(tok->previous())) { + if (const Library::Function* f = library.getFunction(tok->previous())) { return f->containerYield; } } @@ -72,7 +72,7 @@ namespace ValueFlow return value; if (!parent->isBinaryOp()) return value; - if (!parent->isConstOp()) + if (!parent->isConstOp() && !parent->isAssignmentOp()) return value; if (!astIsIntegral(parent->astOperand1(), false)) return value; @@ -88,14 +88,14 @@ namespace ValueFlow ValueType::Sign sign = ValueType::Sign::UNSIGNED; if (n1 < n2) sign = vt2->sign; - else if (n1 > n2) + else // (n1 >= n2) sign = vt1->sign; Value v = castValue(value, sign, std::max(n1, n2) * 8); v.wideintvalue = value.intvalue; return v; } - static const Token *getCastTypeStartToken(const Token *parent, const Settings& settings) + static const Token *getCastTypeStartToken(const Token *parent, const Library& library) { // TODO: This might be a generic utility function? if (!Token::Match(parent, "{|(")) @@ -114,7 +114,7 @@ namespace ValueFlow ftok = ftok->next(); while (Token::Match(ftok, "%name% ::")) ftok = ftok->tokAt(2); - if (settings.library.isNotLibraryFunction(ftok)) + if (library.isNotLibraryFunction(ftok)) return parent->next(); } if (parent->astOperand2() && Token::Match(parent->astOperand1(), "const_cast|dynamic_cast|reinterpret_cast|static_cast <")) @@ -126,32 +126,31 @@ namespace ValueFlow return value.isIntValue() || value.isFloatValue(); } - static void setTokenValueCast(Token *parent, const ValueType &valueType, const Value &value, const Settings &settings) + static void setTokenValueCast(Token *parent, const ValueType &valueType, Value value, const Settings &settings) { if (valueType.pointer || value.isImpossible()) - setTokenValue(parent,value,settings); + setTokenValue(parent,std::move(value),settings); else if (valueType.type == ValueType::Type::CHAR) - setTokenValue(parent, castValue(value, valueType.sign, settings.platform.char_bit), settings); + setTokenValue(parent, castValue(std::move(value), valueType.sign, settings.platform.char_bit), settings); else if (valueType.type == ValueType::Type::SHORT) - setTokenValue(parent, castValue(value, valueType.sign, settings.platform.short_bit), settings); + setTokenValue(parent, castValue(std::move(value), valueType.sign, settings.platform.short_bit), settings); else if (valueType.type == ValueType::Type::INT) - setTokenValue(parent, castValue(value, valueType.sign, settings.platform.int_bit), settings); + setTokenValue(parent, castValue(std::move(value), valueType.sign, settings.platform.int_bit), settings); else if (valueType.type == ValueType::Type::LONG) - setTokenValue(parent, castValue(value, valueType.sign, settings.platform.long_bit), settings); + setTokenValue(parent, castValue(std::move(value), valueType.sign, settings.platform.long_bit), settings); else if (valueType.type == ValueType::Type::LONGLONG) - setTokenValue(parent, castValue(value, valueType.sign, settings.platform.long_long_bit), settings); + setTokenValue(parent, castValue(std::move(value), valueType.sign, settings.platform.long_long_bit), settings); else if (valueType.isFloat() && isNumeric(value)) { - Value floatValue = value; - floatValue.valueType = Value::ValueType::FLOAT; if (value.isIntValue()) - floatValue.floatValue = static_cast(value.intvalue); - setTokenValue(parent, std::move(floatValue), settings); + value.floatValue = static_cast(value.intvalue); + value.valueType = Value::ValueType::FLOAT; + setTokenValue(parent, std::move(value), settings); } else if (value.isIntValue()) { const long long charMax = settings.platform.signedCharMax(); const long long charMin = settings.platform.signedCharMin(); if (charMin <= value.intvalue && value.intvalue <= charMax) { // unknown type, but value is small so there should be no truncation etc - setTokenValue(parent,value,settings); + setTokenValue(parent,std::move(value),settings); } } } @@ -302,27 +301,28 @@ namespace ValueFlow } } Token* next = nullptr; - const Library::Container::Yield yields = getContainerYield(parent, settings, next); + const Library::Container::Yield yields = getContainerYield(parent, settings.library, next); if (yields == Library::Container::Yield::SIZE) { value.valueType = Value::ValueType::INT; setTokenValue(next, std::move(value), settings); } else if (yields == Library::Container::Yield::EMPTY) { - Value v(value); - v.valueType = Value::ValueType::INT; - v.bound = Value::Bound::Point; + const Value::Bound bound = value.bound; + const long long intvalue = value.intvalue; + value.valueType = Value::ValueType::INT; + value.bound = Value::Bound::Point; if (value.isImpossible()) { - if (value.intvalue == 0) - v.setKnown(); - else if ((value.bound == Value::Bound::Upper && value.intvalue > 0) || - (value.bound == Value::Bound::Lower && value.intvalue < 0)) { - v.intvalue = 0; - v.setKnown(); + if (intvalue == 0) + value.setKnown(); + else if ((bound == Value::Bound::Upper && intvalue > 0) || + (bound == Value::Bound::Lower && intvalue < 0)) { + value.intvalue = 0; + value.setKnown(); } else - v.setPossible(); + value.setPossible(); } else { - v.intvalue = !v.intvalue; + value.intvalue = !value.intvalue; } - setTokenValue(next, std::move(v), settings); + setTokenValue(next, std::move(value), settings); } return; } @@ -346,33 +346,32 @@ namespace ValueFlow setTokenValue(parent, std::move(value), settings); return; } - Value pvalue = value; if (!value.subexpressions.empty() && Token::Match(parent, ". %var%")) { if (contains(value.subexpressions, parent->strAt(1))) - pvalue.subexpressions.clear(); + value.subexpressions.clear(); else return; } if (parent->isUnaryOp("&")) { - pvalue.indirect++; - setTokenValue(parent, std::move(pvalue), settings); + value.indirect++; + setTokenValue(parent, std::move(value), settings); } else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok && parent->astOperand2()) { - if (parent->originalName() == "->" && pvalue.indirect > 0) - pvalue.indirect--; - setTokenValue(parent->astOperand2(), std::move(pvalue), settings); + if (parent->originalName() == "->" && value.indirect > 0) + value.indirect--; + setTokenValue(parent->astOperand2(), std::move(value), settings); } else if (Token::Match(parent->astParent(), ". %var%") && parent->astParent()->astOperand1() == parent) { - if (parent->astParent()->originalName() == "->" && pvalue.indirect > 0) - pvalue.indirect--; - setTokenValue(parent->astParent()->astOperand2(), std::move(pvalue), settings); - } else if (parent->isUnaryOp("*") && pvalue.indirect > 0) { - pvalue.indirect--; - setTokenValue(parent, std::move(pvalue), settings); + if (parent->astParent()->originalName() == "->" && value.indirect > 0) + value.indirect--; + setTokenValue(parent->astParent()->astOperand2(), std::move(value), settings); + } else if (parent->isUnaryOp("*") && value.indirect > 0) { + value.indirect--; + setTokenValue(parent, std::move(value), settings); } return; } // cast.. - if (const Token *castType = getCastTypeStartToken(parent, settings)) { + if (const Token *castType = getCastTypeStartToken(parent, settings.library)) { if (contains({Value::ValueType::INT, Value::ValueType::SYMBOLIC}, value.valueType) && Token::simpleMatch(parent->astOperand1(), "dynamic_cast")) return; @@ -382,7 +381,7 @@ namespace ValueFlow && tok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) >= valueType.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer)) return; - setTokenValueCast(parent, valueType, value, settings); + setTokenValueCast(parent, valueType, std::move(value), settings); } else if (parent->str() == ":") { @@ -421,11 +420,10 @@ namespace ValueFlow if (ret) return; - Value v(std::move(value)); - v.conditional = true; - v.changeKnownToPossible(); + value.conditional = true; + value.changeKnownToPossible(); - setTokenValue(parent, std::move(v), settings); + setTokenValue(parent, std::move(value), settings); } } @@ -713,15 +711,13 @@ namespace ValueFlow std::vector args = getArguments(value.tokvalue); if (const Library::Function* f = settings.library.getFunction(parent->previous())) { if (f->containerYield == Library::Container::Yield::SIZE) { - Value v(std::move(value)); - v.valueType = Value::ValueType::INT; - v.intvalue = args.size(); - setTokenValue(parent, std::move(v), settings); + value.valueType = Value::ValueType::INT; + value.intvalue = args.size(); + setTokenValue(parent, std::move(value), settings); } else if (f->containerYield == Library::Container::Yield::EMPTY) { - Value v(std::move(value)); - v.intvalue = args.empty(); - v.valueType = Value::ValueType::INT; - setTokenValue(parent, std::move(v), settings); + value.intvalue = args.empty(); + value.valueType = Value::ValueType::INT; + setTokenValue(parent, std::move(value), settings); } } } diff --git a/lib/vfvalue.cpp b/lib/vfvalue.cpp index 4ec1c742ab3..308b42b91d1 100644 --- a/lib/vfvalue.cpp +++ b/lib/vfvalue.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/lsan-suppr.txt b/lsan-suppr.txt deleted file mode 100644 index bf8389f247e..00000000000 --- a/lsan-suppr.txt +++ /dev/null @@ -1 +0,0 @@ -leak:libpcre.so \ No newline at end of file diff --git a/man/checkers/cstyleCast.md b/man/checkers/cstyleCast.md index 52da49adad2..f05a192ced8 100644 --- a/man/checkers/cstyleCast.md +++ b/man/checkers/cstyleCast.md @@ -31,7 +31,7 @@ The motivation of this checker is to modernize c++ code. You can use C++ casts such as `static_cast` to fix these warnings. -The `dynamic_cast` should rarelly be used to fix these warnings because dangerousTypeCast is +The `dynamic_cast` should rarely be used to fix these warnings because dangerousTypeCast is reported when that can be a good idea. Before: diff --git a/man/checkers/fcloseInLoopCondition.md b/man/checkers/fcloseInLoopCondition.md new file mode 100644 index 00000000000..db7f0a584c6 --- /dev/null +++ b/man/checkers/fcloseInLoopCondition.md @@ -0,0 +1,40 @@ +# fcloseInLoopCondition + +**Message**: fclose() used as loop condition may skip loop body or double-close file handle.
+**Category**: Resource Management
+**Severity**: Warning
+**Language**: C and C++ + +## Description + +Using `fclose()` as a loop condition leads to two unwanted outcomes: + +- On **success**, the condition is false and the loop body never executes. The intent was likely to process the file inside the loop, but it is already closed. +- On **failure**, the condition is true and the loop body executes but `fclose()` is called again on the already-closed file handle on the next iteration, which is undefined behaviour. + +This pattern is almost always a misunderstanding of what `fclose()` returns, or confusion with a function that reads/processes data incrementally (like `fgets` or `fread`). Unlike those functions, `fclose()` is a one-shot teardown operation and has no meaningful retry or loop-until-done semantic. + +## How to fix + +Call `fclose()` outside the loop condition. If you need to check whether the close succeeded, store the return value and test it separately. + +Before: +```c +FILE *fp = fopen("data.txt", "r"); +while (fclose(fp)) { + /* process file */ +} +``` + +After: +```c +FILE *fp = fopen("data.txt", "r"); +/* process file */ +if (fclose(fp) != 0) { + /* handle close error */ +} +``` + +## Related checkers + +- `useClosedFile` - for using a file handle that has already been closed diff --git a/man/checkers/truncLongCast.md b/man/checkers/truncLongCast.md index 7157a5b6627..f6ecd6ea77c 100644 --- a/man/checkers/truncLongCast.md +++ b/man/checkers/truncLongCast.md @@ -8,7 +8,7 @@ ## Description This checker warns when a calculation has type 'int' and it could potentially overflow that and the result is implicitly or explicitly converted to a larger -integer type after the loss of information has already occured. +integer type after the loss of information has already occurred. ## Motivation diff --git a/man/checkers/unknownMacro.md b/man/checkers/unknownMacro.md new file mode 100644 index 00000000000..52599215d89 --- /dev/null +++ b/man/checkers/unknownMacro.md @@ -0,0 +1,68 @@ + +# unknownMacro + +**Message**: There is an unknown macro here somewhere. Configuration is required. If AAA is a macro then please configure it. [unknownMacro] +
+**Category**: Configuration
+**Severity**: Error
+**Language**: C and C++ + +## Description + +Cppcheck has found code that is confusing and does not know how to analyze it. This is a critical +error, the analysis of the whole translation unit is aborted. Such error in a header file can mean +that analysis of many source files are aborted. + +Your code is probably OK but you need to configure Cppcheck to make Cppcheck understand the code +better. + +## How to fix + +Review the configuration. + +If Cppcheck warns about a macro that is defined in a 3rd party library, and there is a cfg file for +that, then a `--library=` option may be a proper solution. + +If Cppcheck warns about a macro that is defined in a header that should be included, make sure that +this header is included properly. Cppcheck must have the include path. + +If Cppcheck warns about a compiler keyword add a `-D` that defines this keyword somehow. I.e. if +cppcheck should just ignore the keyword then an `-DKEYWORD=` option is suggested. + +## Example + +### Example code 1 +``` + fprintf(stderr, "Generating up to " F_U64 " sequences and up to " F_U64 " bases.\n", nSeqs, nBases); +``` + +Warning: + +canu-2.2/src/seqrequester/src/seqrequester/generate.H:72:41: error: There is an unknown macro here somewhere. Configuration is required. If F_U64 is a macro then please configure it. [unknownMacro] + +Fix: + +Somehow `F_U64` must be specified for Cppcheck to be able to analyse this properly. Either: + * Add `-DF_U64="x"` to explicitly tell Cppcheck what it should replace F_U64 with. Or; + * Add `-I..` so that headers are included properly. + * If the symbol is defined in a 3rd party library adding a corresponding `--library=` might solve such issue. + +### Example code 2 +``` +BOTAN_FUNC_ISA("crypto") +void AES_128::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const +``` + +Warning: + +botan-2.19.5+dfsg/src/lib/block/aes/aes_power8/aes_power8.cpp:103:1: error: There is an unknown macro here somewhere. Configuration is required. If BOTAN_FUNC_ISA is a macro then please configure it. [unknownMacro] + +Fix: + +Somehow `BOTAN_FUNC_ISA` must be specified for Cppcheck to be able to analyse this properly. Either: + * Add `-DBOTAN_FUNC_ISA(X)=` to explicitly tell Cppcheck that BOTAN_FUNC_ISA("crypto") should be ignored. Or; + * Add `-I..` so that headers are included properly. + * If the symbol is defined in a 3rd party library adding a corresponding `--library=` might solve such issue. + + + diff --git a/man/cppcheck.1.xml b/man/cppcheck.1.xml index db3a5a9baa6..8579d375bdf 100644 --- a/man/cppcheck.1.xml +++ b/man/cppcheck.1.xml @@ -117,6 +117,9 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ + + + @@ -343,6 +346,14 @@ Example: '-UDEBUG' Print a list of all possible error messages in XML format. + + + + + + Used to specify an error ID which should not result in a non-zero exitcode. + + diff --git a/man/manual-ja.docbook b/man/manual-ja.docbook index 1c13d3d0526..0b2a39cc59e 100644 --- a/man/manual-ja.docbook +++ b/man/manual-ja.docbook @@ -1702,11 +1702,11 @@ Checking unusedvar.cpp... - Cppcheck プロジェクトはいくつかのアドオンを以下の場所で提供しています。: http://github.com/danmar/cppcheck/blob/master/addons + Cppcheck プロジェクトはいくつかのアドオンを以下の場所で提供しています。: http://github.com/cppcheck-opensource/cppcheck/blob/master/addons - ublinterは規格で定義されていない未定義動作に注力した"lint"です。: http://github.com/danmar/ublinter + ublinterは規格で定義されていない未定義動作に注力した"lint"です。: http://github.com/cppcheck-opensource/ublinter diff --git a/man/manual-premium.md b/man/manual-premium.md index 9f2e5992537..4c30dc6d4b3 100644 --- a/man/manual-premium.md +++ b/man/manual-premium.md @@ -7,8 +7,8 @@ documentclass: report # Introduction -Cppcheck is an analysis tool for C/C++ code. It provides unique code analysis to detect bugs and focuses on detecting -undefined behaviour and dangerous coding constructs. The goal is to detect only real errors in the code, and generate +Cppcheck is an analysis tool for C/C++ code. It provides unique code analysis to detect bugs and focuses on detecting +undefined behaviour and dangerous coding constructs. The goal is to detect only real errors in the code, and generate as few false positives (wrongly reported warnings) as possible. Cppcheck is designed to analyze your C/C++ code even if it has non-standard syntax, as is common in for example embedded projects. @@ -16,7 +16,7 @@ Supported code and platforms: - Cppcheck checks non-standard code that contains various compiler extensions, inline assembly code, etc. - Cppcheck should be compilable by any compiler that supports C++11 or later. -- Cppcheck is cross platform and is used in various posix/windows/etc environments. +- Cppcheck is cross-platform and is used in various posix/windows/etc environments. The checks in Cppcheck are not perfect. There are bugs that should be found, that Cppcheck fails to detect. @@ -29,11 +29,11 @@ The kinds of bugs that you can find with static analysis are: - Coding style There are many bugs that you can not find with static analysis. Static analysis tools do not have human knowledge about -what your program is intended to do. If the output from your program is valid but unexpected then in most cases this is -not detected by static analysis tools. For instance, if your small program writes "Helo" on the screen instead of "Hello" +what your program is intended to do. If the output from your program is valid but unexpected, then in most cases this is +not detected by static analysis tools. For instance, if your small program writes "Helo" on the screen instead of "Hello", it is unlikely that any tool will complain about that. -Static analysis should be used as a complement in your quality assurance. It does not replace any of; +Static analysis should be used as a complement in your quality assurance. It does not replace any of: - Careful design - Testing @@ -69,7 +69,7 @@ Here is some simple code: return 0; } -If you save that into file1.c and execute: +If you save that into `file1.c` and execute: cppcheck file1.c @@ -84,7 +84,7 @@ Normally a program has many source files. Cppcheck can check all source files in cppcheck path -If "path" is a folder, then Cppcheck will recursively check all source files in this folder: +If `path` is a folder, then Cppcheck will recursively check all source files in this folder: Checking path/file1.cpp... 1/2 files checked 50% done @@ -93,21 +93,22 @@ If "path" is a folder, then Cppcheck will recursively check all source files in ### Check files manually or use project file -With Cppcheck you can check files manually by specifying files/paths to check and settings. Or you can use a build +With Cppcheck you can check files manually by specifying files/paths to check and settings. Or you can use a build environment, such as CMake or Visual Studio. -We don't know which approach (project file or manual configuration) will give you the best results. It is recommended -that you try both. It is possible that you will get different results so that to find the largest amount of bugs you +We don't know which approach (project file or manual configuration) will give you the best results. It is recommended +that you try both. It is possible that you will get different results so that to find the largest amount of bugs you need to use both approaches. Later chapters will describe this in more detail. ### Check files matching a given file filter With `--file-filter=` you can configure file filter(s) and then only those files matching the filter will be checked. -You can use `**`, `*` and `?` in the file filter pattern. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators +You can use `**`, `*` and `?` in the file filter pattern. + +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. For example, this command below means that `src/test1.cpp` could be checked, but `src/file2.cpp` and `src/test/file1.cpp` will not be checked: @@ -121,30 +122,33 @@ A common use case for `--file-filter` is to check a project, but only check cert cppcheck --project=compile_commands.json --file-filter=src/*.c Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `--file-filter=src/*.c` would mean that: - * a file with relative path `test1.c` is not checked. - * a file with relative path `src/test2.c` can be checked. - * a file with relative path `src/test3.cpp` is not checked. + +- a file with relative path `test1.c` is not checked. +- a file with relative path `src/test2.c` can be checked. +- a file with relative path `src/test3.cpp` is not checked. ### Ignore files matching a given pattern With `-i ` you can configure filename/directory patterns that should be ignored. -A file that is ignored will not be checked directly (the complete translation unit is skipped). Any header #include'd from a source file which is not ignored is checked indirectly, regardless if the header is ignored. +A file that is ignored will not be checked directly (the complete translation unit is skipped). Any header `#include`'d from a source file which is not ignored is checked indirectly, regardless if the header is ignored. + +> *Note*: If you want to filter out warnings for a header file, then `-i` will not work. Use suppressions instead. -> *Note*: If you want to filter out warnings for a header file then `-i` will not work. Use suppressions instead. +You can use `**`, `*` and `?` in the pattern to specify excluded folders/files. -You can use `**`, `*` and `?` in the pattern to specify excluded folders/files. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. A use case for `-i` is to check a project, but exclude certain files/folders: cppcheck --project=compile_commands.json -itest Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `-itest` would mean that: - * a file with relative path `test1.cpp` can be checked. - * a file with relative path `test/somefile.cpp` is not checked + +- a file with relative path `test1.cpp` can be checked. +- a file with relative path `test/somefile.cpp` is not checked ### Clang parser (experimental) @@ -155,7 +159,7 @@ Install `clang`. Then use Cppcheck option `--clang`. Cppcheck executes clang with the -ast-dump option, imports the output, converts it to Cppcheck's internal format, and then performs standard analysis. -You can also pass a custom Clang executable to the option by using for example `--clang=clang-10`. You can also pass it +You can also pass a custom Clang executable to the option by using for example `--clang=clang-10`. You can also pass it with a path. On Windows it will append the `.exe` extension unless you use a path. ## Severities @@ -176,17 +180,17 @@ stylistic issues, such as unused functions, redundant code, constness, operator **performance** -run time performance suggestions based on common knowledge, though it is not certain any measurable speed difference +run time performance suggestions based on common knowledge, though it is not certain any measurable speed difference will be achieved by fixing these messages. **portability** -portability warnings. Implementation defined behavior. 64-bit portability. Some undefined behavior that probably works +portability warnings. Implementation defined behavior. 64-bit portability. Some undefined behavior that probably works "as you want", etc. **information** -configuration problems, which does not relate to the syntactical correctness, but the used Cppcheck configuration could +configuration problems, which does not relate to the syntactical correctness, but the used Cppcheck configuration could be improved. ## Possible speedup analysis of template code @@ -220,7 +224,7 @@ Cppcheck output: As you can see Cppcheck has instantiated `a` until `a<101>` was reached and then it bails out. -To limit template recursion you can: +To limit template recursion, you can: - add template specialisation - configure Cppcheck, which can be done in the GUI project file dialog @@ -244,7 +248,6 @@ Example code with template specialisation: You can pass `-D__cppcheck__` when checking this code. - # Cppcheck build folder Using a Cppcheck build folder is not mandatory but it is recommended. @@ -278,36 +281,44 @@ You can import and use Cppcheck GUI project files in the command line tool: cppcheck --project=foobar.cppcheck -The Cppcheck GUI has a few options that are not available in the command line directly. To use these options you can import a GUI project file. +The Cppcheck GUI has a few options that are not available in the command line directly. To use these options, you can import a GUI project file. The command line tool usage is kept intentionally simple and the options are therefore limited. -To ignore certain folders in the project you can use `-i`. This will skip the analysis of source files in the `foo` folder. +To ignore certain folders in the project, you can use `-i`. This will skip the analysis of source files in the `foo` folder. cppcheck --project=foobar.cppcheck -ifoo -## CMake +## Compilation database (CMake etc.) -Generate a compile database (a JSON file containing compilation commands for each source file): +Many build systems can generate a compilation database (a JSON file containing compilation commands for each source file). +Example `cmake` command to generate the file: cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON . -The file `compile_commands.json` is created in the current folder. Now run Cppcheck like this: +When you have a `compile_commands.json` file, you can run Cppcheck like this: cppcheck --project=compile_commands.json +By default only 1 configuration is checked because that is consistent with the compilation. If you want to check more configurations, you can use `--max-configs` or `--force`. For example: + + cppcheck --project=compile_commands.json --force + To ignore certain folders you can use `-i`. This will skip analysis of source files in the `foo` folder. cppcheck --project=compile_commands.json -ifoo - ## Visual Studio -You can run Cppcheck on individual project files (\*.vcxproj) or on a whole solution (\*.sln) +You can run Cppcheck on individual project files (`*.vcxproj`) or on a whole solution (`*.sln`) or (`*.slnx`). Running Cppcheck on an entire Visual Studio solution: cppcheck --project=foobar.sln +Running Cppcheck on an entire Visual Studio 2026 solution: + + cppcheck --project=foobar.slnx + Running Cppcheck on a Visual Studio project: cppcheck --project=foobar.vcxproj @@ -319,7 +330,7 @@ Limiting on a single configuration: In the `Cppcheck GUI` you have the option to only analyze a single debug configuration. If you want to use this option on the command line, then create a `Cppcheck GUI` project with this activated and then import the GUI project file on the command line. -To ignore certain folders in the project you can use `-i`. This will skip analysis of source files in the `foo` folder. +To ignore certain folders in the project, you can use `-i`. This will skip analysis of source files in the `foo` folder. cppcheck --project=foobar.vcxproj -ifoo @@ -329,25 +340,28 @@ Running Cppcheck on a C++ Builder 6 project: cppcheck --project=foobar.bpr - -To ignore certain folders in the project you can use `-i`. This will skip analysis of source files in the `foo` folder. +To ignore certain folders in the project, you can use `-i`. This will skip analysis of source files in the `foo` folder. cppcheck --project=foobar.bpr -ifoo ## Other -If you can generate a compile database, then it is possible to import that in Cppcheck. +If you generate a compilation database, then it is possible to import that in Cppcheck. -In Linux you can use for instance the `bear` (build ear) utility to generate a compile database from arbitrary build tools: +### Makefile + +In Linux you can convert a Makefile to a `compile_commands.json` using for instance `bear` (build ear) utility: bear -- make -# Preprocessor Settings +If you don't use Linux, there are Python scripts that converts a Makefile into a compilation database. + +# Preprocessor settings -If you use `--project` then Cppcheck will automatically use the preprocessor settings in the imported project file and +If you use `--project`, then Cppcheck will automatically use the preprocessor settings in the imported project file and likely you don't have to configure anything extra. -If you don't use `--project` then a bit of manual preprocessor configuration might be required. However Cppcheck has +If you don't use `--project`, then a bit of manual preprocessor configuration might be required. However Cppcheck has automatic configuration of defines. ## Automatic configuration of preprocessor defines @@ -355,7 +369,7 @@ automatic configuration of defines. Cppcheck automatically test different combinations of preprocessor defines to achieve as high coverage in the analysis as possible. -Here is a file that has 3 bugs (when x,y,z are assigned). +Here is a file that has 3 bugs (when `x`, `y`, `z` are assigned). #ifdef A x=100/0; @@ -386,14 +400,14 @@ Example: cppcheck test.c # only test configuration "-DA" - # No bug is found (#error) + # No bug is found; because C is not defined the #error will cause a preprocessor error cppcheck -DA test.c # only test configuration "-DA -DC" # The first bug is found cppcheck -DA -DC test.c - # The configuration "-DC" is tested + # Test all configurations that does not define "A" # The last bug is found cppcheck -UA test.c @@ -401,20 +415,27 @@ Example: # The two first bugs are found cppcheck --force -DA test.c + # only test 1 valid configuration + # Bug(s) will be found + cppcheck --max-configs=1 test.c + + # test 2 valid configurations with "X" defined. + # Bug(s) will be found + cppcheck --max-configs=2 -DX test.c ## Include paths -To add an include path, use `-I`, followed by the path. +To add an include path, use `-I` followed by the path. -Cppcheck's preprocessor basically handles includes like any other preprocessor. However, while other preprocessors -stop working when they encounter a missing header, Cppcheck will just print an information message and continues +Cppcheck's preprocessor basically handles includes like any other preprocessor. However, while other preprocessors +stop working when they encounter a missing header, Cppcheck will just print an information message and continues parsing the code. -The purpose of this behaviour is that Cppcheck is meant to work without necessarily seeing the entire code. -Actually, it is recommended to not give all include paths. -While it is useful for Cppcheck to see the declaration of a class when checking the implementation of its members, -passing standard library headers is discouraged, because the analysis will not work fully and lead to a longer checking -time. For such cases, .cfg files are the preferred way to provide information about the implementation of functions and +The purpose of this behaviour is that Cppcheck is meant to work without necessarily seeing the entire code. +Actually, it is recommended to not give all include paths. +While it is useful for Cppcheck to see the declaration of a class when checking the implementation of its members, +passing standard library headers is discouraged, because the analysis will not work fully and lead to a longer checking +time. For such cases, `.cfg` files are the preferred way to provide information about the implementation of functions and types to Cppcheck, see below for more information. # Platform @@ -445,7 +466,7 @@ You can also create your own custom platform configuration in a XML file. Here i -# C/C++ Standard +# C/C++ standard Use `--std` on the command line to specify a C/C++ standard. @@ -474,7 +495,7 @@ the GUI, the build dir is configured in the project options. Rechecking code will be much faster. Cppcheck does not analyse unchanged code. The old warnings are loaded from the build dir and reported again. -Whole program analysis does not work when multiple threads are used; unless you use a cppcheck +Whole program analysis does not work when multiple threads are used unless you use a Cppcheck build dir. For instance, the unusedFunction warnings require whole program analysis. # Suppressions @@ -492,12 +513,13 @@ The format for an error suppression is one of: [error id]:[filename2] [error id] -The `error id` is the id that you want to suppress. The id of a warning is shown in brackets in the normal cppcheck text output. +The `error id` is the id that you want to suppress. The id of a warning is shown in brackets in the normal Cppcheck text output. -The `error id` and `filename` patterns may contain `**`, `*` or `?`. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators +The `error id` and `filename` patterns may contain `**`, `*` or `?`. + +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. It is recommended to use forward-slash `/` in the filename pattern as path separator on all operating systems. @@ -539,9 +561,10 @@ You can specify suppressions in a XML file, for example as follows: The `id` and `fileName` patterns may contain `**`, `*` or `?`. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators + +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. The XML format is extensible and may be extended with further attributes in the future. @@ -551,7 +574,7 @@ The usage of the suppressions file is as follows: ## Inline suppressions -Suppressions can also be added directly in the code by adding comments that contain special keywords. +Suppressions can also be added directly in the code by adding comments that contain special keywords. Note that adding comments sacrifices the readability of the code somewhat. This code will normally generate an error message: @@ -576,7 +599,7 @@ You can suppress a warning `aaaa` with: // cppcheck-suppress aaaa -Suppressing multiple ids in one comment by using []: +Suppressing multiple ids in one comment by using `[]`: // cppcheck-suppress [aaaa, bbbb] @@ -607,7 +630,6 @@ Suppressing warnings `aaaa` where macro is used: ... x = MACRO; // <- aaaa warnings are suppressed here - Suppressing multiple ids where macro is used: // cppcheck-suppress-macro [aaaa, bbbb] @@ -636,7 +658,21 @@ Or at the same line as the code: arr[10] = 0; // cppcheck-suppress arrayIndexOutOfBounds } -In this example there are 2 lines with code and 1 suppression comment. The suppression comment only applies to 1 line: `a = b + c;`. +The suppression comment and the line of code may be separated by additional comments or empty lines: + + void f() { + char arr[5]; + + // cppcheck-suppress arrayIndexOutOfBounds + + arr[10] = 0; + + // cppcheck-suppress arrayIndexOutOfBounds + // Set the tenth element of arr to zero + arr[10] = 0; + } + +In the example below there are 2 lines with code and 1 suppression comment. The suppression comment only applies to 1 line: `a = b + c;`. void f() { a = b + c; // cppcheck-suppress abc @@ -683,7 +719,6 @@ Suppression comment on the same line as the code: arr[10] = arr[10] / 0; // cppcheck-suppress[arrayIndexOutOfBounds,zerodiv] } - ### Symbol name You can specify that the inline suppression only applies to a specific symbol: @@ -783,7 +818,7 @@ If you want to reformat the output so that it looks different, then you can use ## Predefined output formats -To get Visual Studio compatible output you can use --template=vs: +To get Visual Studio compatible output, you can use `--template=vs`: cppcheck --template=vs samples/arrayIndexOutOfBounds/bad.c @@ -793,7 +828,7 @@ This output will look like this: samples/arrayIndexOutOfBounds/bad.c(6): error: Array 'a[2]' accessed at index 2, which is out of bounds. -To get gcc compatible output you can use --template=gcc: +To get GCC-compatible output, you can use `--template=gcc`: cppcheck --template=gcc samples/arrayIndexOutOfBounds/bad.c @@ -831,7 +866,7 @@ The output will look like this: samples/arrayIndexOutOfBounds/bad.c,6,error,arrayIndexOutOfBounds, Array 'a[2]' accessed at index 2, which is out of bounds. -## User defined output format (multi line) +## User defined output format (multi-line) Many warnings have multiple locations. Example code: @@ -847,9 +882,9 @@ Many warnings have multiple locations. Example code: return 0; } -There is a possible null pointer dereference at line 3. -Cppcheck can show how it came to that conclusion by showing extra location information. -You need to use both --template and --template-location at the command line, for example: +There is a possible null pointer dereference at line 3. +Cppcheck can show how it came to that conclusion by showing extra location information. +You need to use both `--template` and `--template-location` at the command line, for example: cppcheck \ --template="{file}:{line}: {severity}: {message}\n{code}" \ @@ -871,13 +906,13 @@ The output from Cppcheck is: *p = 3; ^ -The first line in the warning is formatted by the --template format. +The first line in the warning is formatted by the `--template` format. -The other lines in the warning are formatted by the --template-location format. +The other lines in the warning are formatted by the `--template-location` format. -### Format specifiers for --template +### Format specifiers for `--template` -The available specifiers for --template are: +The available specifiers for `--template` are: **{file}** @@ -893,11 +928,11 @@ Column number **{callstack}** -Write all locations. Each location is written in [{file}:{line}] format and the locations are separated by ->. For instance it might look like: [multiline.c:8] -> [multiline.c:9] -> [multiline.c:3] +Write all locations. Each location is written in `[{file}:{line}]` format and the locations are separated by `->`. For instance it might look like: `[multiline.c:8] -> [multiline.c:9] -> [multiline.c:3]` **{inconclusive:text}** -If warning is inconclusive, then the given text is written. The given text can be any text that does not contain }. Example: {inconclusive:inconclusive,} +If warning is inconclusive, then the given text is written. The given text can be any text that does not contain `}`. Example: `{inconclusive:inconclusive,}` **{severity}** @@ -931,7 +966,7 @@ Newline Carriage return -### Format specifiers for --template-location +### Format specifiers for `--template-location` The available specifiers for `--template-location` are: @@ -983,7 +1018,7 @@ Example code: int x = 0; } -In Cppcheck text output the remarks are not shown by default, you can use `--template` option `{remark}` to show remarks: +In Cppcheck text output, the remarks are not shown by default, you can use `--template` option `{remark}` to show remarks: $ ./cppcheck --enable=style \ --template="{file}:{line}: {message} [{id}]\\n{remark}" test1.c @@ -992,12 +1027,12 @@ In Cppcheck text output the remarks are not shown by default, you can use `--tem test1.c:4: Variable 'x' is assigned a value that is never used. [unreadVariable] Initialize x with 0 -In xml output the comment text is provided in a "remark" attribute: +In XML output, the comment text is provided in a `remark` attribute: $ ./cppcheck --enable=style --xml test1.c - .... + ... remark="Initialize x with 0" - .... + ... # Addons @@ -1007,52 +1042,51 @@ Cppcheck is distributed with a few addons which are listed below. ## Supported addons -### namingng.py +### `namingng.py` -[namingng.py](https://github.com/danmar/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. +[`namingng.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. You need to have a configuration file that defines your naming conventions. By default the filename `namingng.config.json` is used but there is an option so you can use any filename you want. Example configuration of naming conventions: -``` -{ - "RE_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"], - "RE_PRIVATE_MEMBER_VARIABLE": null, - "RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"], - "_comment": "comments can be added to the config with underscore-prefixed keys", - "include_guard": { - "input": "path", - "prefix": "GUARD_", - "case": "upper", - "max_linenr": 5, - "RE_HEADERFILE": "[^/].*\\.h\\Z", - "required": true - }, - "var_prefixes": {"uint32_t": "ui32"}, - "function_prefixes": {"uint16_t": "ui16", - "uint32_t": "ui32"} -} -``` - -### threadsafety.py - -[threadsafety.py](https://github.com/danmar/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. - -### y2038.py - -[y2038.py](https://github.com/danmar/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. - -## Running Addons + + { + "RE_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"], + "RE_PRIVATE_MEMBER_VARIABLE": null, + "RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"], + "_comment": "comments can be added to the config with underscore-prefixed keys", + "include_guard": { + "input": "path", + "prefix": "GUARD_", + "case": "upper", + "max_linenr": 5, + "RE_HEADERFILE": "[^/].*\\.h\\Z", + "required": true + }, + "var_prefixes": {"uint32_t": "ui32"}, + "function_prefixes": {"uint16_t": "ui16", + "uint32_t": "ui32"} + } + +### `threadsafety.py` + +[`threadsafety.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. + +### `y2038.py` + +[`y2038.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. + +## Running addons Addons can be executed with the `--addon` option: cppcheck --addon=namingng.py somefile.c -Likewise, if you have created your own script you can execute that: +Likewise, if you have created your own script, you can execute that: cppcheck --addon=mychecks.py somefile.c -You can configure how you want to execute an addon in a json file. For example: +You can configure how you want to execute an addon in a JSON file. For example: { "script": "mychecks.py", @@ -1062,7 +1096,7 @@ You can configure how you want to execute an addon in a json file. For example: "ctu": false } -To use that json file to execute your addon use the --addon option: +To use that JSON file to execute your addon, use the `--addon` option: cppcheck --addon=mychecks.json somefile.c @@ -1072,75 +1106,74 @@ Cppcheck search for addons in the local folder first and then in the installatio # Library configuration -When external libraries are used, such as WinAPI, POSIX, gtk, Qt, etc, Cppcheck has no information about functions, types, or macros contained in those libraries. Cppcheck then fails to detect various problems in the code, or might even abort the analysis. But this can be fixed by using the appropriate configuration files. - -Cppcheck already contains configurations for several libraries. They can be loaded as described below. Note that the configuration for the standard libraries of C and C++, std.cfg, is always loaded by cppcheck. If you create or update a configuration file for a popular library, we would appreciate if you supplied it to the cppcheck project. - -## Using a .cfg file - -To use a .cfg file shipped with cppcheck, pass the `--library=` option. The table below shows the currently existing libraries: - -| .cfg file | Library | Comment | -| ----------------- | ------------- | ------------- | -| avr.cfg | | | -| bento4.cfg | [Bento4](http://www.bento4.com/) | | -| boost.cfg | [Boost](http://www.boost.org/) | | -| bsd.cfg | [BSD](https://www.freebsd.org/) | | -| cairo.cfg | [cairo](https://www.cairographics.org/) | | -| cppcheck-lib.cfg | [Cppcheck](http://cppcheck.net/) | Used in selfcheck of | -| | |the Cppcheck code base | -| cppunit.cfg | [CppUnit](https://sourceforge.net/projects/cppunit/) | | -| dpdk.cfg | | | -| embedded_sql.cfg | | | -| emscripten.cfg | | | -| ginac.cfg | | | -| gnu.cfg | [GNU](https://www.gnu.org/) | | -| googletest.cfg | [GoogleTest](https://github.com/google/googletest) | | -| gtk.cfg | [GTK](https://www.gtk.org/) | | -| icu.cfg | | | -| kde.cfg | [KDE](https://kde.org/) | | -| libcerror.cfg | [libcerror](https://github.com/libyal/libcerror) | | -| libcurl.cfg | [libcurl](https://curl.se/libcurl/) | | -| libsigc++.cfg | [libsigc++](https://github.com/libsigcplusplus/libsigcplusplus) | | -| lua.cfg | | | -| mfc.cfg | [MFC](https://learn.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications) | | -| microsoft_atl.cfg | [ATL](https://learn.microsoft.com/en-us/cpp/atl/active-template-library-atl-concepts) | | -| microsoft_sal.cfg | [SAL annotations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/sal-annotations) | | -| microsoft_unittest.cfg | [CppUnitTest](https://learn.microsoft.com/en-us/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference) | | -| motif.cfg | | | -| nspr.cfg | | | -| ntl.cfg | | | -| opencv2.cfg | [OpenCV](https://opencv.org/) | | -| opengl.cfg | [OpenGL](https://opengl.org/) | | -| openmp.cfg | [OpenMP](https://www.openmp.org/) | | -| openssl.cfg | [OpenSSL](https://www.openssl.org/) | | -| pcre.cfg | [PCRE](https://pcre.org/) | | -| posix.cfg | [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/) | | -| python.cfg | | | -| qt.cfg | [Qt](https://doc.qt.io/qt.html) | | -| ruby.cfg | | | -| sdl.cfg | | | -| sfml.cfg | | | -| sqlite3.cfg | [SQLite](https://www.sqlite.org/) | | -| std.cfg | C/C++ standard library | Loaded by default | -| tinyxml2.cfg | [TinyXML-2](https://github.com/leethomason/tinyxml2) | | -| vcl.cfg | | | -| windows.cfg | [Win32 API](https://learn.microsoft.com/en-us/windows/win32/) | | -| wxsqlite3.cfg | | | -| wxsvg.cfg | | | -| wxwidgets.cfg | [wxWidgets](https://www.wxwidgets.org/) | | -| zephyr.cfg | | | -| zlib.cfg | [zlib](https://www.zlib.net) | | - -## Creating a custom .cfg file - -You can create and use your own .cfg files for your projects. Use `--check-library` to get hints about what you should configure. +When external libraries are used, such as WinAPI, POSIX, gtk, Qt, etc., Cppcheck has no information about functions, types, or macros contained in those libraries. Cppcheck then fails to detect various problems in the code, or might even abort the analysis. But this can be fixed by using the appropriate configuration files. + +Cppcheck already contains configurations for several libraries. They can be loaded as described below. Note that the configuration for the standard libraries of C and C++, `std.cfg`, is always loaded by Cppcheck. If you create or update a configuration file for a popular library, we would appreciate if you supplied it to the Cppcheck project. + +## Using a `.cfg` file + +To use a `.cfg` file shipped with Cppcheck, pass the `--library=` option. The table below shows the currently existing libraries: + +| `.cfg` file | Library | Comment | +| --- | --- | --- | +| `avr.cfg` | | | +| `bento4.cfg` | [Bento4](http://www.bento4.com/) | | +| `boost.cfg` | [Boost](http://www.boost.org/) | | +| `bsd.cfg` | [BSD](https://www.freebsd.org/) | | +| `cairo.cfg` | [cairo](https://www.cairographics.org/) | | +| `cppcheck-lib.cfg` | [Cppcheck](http://cppcheck.net/) | Used in selfcheck of the Cppcheck code base | +| `cppunit.cfg` | [CppUnit](https://sourceforge.net/projects/cppunit/) | | +| `dpdk.cfg` | | | +| `embedded_sql.cfg` | | | +| `emscripten.cfg` | | | +| `ginac.cfg` | | | +| `gnu.cfg` | [GNU](https://www.gnu.org/) | | +| `googletest.cfg` | [GoogleTest](https://github.com/google/googletest) | | +| `gtk.cfg` | [GTK](https://www.gtk.org/) | | +| `icu.cfg` | | | +| `kde.cfg` | [KDE](https://kde.org/) | | +| `libcerror.cfg` | [libcerror](https://github.com/libyal/libcerror) | | +| `libcurl.cfg` | [libcurl](https://curl.se/libcurl/) | | +| `libsigc++.cfg` | [libsigc++](https://github.com/libsigcplusplus/libsigcplusplus) | | +| `lua.cfg` | | | +| `mfc.cfg` | [MFC](https://learn.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications) | | +| `microsoft_atl.cfg` | [ATL](https://learn.microsoft.com/en-us/cpp/atl/active-template-library-atl-concepts) | | +| `microsoft_sal.cfg` | [SAL annotations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/sal-annotations) | | +| `microsoft_unittest.cfg` | [CppUnitTest](https://learn.microsoft.com/en-us/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference) | | +| `motif.cfg` | | | +| `nspr.cfg` | | | +| `ntl.cfg` | | | +| `opencv2.cfg` | [OpenCV](https://opencv.org/) | | +| `opengl.cfg` | [OpenGL](https://opengl.org/) | | +| `openmp.cfg` | [OpenMP](https://www.openmp.org/) | | +| `openssl.cfg` | [OpenSSL](https://www.openssl.org/) | | +| `pcre.cfg` | [PCRE](https://pcre.org/) | | +| `posix.cfg` | [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/) | | +| `python.cfg` | | | +| `qt.cfg` | [Qt](https://doc.qt.io/qt.html) | | +| `ruby.cfg` | | | +| `sdl.cfg` | | | +| `sfml.cfg` | | | +| `sqlite3.cfg` | [SQLite](https://www.sqlite.org/) | | +| `std.cfg` | C/C++ standard library | Loaded by default | +| `tinyxml2.cfg` | [TinyXML-2](https://github.com/leethomason/tinyxml2) | | +| `vcl.cfg` | | | +| `windows.cfg` | [Win32 API](https://learn.microsoft.com/en-us/windows/win32/) | | +| `wxsqlite3.cfg` | | | +| `wxsvg.cfg` | | | +| `wxwidgets.cfg` | [wxWidgets](https://www.wxwidgets.org/) | | +| `zephyr.cfg` | | | +| `zlib.cfg` | [zlib](https://www.zlib.net) | | + +## Creating a custom `.cfg` file + +You can create and use your own `.cfg` files for your projects. Use `--check-library` to get hints about what you should configure. You can use the `Library Editor` in the `Cppcheck GUI` to edit configuration files. It is available in the `View` menu. -The .cfg file format is documented in the `Reference: Cppcheck .cfg format` (https://cppcheck.sourceforge.io/reference-cfg-format.pdf) document. +The `.cfg` file format is documented in the `Reference: Cppcheck .cfg format` () document. -# HTML Report +# HTML report You can convert the XML output from Cppcheck into a HTML report. You'll need Python and the pygments module () for this to work. In the Cppcheck source tree there is a folder htmlreport that contains a script that transforms a Cppcheck XML file into HTML output. @@ -1170,15 +1203,17 @@ Example usage: cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=. or + cppcheck gui/test.cpp --xml 2> err.xml cppcheck-htmlreport --file=err.xml --report-dir=test1 \ --source-dir=https://github.com///blob// -## Choosing Between Local Annotated HTML and Remote Repository Links +## Choosing between local annotated HTML and remote repository links + +`cppcheck-htmlreport` supports two modes for linking to source files: -cppcheck-htmlreport supports two modes for linking to source files: - - Local annotated HTML files (default when `--source-dir` is a filesystem path) - - Remote GitHub/GitLab links (when `--source-dir` is a URL) +- Local annotated HTML files (default when `--source-dir` is a filesystem path) +- Remote GitHub/GitLab links (when `--source-dir` is a URL) Pointing `--source-dir` to a filesystem path generates local annotated HTML files. This is useful when you need a fully self-contained report that works offline, @@ -1193,13 +1228,13 @@ handled by the hosting service. In general, local mode fits air-gapped environments, while remote mode works best for CI workflows and large or private repositories. -# Check Level +# Check level ## Reduced The "reduced" check level performs a limited data flow analysis. If developers -want to run cppcheck directly during development and require faster results -than "normal" provides then this reduced checking can be an option. +want to run Cppcheck directly during development and require faster results +than "normal" provides, then this reduced checking can be an option. ## Normal @@ -1209,7 +1244,7 @@ The "normal" check level should be useful during active development: - checking files while you edit them. - block changes to the repo -- etc +- etc. ## Exhaustive @@ -1218,7 +1253,7 @@ When you can wait longer for the results you can enable the "exhaustive" checkin Exhaustive checking level should be useful for scenarios where you can wait for results. For instance: - nightly builds -- etc +- etc. # Speeding up analysis @@ -1226,18 +1261,17 @@ Exhaustive checking level should be useful for scenarios where you can wait for For performance reasons it might be a good idea to limit preprocessor configurations to check. -## Limit ValueFlow: max if count +## Limit ValueFlow: max `if` count -The command line option `--performance-valueflow-max-if-count` adjusts the max count for number of if in a function. +The command line option `--performance-valueflow-max-if-count` adjusts the max count for number of `if` in a function. -When that limit is exceeded there is a limitation of data flow in that function. It is not drastic: +When that limit is exceeded, there is a limitation of data flow in that function. It is not drastic: - Analysis of other functions are not affected. - It's only for some specific data flow analysis, we have data flow analysis that is always executed. - All checks are always executed. There can still be plenty of warnings in the limited function. -There is data flow analysis that slows down exponentially when number of if increase. And the limit is intended to avoid that -analysis time explodes. +There is data flow analysis that slows down exponentially when number of `if` increase. And the limit is intended to avoid that analysis time explodes. ## GUI options @@ -1248,13 +1282,13 @@ In the GUI: - Open the project dialog. - In the "Analysis" tab there are several options. -If you want to use these limitations on the command line also you can import the GUI project file with --project. +If you want to use these limitations on the command line too, you can import the GUI project file with `--project`. # Cppcheck Premium ## Bug hunting -This is analysis that is more noisy than normal analysis. Most warnings will be false positives (cppcheck will wrongly claim that there are bugs). The design goal is to not have more than roughly 5 - 10 false positives in each file. +This is analysis that is more noisy than normal analysis. Most warnings will be false positives (Cppcheck will wrongly claim that there are bugs). The design goal is to not have more than roughly 5 to 10 false positives in each file. It is not intended to be used in normal CI or regular static analysis by developers. The noise makes it useless for that. @@ -1262,7 +1296,7 @@ It is intended to be used when you are looking for bugs and you really can accep - You have developed a brand new feature and want to ensure that there are no bugs. - Maybe as part of release testing your product you can run bug hunting on modified files. -- Etc +- Etc. Technically, analysis that is "sound" will detect all bugs. Analysis that is "soundy" has the goal to detect most bugs and it tries to keep the noise at an reasonable level. @@ -1270,41 +1304,41 @@ The Cppcheck bug hunting analysis is "soundy". Command: - cppcheck --premium=bughunting .... + cppcheck --premium=bughunting ... ## Coding standards Command to activate Autosar checkers: - cppcheck --premium=autosar .... + cppcheck --premium=autosar ... Command to activate Cert C checkers: - cppcheck --premium=cert-c .... + cppcheck --premium=cert-c ... Command to activate Cert C++ checkers: - cppcheck --premium=cert-c++ .... + cppcheck --premium=cert-c++ ... Command to activate Misra C 2012 checkers: - cppcheck --premium=misra-c-2012 .... + cppcheck --premium=misra-c-2012 ... Command to activate Misra C 2023 checkers: - cppcheck --premium=misra-c-2023 .... + cppcheck --premium=misra-c-2023 ... Command to activate Misra C 2025 checkers: - cppcheck --premium=misra-c-2025 .... + cppcheck --premium=misra-c-2025 ... Command to activate Misra C++ 2008 checkers: - cppcheck --premium=misra-c++-2008 .... + cppcheck --premium=misra-c++-2008 ... Command to activate Misra C++ 2023 checkers: - cppcheck --premium=misra-c++-2023 .... + cppcheck --premium=misra-c++-2023 ... ### Checking all C and C++ files @@ -1312,7 +1346,7 @@ The `cert-c` and `misra-c-*` coding standards target C and therefore the checker The `autosar`, `cert-c++` and `misra-c++-*` coding standards target C++ and therefore the checkers only check C++ files by default. -If you want to check all files you can append ":all" to the coding standard. Example: +If you want to check all files, you can append `:all` to the coding standard. Example: # Misra C checkers are executed on C files, not on C++ files cppcheck --premium=misra-c-2025 path @@ -1320,7 +1354,6 @@ If you want to check all files you can append ":all" to the coding standard. Exa # Misra C checkers are executed on C and C++ files cppcheck --premium=misra-c-2025:all path - ## Compliance report ### Graphical user interface @@ -1331,7 +1364,7 @@ the `Compliance report...` in the `File` menu. ### Command line There is a tool `compliance-report` that is distributed with Cppcheck Premium. To see -all available options run `compliance-report` in a terminal with no options. +all available options, run `compliance-report` in a terminal with no options. Below is example usage to generate a Misra C 2012 compliance report. @@ -1344,12 +1377,12 @@ Description of the options: - `--misra-c-2012`: Generate a compliance report for misra-c-2012 - `--project-name`: The name of the project - `--project-version`: The version of the project -- `--output-file`: html filename that the report should be written to -- `results.xml`: The xml output from cppcheck +- `--output-file`: HTML filename that the report should be written to +- `results.xml`: The XML output from Cppcheck ## Metrics -To generate metrics add option `--premium=metrics`. The metrics are saved in the xml v3 report. +To generate metrics, add option `--premium=metrics`. The metrics are saved in the XML v3 report. Example: cppcheck --premium=metrics test.c --xml-version=3 2> res.xml @@ -1358,41 +1391,41 @@ We provide a small simple python script that creates a metrics report in CSV for python3 HISReport.py -f res.xml -j path/to/cppcheck-id-mapping.json -o test.csv -the `cppcheck-id-mapping.json` is provided in the cppcheck premium installation folder, i.e. +The `cppcheck-id-mapping.json` is provided in the Cppcheck premium installation folder, i.e. `/opt/cppcheckpremium` or `C:\Program Files\Cppcheck Premium`. -We do not have a ready-made solution to generate a html/pdf report. You can easily tweak our -HISReport.py script so that it generates html and get the report exactly as you want. +We do not have a ready-made solution to generate a HTML/pdf report. You can easily tweak our +`HISReport.py` script so that it generates HTML and get the report exactly as you want. ## Licenses -### Commercial Terms +### Commercial terms Information about Cppcheck Premium licenses: -https://www.cppcheck.com/plans-pricing + -### Installation / Registration +### Installation / registration This is described on the Cppcheck Premium website: -https://www.cppcheck.com + ### License file path There are predefined paths where the premium addon search for license files. If you want to -provide an arbitrary license file path on the command line you can use the option +provide an arbitrary license file path on the command line, you can use the option `--premium-license-file`. Example: cppcheck --premium-license-file=path/to/file.lic test.cpp -If an explicit path is provided like this then premium addon does not search for license +If an explicit path is provided like this, then premium addon does not search for license files in the predefined paths. ### Troubleshooting -#### Step 1: check premiumaddon debug output +#### Step 1: check `premiumaddon` debug output -If your license does not work you can get some details about the license validation by executing -premiumaddon binary with the `--debug` option. +If your license does not work, you can get some details about the license validation by executing +`premiumaddon` binary with the `--debug` option. Windows: @@ -1404,18 +1437,17 @@ Linux/Mac: These commands can be executed from an arbitrary folder. -#### Step 2: clean up cppcheck build dir +#### Step 2: clean up Cppcheck build dir Command line: -If you use --cppcheck-build-dir then remove all files in the specified folder and recheck. +If you use `--cppcheck-build-dir`, then remove all files in the specified folder and recheck. Cppcheck GUI: -The GUI normally by default creates a cppcheck build dir. Clear all results and recheck. +The GUI normally by default creates a Cppcheck build dir. Clear all results and recheck. You can clear all results by clicking on the brush icon in the toolbar. Or by open `Edit` menu and selecting menu item `Clear results`. -#### Step 3: remove cppcheck-premium-loc files +#### Step 3: remove `cppcheck-premium-loc` files -If you have cppcheck-premium-loc files in your project folders those should be removed. +If you have `cppcheck-premium-loc` files in your project folders, those should be removed. If such files are generated during analysis, then review your scripts to check why those files are generated. - diff --git a/man/manual.md b/man/manual.md index d8da119f388..8d8d5b22350 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1,6 +1,6 @@ --- title: Cppcheck manual -subtitle: Version 2.19 dev +subtitle: Version 2.21 dev author: Cppcheck team lang: en documentclass: report @@ -8,8 +8,8 @@ documentclass: report # Introduction -Cppcheck is an analysis tool for C/C++ code. It provides unique code analysis to detect bugs and focuses on detecting -undefined behaviour and dangerous coding constructs. The goal is to detect only real errors in the code, and generate +Cppcheck is an analysis tool for C/C++ code. It provides unique code analysis to detect bugs and focuses on detecting +undefined behaviour and dangerous coding constructs. The goal is to detect only real errors in the code, and generate as few false positives (wrongly reported warnings) as possible. Cppcheck is designed to analyze your C/C++ code even if it has non-standard syntax, as is common in for example embedded projects. @@ -17,7 +17,7 @@ Supported code and platforms: - Cppcheck checks non-standard code that contains various compiler extensions, inline assembly code, etc. - Cppcheck should be compilable by any compiler that supports C++11 or later. -- Cppcheck is cross platform and is used in various posix/windows/etc environments. +- Cppcheck is cross-platform and is used in various posix/windows/etc environments. The checks in Cppcheck are not perfect. There are bugs that should be found, that Cppcheck fails to detect. @@ -30,11 +30,11 @@ The kinds of bugs that you can find with static analysis are: - Coding style There are many bugs that you can not find with static analysis. Static analysis tools do not have human knowledge about -what your program is intended to do. If the output from your program is valid but unexpected then in most cases this is -not detected by static analysis tools. For instance, if your small program writes "Helo" on the screen instead of "Hello" +what your program is intended to do. If the output from your program is valid but unexpected, then in most cases this is +not detected by static analysis tools. For instance, if your small program writes "Helo" on the screen instead of "Hello", it is unlikely that any tool will complain about that. -Static analysis should be used as a complement in your quality assurance. It does not replace any of; +Static analysis should be used as a complement in your quality assurance. It does not replace any of: - Careful design - Testing @@ -70,7 +70,7 @@ Here is some simple code: return 0; } -If you save that into file1.c and execute: +If you save that into `file1.c` and execute: cppcheck file1.c @@ -85,7 +85,7 @@ Normally a program has many source files. Cppcheck can check all source files in cppcheck path -If "path" is a folder, then Cppcheck will recursively check all source files in this folder: +If `path` is a folder, then Cppcheck will recursively check all source files in this folder: Checking path/file1.cpp... 1/2 files checked 50% done @@ -94,21 +94,22 @@ If "path" is a folder, then Cppcheck will recursively check all source files in ### Check files manually or use project file -With Cppcheck you can check files manually by specifying files/paths to check and settings. Or you can use a build +With Cppcheck you can check files manually by specifying files/paths to check and settings. Or you can use a build environment, such as CMake or Visual Studio. -We don't know which approach (project file or manual configuration) will give you the best results. It is recommended -that you try both. It is possible that you will get different results so that to find the largest amount of bugs you +We don't know which approach (project file or manual configuration) will give you the best results. It is recommended +that you try both. It is possible that you will get different results so that to find the largest amount of bugs you need to use both approaches. Later chapters will describe this in more detail. ### Check files matching a given file filter With `--file-filter=` you can configure file filter(s) and then only those files matching the filter will be checked. -You can use `**`, `*` and `?` in the file filter pattern. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators +You can use `**`, `*` and `?` in the file filter pattern. + +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. For example, this command below means that `src/test1.cpp` could be checked, but `src/file2.cpp` and `src/test/file1.cpp` will not be checked: @@ -122,22 +123,24 @@ A common use case for `--file-filter` is to check a project, but only check cert cppcheck --project=compile_commands.json --file-filter=src/*.c Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `--file-filter=src/*.c` would mean that: - * a file with relative path `test1.c` is not checked. - * a file with relative path `src/test2.c` can be checked. - * a file with relative path `src/test3.cpp` is not checked. + +- a file with relative path `test1.c` is not checked. +- a file with relative path `src/test2.c` can be checked. +- a file with relative path `src/test3.cpp` is not checked. ### Ignore files matching a given pattern With `-i ` you can configure filename/directory patterns that should be ignored. -A file that is ignored will not be checked directly (the complete translation unit is skipped). Any header #include'd from a source file which is not ignored is checked indirectly, regardless if the header is ignored. +A file that is ignored will not be checked directly (the complete translation unit is skipped). Any header `#include`'d from a source file which is not ignored is checked indirectly, regardless if the header is ignored. + +> *Note*: If you want to filter out warnings for a header file, then `-i` will not work. Use suppressions instead. -> *Note*: If you want to filter out warnings for a header file then `-i` will not work. Use suppressions instead. +You can use `**`, `*` and `?` in the pattern to specify excluded folders/files. -You can use `**`, `*` and `?` in the pattern to specify excluded folders/files. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. A use case for `-i` is to check a project, but exclude certain files/folders: @@ -145,8 +148,8 @@ A use case for `-i` is to check a project, but exclude certain files/folders: Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `-itest` would mean that: - * a file with relative path `test1.cpp` can be checked. - * a file with relative path `test/somefile.cpp` is not checked +- a file with relative path `test1.cpp` can be checked. +- a file with relative path `test/somefile.cpp` is not checked ### Clang parser (experimental) @@ -157,7 +160,7 @@ Install `clang`. Then use Cppcheck option `--clang`. Cppcheck executes clang with the -ast-dump option, imports the output, converts it to Cppcheck's internal format, and then performs standard analysis. -You can also pass a custom Clang executable to the option by using for example `--clang=clang-10`. You can also pass it +You can also pass a custom Clang executable to the option by using for example `--clang=clang-10`. You can also pass it with a path. On Windows it will append the `.exe` extension unless you use a path. ## Severities @@ -178,17 +181,17 @@ stylistic issues, such as unused functions, redundant code, constness, operator **performance** -run time performance suggestions based on common knowledge, though it is not certain any measurable speed difference +run time performance suggestions based on common knowledge, though it is not certain any measurable speed difference will be achieved by fixing these messages. **portability** -portability warnings. Implementation defined behavior. 64-bit portability. Some undefined behavior that probably works +portability warnings. Implementation defined behavior. 64-bit portability. Some undefined behavior that probably works "as you want", etc. **information** -configuration problems, which does not relate to the syntactical correctness, but the used Cppcheck configuration could +configuration problems, which does not relate to the syntactical correctness, but the used Cppcheck configuration could be improved. ## Possible speedup analysis of template code @@ -222,7 +225,7 @@ Cppcheck output: As you can see Cppcheck has instantiated `a` until `a<101>` was reached and then it bails out. -To limit template recursion you can: +To limit template recursion, you can: - add template specialisation - configure Cppcheck, which can be done in the GUI project file dialog @@ -246,7 +249,6 @@ Example code with template specialisation: You can pass `-D__cppcheck__` when checking this code. - # Cppcheck build folder Using a Cppcheck build folder is not mandatory but it is recommended. @@ -280,25 +282,25 @@ You can import and use Cppcheck GUI project files in the command line tool: cppcheck --project=foobar.cppcheck -The Cppcheck GUI has a few options that are not available in the command line directly. To use these options you can import a GUI project file. +The Cppcheck GUI has a few options that are not available in the command line directly. To use these options, you can import a GUI project file. The command line tool usage is kept intentionally simple and the options are therefore limited. -To ignore certain folders in the project you can use `-i`. This will skip the analysis of source files in the `foo` folder. +To ignore certain folders in the project, you can use `-i`. This will skip the analysis of source files in the `foo` folder. cppcheck --project=foobar.cppcheck -ifoo -## Compilation database (cmake etc) +## Compilation database (CMake etc.) Many build systems can generate a compilation database (a JSON file containing compilation commands for each source file). Example `cmake` command to generate the file: cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON . -When you have a `compile_commands.json` file you can run Cppcheck like this: +When you have a `compile_commands.json` file, you can run Cppcheck like this: cppcheck --project=compile_commands.json -By default only 1 configuration is checked because that is consistent with the compilation. If you want to check more configurations you can use `--max-configs` or `--force`. For example: +By default only 1 configuration is checked because that is consistent with the compilation. If you want to check more configurations, you can use `--max-configs` or `--force`. For example: cppcheck --project=compile_commands.json --force @@ -306,15 +308,18 @@ To ignore certain folders you can use `-i`. This will skip analysis of source fi cppcheck --project=compile_commands.json -ifoo - ## Visual Studio -You can run Cppcheck on individual project files (\*.vcxproj) or on a whole solution (\*.sln) +You can run Cppcheck on individual project files (`*.vcxproj`) or on a whole solution (`*.sln`) or (`*.slnx`). Running Cppcheck on an entire Visual Studio solution: cppcheck --project=foobar.sln +Running Cppcheck on an entire Visual Studio 2026 solution: + + cppcheck --project=foobar.slnx + Running Cppcheck on a Visual Studio project: cppcheck --project=foobar.vcxproj @@ -326,7 +331,7 @@ Limiting on a single configuration: In the `Cppcheck GUI` you have the option to only analyze a single debug configuration. If you want to use this option on the command line, then create a `Cppcheck GUI` project with this activated and then import the GUI project file on the command line. -To ignore certain folders in the project you can use `-i`. This will skip analysis of source files in the `foo` folder. +To ignore certain folders in the project, you can use `-i`. This will skip analysis of source files in the `foo` folder. cppcheck --project=foobar.vcxproj -ifoo @@ -336,8 +341,7 @@ Running Cppcheck on a C++ Builder 6 project: cppcheck --project=foobar.bpr - -To ignore certain folders in the project you can use `-i`. This will skip analysis of source files in the `foo` folder. +To ignore certain folders in the project, you can use `-i`. This will skip analysis of source files in the `foo` folder. cppcheck --project=foobar.bpr -ifoo @@ -347,18 +351,18 @@ If you generate a compilation database, then it is possible to import that in Cp ### Makefile -In Linux you can convert a Makefile to a compile_commands.json using for instance `bear` (build ear) utility: +In Linux you can convert a Makefile to a `compile_commands.json` using for instance `bear` (build ear) utility: bear -- make -If you don't use Linux; there are python scripts that converts a Makefile into a compilation database. +If you don't use Linux, there are Python scripts that converts a Makefile into a compilation database. -# Preprocessor Settings +# Preprocessor settings -If you use `--project` then Cppcheck will automatically use the preprocessor settings in the imported project file and +If you use `--project`, then Cppcheck will automatically use the preprocessor settings in the imported project file and likely you don't have to configure anything extra. -If you don't use `--project` then a bit of manual preprocessor configuration might be required. However Cppcheck has +If you don't use `--project`, then a bit of manual preprocessor configuration might be required. However Cppcheck has automatic configuration of defines. ## Automatic configuration of preprocessor defines @@ -366,7 +370,7 @@ automatic configuration of defines. Cppcheck automatically test different combinations of preprocessor defines to achieve as high coverage in the analysis as possible. -Here is a file that has 3 bugs (when x,y,z are assigned). +Here is a file that has 3 bugs (when `x`, `y`, `z` are assigned). #ifdef A x=100/0; @@ -422,17 +426,17 @@ Example: ## Include paths -To add an include path, use `-I`, followed by the path. +To add an include path, use `-I` followed by the path. -Cppcheck's preprocessor basically handles includes like any other preprocessor. However, while other preprocessors -stop working when they encounter a missing header, Cppcheck will just print an information message and continues +Cppcheck's preprocessor basically handles includes like any other preprocessor. However, while other preprocessors +stop working when they encounter a missing header, Cppcheck will just print an information message and continues parsing the code. -The purpose of this behaviour is that Cppcheck is meant to work without necessarily seeing the entire code. -Actually, it is recommended to not give all include paths. -While it is useful for Cppcheck to see the declaration of a class when checking the implementation of its members, -passing standard library headers is discouraged, because the analysis will not work fully and lead to a longer checking -time. For such cases, .cfg files are the preferred way to provide information about the implementation of functions and +The purpose of this behaviour is that Cppcheck is meant to work without necessarily seeing the entire code. +Actually, it is recommended to not give all include paths. +While it is useful for Cppcheck to see the declaration of a class when checking the implementation of its members, +passing standard library headers is discouraged, because the analysis will not work fully and lead to a longer checking +time. For such cases, `.cfg` files are the preferred way to provide information about the implementation of functions and types to Cppcheck, see below for more information. # Platform @@ -463,7 +467,7 @@ You can also create your own custom platform configuration in a XML file. Here i -# C/C++ Standard +# C/C++ standard Use `--std` on the command line to specify a C/C++ standard. @@ -492,7 +496,7 @@ the GUI, the build dir is configured in the project options. Rechecking code will be much faster. Cppcheck does not analyse unchanged code. The old warnings are loaded from the build dir and reported again. -Whole program analysis does not work when multiple threads are used; unless you use a cppcheck +Whole program analysis does not work when multiple threads are used unless you use a Cppcheck build dir. For instance, the unusedFunction warnings require whole program analysis. # Suppressions @@ -510,12 +514,13 @@ The format for an error suppression is one of: [error id]:[filename2] [error id] -The `error id` is the id that you want to suppress. The id of a warning is shown in brackets in the normal cppcheck text output. +The `error id` is the id that you want to suppress. The id of a warning is shown in brackets in the normal Cppcheck text output. + +The `error id` and `filename` patterns may contain `**`, `*` or `?`. -The `error id` and `filename` patterns may contain `**`, `*` or `?`. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. It is recommended to use forward-slash `/` in the filename pattern as path separator on all operating systems. @@ -557,9 +562,10 @@ You can specify suppressions in a XML file, for example as follows: The `id` and `fileName` patterns may contain `**`, `*` or `?`. -`**`: matches zero or more characters, including path separators -`*`: matches zero or more characters, excluding path separators -`?`: matches any single character except path separators + +- `**` matches zero or more characters, including path separators. +- `*` matches zero or more characters, excluding path separators. +- `?` matches any single character except path separators. The XML format is extensible and may be extended with further attributes in the future. @@ -569,7 +575,7 @@ The usage of the suppressions file is as follows: ## Inline suppressions -Suppressions can also be added directly in the code by adding comments that contain special keywords. +Suppressions can also be added directly in the code by adding comments that contain special keywords. Note that adding comments sacrifices the readability of the code somewhat. This code will normally generate an error message: @@ -594,7 +600,7 @@ You can suppress a warning `aaaa` with: // cppcheck-suppress aaaa -Suppressing multiple ids in one comment by using []: +Suppressing multiple ids in one comment by using `[]`: // cppcheck-suppress [aaaa, bbbb] @@ -625,7 +631,6 @@ Suppressing warnings `aaaa` where macro is used: ... x = MACRO; // <- aaaa warnings are suppressed here - Suppressing multiple ids where macro is used: // cppcheck-suppress-macro [aaaa, bbbb] @@ -654,7 +659,21 @@ Or at the same line as the code: arr[10] = 0; // cppcheck-suppress arrayIndexOutOfBounds } -In this example there are 2 lines with code and 1 suppression comment. The suppression comment only applies to 1 line: `a = b + c;`. +The suppression comment and the line of code may be separated by additional comments or empty lines: + + void f() { + char arr[5]; + + // cppcheck-suppress arrayIndexOutOfBounds + + arr[10] = 0; + + // cppcheck-suppress arrayIndexOutOfBounds + // Set the tenth element of arr to zero + arr[10] = 0; + } + +In the example below there are 2 lines with code and 1 suppression comment. The suppression comment only applies to 1 line: `a = b + c;`. void f() { a = b + c; // cppcheck-suppress abc @@ -701,7 +720,6 @@ Suppression comment on the same line as the code: arr[10] = arr[10] / 0; // cppcheck-suppress[arrayIndexOutOfBounds,zerodiv] } - ### Symbol name You can specify that the inline suppression only applies to a specific symbol: @@ -801,7 +819,7 @@ If you want to reformat the output so that it looks different, then you can use ## Predefined output formats -To get Visual Studio compatible output you can use --template=vs: +To get Visual Studio compatible output, you can use `--template=vs`: cppcheck --template=vs samples/arrayIndexOutOfBounds/bad.c @@ -811,7 +829,7 @@ This output will look like this: samples/arrayIndexOutOfBounds/bad.c(6): error: Array 'a[2]' accessed at index 2, which is out of bounds. -To get gcc compatible output you can use --template=gcc: +To get GCC-compatible output, you can use `--template=gcc`: cppcheck --template=gcc samples/arrayIndexOutOfBounds/bad.c @@ -849,7 +867,7 @@ The output will look like this: samples/arrayIndexOutOfBounds/bad.c,6,error,arrayIndexOutOfBounds, Array 'a[2]' accessed at index 2, which is out of bounds. -## User defined output format (multi line) +## User defined output format (multi-line) Many warnings have multiple locations. Example code: @@ -865,9 +883,9 @@ Many warnings have multiple locations. Example code: return 0; } -There is a possible null pointer dereference at line 3. -Cppcheck can show how it came to that conclusion by showing extra location information. -You need to use both --template and --template-location at the command line, for example: +There is a possible null pointer dereference at line 3. +Cppcheck can show how it came to that conclusion by showing extra location information. +You need to use both `--template` and `--template-location` at the command line, for example: cppcheck \ --template="{file}:{line}: {severity}: {message}\n{code}" \ @@ -889,13 +907,13 @@ The output from Cppcheck is: *p = 3; ^ -The first line in the warning is formatted by the --template format. +The first line in the warning is formatted by the `--template` format. -The other lines in the warning are formatted by the --template-location format. +The other lines in the warning are formatted by the `--template-location` format. -### Format specifiers for --template +### Format specifiers for `--template` -The available specifiers for --template are: +The available specifiers for `--template` are: **{file}** @@ -911,11 +929,11 @@ Column number **{callstack}** -Write all locations. Each location is written in [{file}:{line}] format and the locations are separated by ->. For instance it might look like: [multiline.c:8] -> [multiline.c:9] -> [multiline.c:3] +Write all locations. Each location is written in `[{file}:{line}]` format and the locations are separated by `->`. For instance it might look like: `[multiline.c:8] -> [multiline.c:9] -> [multiline.c:3]` **{inconclusive:text}** -If warning is inconclusive, then the given text is written. The given text can be any text that does not contain }. Example: {inconclusive:inconclusive,} +If warning is inconclusive, then the given text is written. The given text can be any text that does not contain `}`. Example: `{inconclusive:inconclusive,}` **{severity}** @@ -949,7 +967,7 @@ Newline Carriage return -### Format specifiers for --template-location +### Format specifiers for `--template-location` The available specifiers for `--template-location` are: @@ -1001,7 +1019,7 @@ Example code: int x = 0; } -In Cppcheck text output the remarks are not shown by default, you can use `--template` option `{remark}` to show remarks: +In Cppcheck text output, the remarks are not shown by default, you can use `--template` option `{remark}` to show remarks: $ ./cppcheck --enable=style \ --template="{file}:{line}: {message} [{id}]\\n{remark}" test1.c @@ -1010,12 +1028,12 @@ In Cppcheck text output the remarks are not shown by default, you can use `--tem test1.c:4: Variable 'x' is assigned a value that is never used. [unreadVariable] Initialize x with 0 -In xml output the comment text is provided in a "remark" attribute: +In XML output, the comment text is provided in a `remark` attribute: $ ./cppcheck --enable=style --xml test1.c - .... + ... remark="Initialize x with 0" - .... + ... # Addons @@ -1025,11 +1043,11 @@ Cppcheck is distributed with a few addons which are listed below. ## Supported addons -### misra.py +### `misra.py` -[misra.py](https://github.com/danmar/cppcheck/blob/main/addons/misra.py) is used to verify compliance with MISRA C 2012, a proprietary set of guidelines to avoid questionable code, developed for embedded systems. +[`misra.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misra.py) is used to verify compliance with MISRA C 2012, a proprietary set of guidelines to avoid questionable code, developed for embedded systems. -The misra.py script does not provide rule texts, those should be downloaded from [MISRA](https://gitlab.com/MISRA/MISRA-C/MISRA-C-2012/tools) +The `misra.py` script does not provide rule texts, those should be downloaded from [MISRA](https://gitlab.com/MISRA/MISRA-C/MISRA-C-2012/tools). To load the rule texts, create a configuration file. Example `misra.json`: @@ -1047,52 +1065,51 @@ To use that `misra.json` in Cppcheck analysis, use option `--addon=misra.json`: Misra checkers in open source Cppcheck only cover MISRA rules partially and for full coverage use Cppcheck Premium. -### namingng.py +### `namingng.py` -[namingng.py](https://github.com/danmar/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. +[`namingng.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. You need to have a configuration file that defines your naming conventions. By default the filename `namingng.config.json` is used but there is an option so you can use any filename you want. Example configuration of naming conventions: -``` -{ - "RE_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"], - "RE_PRIVATE_MEMBER_VARIABLE": null, - "RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"], - "_comment": "comments can be added to the config with underscore-prefixed keys", - "include_guard": { - "input": "path", - "prefix": "GUARD_", - "case": "upper", - "max_linenr": 5, - "RE_HEADERFILE": "[^/].*\\.h\\Z", - "required": true - }, - "var_prefixes": {"uint32_t": "ui32"}, - "function_prefixes": {"uint16_t": "ui16", - "uint32_t": "ui32"} -} -``` - -### threadsafety.py - -[threadsafety.py](https://github.com/danmar/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. - -### y2038.py - -[y2038.py](https://github.com/danmar/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. - -## Running Addons + + { + "RE_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"], + "RE_PRIVATE_MEMBER_VARIABLE": null, + "RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"], + "_comment": "comments can be added to the config with underscore-prefixed keys", + "include_guard": { + "input": "path", + "prefix": "GUARD_", + "case": "upper", + "max_linenr": 5, + "RE_HEADERFILE": "[^/].*\\.h\\Z", + "required": true + }, + "var_prefixes": {"uint32_t": "ui32"}, + "function_prefixes": {"uint16_t": "ui16", + "uint32_t": "ui32"} + } + +### `threadsafety.py` + +[`threadsafety.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. + +### `y2038.py` + +[`y2038.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. + +## Running addons Addons can be executed with the `--addon` option: cppcheck --addon=namingng.py somefile.c -Likewise, if you have created your own script you can execute that: +Likewise, if you have created your own script, you can execute that: cppcheck --addon=mychecks.py somefile.c -You can configure how you want to execute an addon in a json file. For example: +You can configure how you want to execute an addon in a JSON file. For example: { "script": "mychecks.py", @@ -1102,7 +1119,7 @@ You can configure how you want to execute an addon in a json file. For example: "ctu": false } -To use that json file to execute your addon use the --addon option: +To use that JSON file to execute your addon, use the `--addon` option: cppcheck --addon=mychecks.json somefile.c @@ -1112,75 +1129,74 @@ Cppcheck search for addons in the local folder first and then in the installatio # Library configuration -When external libraries are used, such as WinAPI, POSIX, gtk, Qt, etc, Cppcheck has no information about functions, types, or macros contained in those libraries. Cppcheck then fails to detect various problems in the code, or might even abort the analysis. But this can be fixed by using the appropriate configuration files. - -Cppcheck already contains configurations for several libraries. They can be loaded as described below. Note that the configuration for the standard libraries of C and C++, std.cfg, is always loaded by cppcheck. If you create or update a configuration file for a popular library, we would appreciate if you supplied it to the cppcheck project. - -## Using a .cfg file - -To use a .cfg file shipped with cppcheck, pass the `--library=` option. The table below shows the currently existing libraries: - -| .cfg file | Library | Comment | -| ----------------- | ------------- | ------------- | -| avr.cfg | | | -| bento4.cfg | [Bento4](http://www.bento4.com/) | | -| boost.cfg | [Boost](http://www.boost.org/) | | -| bsd.cfg | [BSD](https://www.freebsd.org/) | | -| cairo.cfg | [cairo](https://www.cairographics.org/) | | -| cppcheck-lib.cfg | [Cppcheck](http://cppcheck.net/) | Used in selfcheck of | -| | |the Cppcheck code base | -| cppunit.cfg | [CppUnit](https://sourceforge.net/projects/cppunit/) | | -| dpdk.cfg | | | -| embedded_sql.cfg | | | -| emscripten.cfg | | | -| ginac.cfg | | | -| gnu.cfg | [GNU](https://www.gnu.org/) | | -| googletest.cfg | [GoogleTest](https://github.com/google/googletest) | | -| gtk.cfg | [GTK](https://www.gtk.org/) | | -| icu.cfg | | | -| kde.cfg | [KDE](https://kde.org/) | | -| libcerror.cfg | [libcerror](https://github.com/libyal/libcerror) | | -| libcurl.cfg | [libcurl](https://curl.se/libcurl/) | | -| libsigc++.cfg | [libsigc++](https://github.com/libsigcplusplus/libsigcplusplus) | | -| lua.cfg | | | -| mfc.cfg | [MFC](https://learn.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications) | | -| microsoft_atl.cfg | [ATL](https://learn.microsoft.com/en-us/cpp/atl/active-template-library-atl-concepts) | | -| microsoft_sal.cfg | [SAL annotations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/sal-annotations) | | -| microsoft_unittest.cfg | [CppUnitTest](https://learn.microsoft.com/en-us/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference) | | -| motif.cfg | | | -| nspr.cfg | | | -| ntl.cfg | | | -| opencv2.cfg | [OpenCV](https://opencv.org/) | | -| opengl.cfg | [OpenGL](https://opengl.org/) | | -| openmp.cfg | [OpenMP](https://www.openmp.org/) | | -| openssl.cfg | [OpenSSL](https://www.openssl.org/) | | -| pcre.cfg | [PCRE](https://pcre.org/) | | -| posix.cfg | [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/) | | -| python.cfg | | | -| qt.cfg | [Qt](https://doc.qt.io/qt.html) | | -| ruby.cfg | | | -| sdl.cfg | | | -| sfml.cfg | | | -| sqlite3.cfg | [SQLite](https://www.sqlite.org/) | | -| std.cfg | C/C++ standard library | Loaded by default | -| tinyxml2.cfg | [TinyXML-2](https://github.com/leethomason/tinyxml2) | | -| vcl.cfg | | | -| windows.cfg | [Win32 API](https://learn.microsoft.com/en-us/windows/win32/) | | -| wxsqlite3.cfg | | | -| wxsvg.cfg | | | -| wxwidgets.cfg | [wxWidgets](https://www.wxwidgets.org/) | | -| zephyr.cfg | | | -| zlib.cfg | [zlib](https://www.zlib.net) | | - -## Creating a custom .cfg file - -You can create and use your own .cfg files for your projects. Use `--check-library` to get hints about what you should configure. +When external libraries are used, such as WinAPI, POSIX, gtk, Qt, etc., Cppcheck has no information about functions, types, or macros contained in those libraries. Cppcheck then fails to detect various problems in the code, or might even abort the analysis. But this can be fixed by using the appropriate configuration files. + +Cppcheck already contains configurations for several libraries. They can be loaded as described below. Note that the configuration for the standard libraries of C and C++, `std.cfg`, is always loaded by Cppcheck. If you create or update a configuration file for a popular library, we would appreciate if you supplied it to the Cppcheck project. + +## Using a `.cfg` file + +To use a `.cfg` file shipped with Cppcheck, pass the `--library=` option. The table below shows the currently existing libraries: + +| `.cfg` file | Library | Comment | +| --- | --- | --- | +| `avr.cfg` | | | +| `bento4.cfg` | [Bento4](http://www.bento4.com/) | | +| `boost.cfg` | [Boost](http://www.boost.org/) | | +| `bsd.cfg` | [BSD](https://www.freebsd.org/) | | +| `cairo.cfg` | [cairo](https://www.cairographics.org/) | | +| `cppcheck-lib.cfg` | [Cppcheck](http://cppcheck.net/) | Used in selfcheck of the Cppcheck code base | +| `cppunit.cfg` | [CppUnit](https://sourceforge.net/projects/cppunit/) | | +| `dpdk.cfg` | | | +| `embedded_sql.cfg` | | | +| `emscripten.cfg` | | | +| `ginac.cfg` | | | +| `gnu.cfg` | [GNU](https://www.gnu.org/) | | +| `googletest.cfg` | [GoogleTest](https://github.com/google/googletest) | | +| `gtk.cfg` | [GTK](https://www.gtk.org/) | | +| `icu.cfg` | | | +| `kde.cfg` | [KDE](https://kde.org/) | | +| `libcerror.cfg` | [libcerror](https://github.com/libyal/libcerror) | | +| `libcurl.cfg` | [libcurl](https://curl.se/libcurl/) | | +| `libsigc++.cfg` | [libsigc++](https://github.com/libsigcplusplus/libsigcplusplus) | | +| `lua.cfg` | | | +| `mfc.cfg` | [MFC](https://learn.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications) | | +| `microsoft_atl.cfg` | [ATL](https://learn.microsoft.com/en-us/cpp/atl/active-template-library-atl-concepts) | | +| `microsoft_sal.cfg` | [SAL annotations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/sal-annotations) | | +| `microsoft_unittest.cfg` | [CppUnitTest](https://learn.microsoft.com/en-us/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference) | | +| `motif.cfg` | | | +| `nspr.cfg` | | | +| `ntl.cfg` | | | +| `opencv2.cfg` | [OpenCV](https://opencv.org/) | | +| `opengl.cfg` | [OpenGL](https://opengl.org/) | | +| `openmp.cfg` | [OpenMP](https://www.openmp.org/) | | +| `openssl.cfg` | [OpenSSL](https://www.openssl.org/) | | +| `pcre.cfg` | [PCRE](https://pcre.org/) | | +| `posix.cfg` | [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/) | | +| `python.cfg` | | | +| `qt.cfg` | [Qt](https://doc.qt.io/qt.html) | | +| `ruby.cfg` | | | +| `sdl.cfg` | | | +| `sfml.cfg` | | | +| `sqlite3.cfg` | [SQLite](https://www.sqlite.org/) | | +| `std.cfg` | C/C++ standard library | Loaded by default | +| `tinyxml2.cfg` | [TinyXML-2](https://github.com/leethomason/tinyxml2) | | +| `vcl.cfg` | | | +| `windows.cfg` | [Win32 API](https://learn.microsoft.com/en-us/windows/win32/) | | +| `wxsqlite3.cfg` | | | +| `wxsvg.cfg` | | | +| `wxwidgets.cfg` | [wxWidgets](https://www.wxwidgets.org/) | | +| `zephyr.cfg` | | | +| `zlib.cfg` | [zlib](https://www.zlib.net) | | + +## Creating a custom `.cfg` file + +You can create and use your own `.cfg` files for your projects. Use `--check-library` to get hints about what you should configure. You can use the `Library Editor` in the `Cppcheck GUI` to edit configuration files. It is available in the `View` menu. -The .cfg file format is documented in the `Reference: Cppcheck .cfg format` (https://cppcheck.sourceforge.io/reference-cfg-format.pdf) document. +The `.cfg` file format is documented in the `Reference: Cppcheck .cfg format` () document. -# HTML Report +# HTML report You can convert the XML output from Cppcheck into a HTML report. You'll need Python and the pygments module () for this to work. In the Cppcheck source tree there is a folder htmlreport that contains a script that transforms a Cppcheck XML file into HTML output. @@ -1210,15 +1226,17 @@ Example usage: cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=. or + cppcheck gui/test.cpp --xml 2> err.xml cppcheck-htmlreport --file=err.xml --report-dir=test1 \ --source-dir=https://github.com///blob// -## Choosing Between Local Annotated HTML and Remote Repository Links +## Choosing between local annotated HTML and remote repository links + +`cppcheck-htmlreport` supports two modes for linking to source files: -cppcheck-htmlreport supports two modes for linking to source files: - - Local annotated HTML files (default when `--source-dir` is a filesystem path) - - Remote GitHub/GitLab links (when `--source-dir` is a URL) +- Local annotated HTML files (default when `--source-dir` is a filesystem path) +- Remote GitHub/GitLab links (when `--source-dir` is a URL) Pointing `--source-dir` to a filesystem path generates local annotated HTML files. This is useful when you need a fully self-contained report that works offline, @@ -1233,13 +1251,13 @@ handled by the hosting service. In general, local mode fits air-gapped environments, while remote mode works best for CI workflows and large or private repositories. -# Check Level +# Check level ## Reduced The "reduced" check level performs a limited data flow analysis. If developers -want to run cppcheck directly during development and require faster results -than "normal" provides then this reduced checking can be an option. +want to run Cppcheck directly during development and require faster results +than "normal" provides, then this reduced checking can be an option. ## Normal @@ -1249,7 +1267,7 @@ The "normal" check level should be useful during active development: - checking files while you edit them. - block changes to the repo -- etc +- etc. ## Exhaustive @@ -1258,7 +1276,7 @@ When you can wait longer for the results you can enable the "exhaustive" checkin Exhaustive checking level should be useful for scenarios where you can wait for results. For instance: - nightly builds -- etc +- etc. # Speeding up analysis @@ -1266,18 +1284,17 @@ Exhaustive checking level should be useful for scenarios where you can wait for For performance reasons it might be a good idea to limit preprocessor configurations to check. -## Limit ValueFlow: max if count +## Limit ValueFlow: max `if` count -The command line option `--performance-valueflow-max-if-count` adjusts the max count for number of if in a function. +The command line option `--performance-valueflow-max-if-count` adjusts the max count for number of `if` in a function. -When that limit is exceeded there is a limitation of data flow in that function. It is not drastic: +When that limit is exceeded, there is a limitation of data flow in that function. It is not drastic: - Analysis of other functions are not affected. - It's only for some specific data flow analysis, we have data flow analysis that is always executed. - All checks are always executed. There can still be plenty of warnings in the limited function. -There is data flow analysis that slows down exponentially when number of if increase. And the limit is intended to avoid that -analysis time explodes. +There is data flow analysis that slows down exponentially when number of `if` increase. And the limit is intended to avoid that analysis time explodes. ## GUI options @@ -1288,4 +1305,4 @@ In the GUI: - Open the project dialog. - In the "Analysis" tab there are several options. -If you want to use these limitations on the command line also you can import the GUI project file with --project. +If you want to use these limitations on the command line too, you can import the GUI project file with `--project`. diff --git a/man/reference-cfg-format.md b/man/reference-cfg-format.md index 7a9e3b6dee7..3067d0a8f2c 100644 --- a/man/reference-cfg-format.md +++ b/man/reference-cfg-format.md @@ -1,6 +1,6 @@ --- title: Cppcheck .cfg format -subtitle: Version 2.19 dev +subtitle: Version 2.21 dev author: Cppcheck team lang: en documentclass: report diff --git a/man/writing-addons.md b/man/writing-addons.md index da21ea513ad..e593c2e9cce 100644 --- a/man/writing-addons.md +++ b/man/writing-addons.md @@ -1,6 +1,6 @@ --- title: Writing addons -subtitle: Version 2.19 dev +subtitle: Version 2.21 dev author: Cppcheck team lang: en documentclass: report diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index ad7fb641024..c93b8694065 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -65,6 +65,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/checknullpointer.o \ $(libcppdir)/checkother.o \ $(libcppdir)/checkpostfixoperator.o \ + $(libcppdir)/checks.o \ $(libcppdir)/checksizeof.o \ $(libcppdir)/checkstl.o \ $(libcppdir)/checkstring.o \ @@ -152,13 +153,13 @@ simplecpp.o: ../externals/simplecpp/simplecpp.cpp ../externals/simplecpp/simplec tinyxml2.o: ../externals/tinyxml2/tinyxml2.cpp ../externals/tinyxml2/tinyxml2.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -w -D_LARGEFILE_SOURCE -c -o $@ ../externals/tinyxml2/tinyxml2.cpp -$(libcppdir)/valueflow.o: ../lib/valueflow.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/check.h ../lib/checkers.h ../lib/checkuninitvar.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/forwardanalyzer.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/programmemory.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/valueflow.o: ../lib/valueflow.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/check.h ../lib/checkers.h ../lib/checkuninitvar.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/forwardanalyzer.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/programmemory.h ../lib/regex.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp -$(libcppdir)/tokenize.o: ../lib/tokenize.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/tokenize.o: ../lib/tokenize.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenize.cpp -$(libcppdir)/symboldatabase.o: ../lib/symboldatabase.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/symboldatabase.o: ../lib/symboldatabase.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/symboldatabase.cpp $(libcppdir)/addoninfo.o: ../lib/addoninfo.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/config.h ../lib/json.h ../lib/path.h ../lib/standards.h ../lib/utils.h @@ -167,31 +168,31 @@ $(libcppdir)/addoninfo.o: ../lib/addoninfo.cpp ../externals/picojson/picojson.h $(libcppdir)/analyzerinfo.o: ../lib/analyzerinfo.cpp ../externals/tinyxml2/tinyxml2.h ../lib/analyzerinfo.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/standards.h ../lib/utils.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp -$(libcppdir)/astutils.o: ../lib/astutils.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/astutils.o: ../lib/astutils.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/astutils.cpp -$(libcppdir)/check.o: ../lib/check.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/check.o: ../lib/check.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check.cpp -$(libcppdir)/check64bit.o: ../lib/check64bit.cpp ../lib/addoninfo.h ../lib/check.h ../lib/check64bit.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/check64bit.o: ../lib/check64bit.cpp ../lib/addoninfo.h ../lib/check.h ../lib/check64bit.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check64bit.cpp -$(libcppdir)/checkassert.o: ../lib/checkassert.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkassert.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkassert.o: ../lib/checkassert.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkassert.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkassert.cpp -$(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkautovariables.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkautovariables.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkautovariables.cpp -$(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp -$(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/checkers.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/checkers.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp -$(libcppdir)/checkclass.o: ../lib/checkclass.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/checkclass.o: ../lib/checkclass.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkclass.cpp -$(libcppdir)/checkcondition.o: ../lib/checkcondition.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkcondition.h ../lib/checkers.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkcondition.o: ../lib/checkcondition.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkcondition.h ../lib/checkers.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp $(libcppdir)/checkers.o: ../lib/checkers.cpp ../lib/checkers.h ../lib/config.h @@ -200,73 +201,76 @@ $(libcppdir)/checkers.o: ../lib/checkers.cpp ../lib/checkers.h ../lib/config.h $(libcppdir)/checkersidmapping.o: ../lib/checkersidmapping.cpp ../lib/checkers.h ../lib/config.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersidmapping.cpp -$(libcppdir)/checkersreport.o: ../lib/checkersreport.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/checkersreport.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/standards.h ../lib/utils.h +$(libcppdir)/checkersreport.o: ../lib/checkersreport.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/checkersreport.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/standards.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersreport.cpp -$(libcppdir)/checkexceptionsafety.o: ../lib/checkexceptionsafety.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkexceptionsafety.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkexceptionsafety.o: ../lib/checkexceptionsafety.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkexceptionsafety.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkexceptionsafety.cpp -$(libcppdir)/checkfunctions.o: ../lib/checkfunctions.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkfunctions.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkfunctions.o: ../lib/checkfunctions.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkfunctions.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkfunctions.cpp -$(libcppdir)/checkinternal.o: ../lib/checkinternal.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkinternal.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkinternal.o: ../lib/checkinternal.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkinternal.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkinternal.cpp -$(libcppdir)/checkio.o: ../lib/checkio.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkio.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkio.o: ../lib/checkio.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkio.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkio.cpp -$(libcppdir)/checkleakautovar.o: ../lib/checkleakautovar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkleakautovar.o: ../lib/checkleakautovar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkleakautovar.cpp -$(libcppdir)/checkmemoryleak.o: ../lib/checkmemoryleak.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkmemoryleak.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkmemoryleak.o: ../lib/checkmemoryleak.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkmemoryleak.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkmemoryleak.cpp -$(libcppdir)/checknullpointer.o: ../lib/checknullpointer.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checknullpointer.o: ../lib/checknullpointer.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checknullpointer.cpp -$(libcppdir)/checkother.o: ../lib/checkother.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkother.o: ../lib/checkother.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkother.cpp -$(libcppdir)/checkpostfixoperator.o: ../lib/checkpostfixoperator.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checkpostfixoperator.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkpostfixoperator.o: ../lib/checkpostfixoperator.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checkpostfixoperator.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkpostfixoperator.cpp -$(libcppdir)/checksizeof.o: ../lib/checksizeof.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checksizeof.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checks.o: ../lib/checks.cpp ../lib/check.h ../lib/check64bit.h ../lib/checkassert.h ../lib/checkautovariables.h ../lib/checkbool.h ../lib/checkbufferoverrun.h ../lib/checkclass.h ../lib/checkcondition.h ../lib/checkexceptionsafety.h ../lib/checkfunctions.h ../lib/checkinternal.h ../lib/checkio.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/checkother.h ../lib/checkpostfixoperator.h ../lib/checks.h ../lib/checksizeof.h ../lib/checkstl.h ../lib/checkstring.h ../lib/checktype.h ../lib/checkuninitvar.h ../lib/checkunusedvar.h ../lib/checkvaarg.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/standards.h ../lib/vfvalue.h + $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checks.cpp + +$(libcppdir)/checksizeof.o: ../lib/checksizeof.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checksizeof.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checksizeof.cpp -$(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/checkstl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/pathanalysis.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/checkstl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/pathanalysis.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstl.cpp -$(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkstring.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkstring.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp -$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp -$(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/checkuninitvar.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/checkuninitvar.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkuninitvar.cpp -$(libcppdir)/checkunusedfunctions.o: ../lib/checkunusedfunctions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/astutils.h ../lib/checkers.h ../lib/checkunusedfunctions.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/checkunusedfunctions.o: ../lib/checkunusedfunctions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/astutils.h ../lib/checkers.h ../lib/checkunusedfunctions.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedfunctions.cpp -$(libcppdir)/checkunusedvar.o: ../lib/checkunusedvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkunusedvar.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkunusedvar.o: ../lib/checkunusedvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkunusedvar.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedvar.cpp -$(libcppdir)/checkvaarg.o: ../lib/checkvaarg.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkvaarg.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkvaarg.o: ../lib/checkvaarg.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkvaarg.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp -$(libcppdir)/clangimport.o: ../lib/clangimport.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/clangimport.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/clangimport.o: ../lib/clangimport.cpp ../lib/clangimport.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/clangimport.cpp $(libcppdir)/color.o: ../lib/color.cpp ../lib/color.h ../lib/config.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/color.cpp -$(libcppdir)/cppcheck.o: ../lib/cppcheck.cpp ../externals/picojson/picojson.h ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/check.h ../lib/checkers.h ../lib/checkunusedfunctions.h ../lib/clangimport.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/version.h ../lib/vfvalue.h +$(libcppdir)/cppcheck.o: ../lib/cppcheck.cpp ../externals/picojson/picojson.h ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/check.h ../lib/checkers.h ../lib/checks.h ../lib/checkunusedfunctions.h ../lib/clangimport.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/version.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/cppcheck.cpp $(libcppdir)/ctu.o: ../lib/ctu.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: ../lib/errortypes.cpp ../lib/config.h ../lib/errortypes.h ../lib/utils.h @@ -275,13 +279,13 @@ $(libcppdir)/errortypes.o: ../lib/errortypes.cpp ../lib/config.h ../lib/errortyp $(libcppdir)/findtoken.o: ../lib/findtoken.cpp ../lib/astutils.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/findtoken.cpp -$(libcppdir)/forwardanalyzer.o: ../lib/forwardanalyzer.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/forwardanalyzer.o: ../lib/forwardanalyzer.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/forwardanalyzer.cpp -$(libcppdir)/fwdanalysis.o: ../lib/fwdanalysis.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/fwdanalysis.o: ../lib/fwdanalysis.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp -$(libcppdir)/importproject.o: ../lib/importproject.cpp ../externals/picojson/picojson.h ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/filesettings.h ../lib/importproject.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/importproject.o: ../lib/importproject.cpp ../externals/picojson/picojson.h ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/filesettings.h ../lib/importproject.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp $(libcppdir)/infer.o: ../lib/infer.cpp ../lib/calculate.h ../lib/config.h ../lib/errortypes.h ../lib/infer.h ../lib/mathlib.h ../lib/smallvector.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h @@ -305,58 +309,58 @@ $(libcppdir)/pathanalysis.o: ../lib/pathanalysis.cpp ../lib/astutils.h ../lib/co $(libcppdir)/pathmatch.o: ../lib/pathmatch.cpp ../lib/config.h ../lib/path.h ../lib/pathmatch.h ../lib/standards.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/pathmatch.cpp -$(libcppdir)/platform.o: ../lib/platform.cpp ../externals/tinyxml2/tinyxml2.h ../lib/config.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/standards.h ../lib/xml.h +$(libcppdir)/platform.o: ../lib/platform.cpp ../externals/tinyxml2/tinyxml2.h ../lib/config.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/standards.h ../lib/utils.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/platform.cpp -$(libcppdir)/preprocessor.o: ../lib/preprocessor.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/settings.h ../lib/standards.h ../lib/suppressions.h ../lib/utils.h +$(libcppdir)/preprocessor.o: ../lib/preprocessor.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/regex.h ../lib/settings.h ../lib/standards.h ../lib/suppressions.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/preprocessor.cpp -$(libcppdir)/programmemory.o: ../lib/programmemory.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/programmemory.o: ../lib/programmemory.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/programmemory.cpp $(libcppdir)/regex.o: ../lib/regex.cpp ../lib/config.h ../lib/regex.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/regex.cpp -$(libcppdir)/reverseanalyzer.o: ../lib/reverseanalyzer.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/reverseanalyzer.o: ../lib/reverseanalyzer.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/reverseanalyzer.cpp -$(libcppdir)/sarifreport.o: ../lib/sarifreport.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/sarifreport.h ../lib/settings.h ../lib/standards.h ../lib/utils.h +$(libcppdir)/sarifreport.o: ../lib/sarifreport.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/sarifreport.h ../lib/settings.h ../lib/standards.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/sarifreport.cpp -$(libcppdir)/settings.o: ../lib/settings.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/standards.h ../lib/summaries.h ../lib/suppressions.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/settings.o: ../lib/settings.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/standards.h ../lib/summaries.h ../lib/suppressions.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/settings.cpp $(libcppdir)/standards.o: ../lib/standards.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/standards.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/standards.cpp -$(libcppdir)/summaries.o: ../lib/summaries.cpp ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/summaries.o: ../lib/summaries.cpp ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp -$(libcppdir)/suppressions.o: ../lib/suppressions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/suppressions.o: ../lib/suppressions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp -$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp $(libcppdir)/timer.o: ../lib/timer.cpp ../lib/config.h ../lib/timer.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/timer.cpp -$(libcppdir)/token.o: ../lib/token.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/tokenrange.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/token.o: ../lib/token.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/tokenrange.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/token.cpp -$(libcppdir)/tokenlist.o: ../lib/tokenlist.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/tokenlist.o: ../lib/tokenlist.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenlist.cpp $(libcppdir)/utils.o: ../lib/utils.cpp ../lib/config.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/utils.cpp -$(libcppdir)/vf_analyzers.o: ../lib/vf_analyzers.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/vf_analyzers.o: ../lib/vf_analyzers.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_analyzers.cpp -$(libcppdir)/vf_common.o: ../lib/vf_common.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/vf_common.o: ../lib/vf_common.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_common.cpp -$(libcppdir)/vf_settokenvalue.o: ../lib/vf_settokenvalue.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/vf_settokenvalue.o: ../lib/vf_settokenvalue.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_settokenvalue.cpp $(libcppdir)/vfvalue.o: ../lib/vfvalue.cpp ../lib/config.h ../lib/errortypes.h ../lib/mathlib.h ../lib/smallvector.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h diff --git a/oss-fuzz/main.cpp b/oss-fuzz/main.cpp index 8500bb966cb..e1bd5952966 100644 --- a/oss-fuzz/main.cpp +++ b/oss-fuzz/main.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/platforms/riscv32.xml b/platforms/riscv32.xml new file mode 100644 index 00000000000..1ba1f7e431d --- /dev/null +++ b/platforms/riscv32.xml @@ -0,0 +1,18 @@ + + + 8 + unsigned + + 1 + 2 + 4 + 4 + 8 + 4 + 8 + 16 + 4 + 4 + 4 + + diff --git a/platforms/riscv64.xml b/platforms/riscv64.xml new file mode 100644 index 00000000000..818c2841580 --- /dev/null +++ b/platforms/riscv64.xml @@ -0,0 +1,18 @@ + + + 8 + unsigned + + 1 + 2 + 4 + 8 + 8 + 4 + 8 + 16 + 8 + 8 + 4 + + diff --git a/readme.md b/readme.md index 72f368b3293..512a1ec1110 100644 --- a/readme.md +++ b/readme.md @@ -1,9 +1,10 @@ -# **Cppcheck** +# **Cppcheck** + +NOTE: This repository was recently moved from https://github.com/danmar/cppcheck to https://github.com/cppcheck-opensource/cppcheck. Please make sure to update all your references to it accordingly. |release-windows|OSS-Fuzz|Coverity Scan Build Status|include-what-you-use|License| |:--:|:--:|:--:|:--:|:--:| -|[![release-windows](https://github.com/danmar/cppcheck/actions/workflows/release-windows.yml/badge.svg?branch=main)](https://github.com/danmar/cppcheck/actions/workflows/release-windows.yml)|[![OSS-Fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/cppcheck.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:cppcheck)|[![Coverity Scan Build Status](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512)|[![include-what-you-use](https://github.com/danmar/cppcheck/actions/workflows/iwyu.yml/badge.svg?branch=main)](https://github.com/danmar/cppcheck/actions/workflows/iwyu.yml)|[![License](https://img.shields.io/badge/license-GPL3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0) - +|[![release-windows](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/release-windows.yml/badge.svg?branch=main)](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/release-windows.yml)|[![OSS-Fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/cppcheck.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:cppcheck)|[![Coverity Scan Build Status](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512)|[![include-what-you-use](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/iwyu.yml/badge.svg?branch=main)](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/iwyu.yml)|[![License](https://img.shields.io/badge/license-GPL3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0)| ## About the name @@ -21,7 +22,8 @@ Cppcheck is a hobby project with limited resources. You can help us by donating 1. Download (and extract) Cppcheck source code. 2. Run (Linux/MacOS example): - ``` + + ```shell cd cppcheck/ python3 -m venv .venv source .venv/bin/activate @@ -30,19 +32,20 @@ Cppcheck is a hobby project with limited resources. You can help us by donating ./tools/donate-cpu.py ``` -The script will analyse debian source code and upload the results to a cppcheck server. We need these results both to improve Cppcheck and to detect regressions. +The script will analyse Debian source code and upload the results to a Cppcheck server. We need these results both to improve Cppcheck and to detect regressions. -You can stop the script whenever you like with Ctrl C. +You can stop the script whenever you like with Ctrl+C. ## Compiling -Cppcheck requires a C++ compiler with (partial) C++11 support. Minimum required versions are GCC 5.1 / Clang 3.5 / Visual Studio 2015. +Cppcheck requires a C++ compiler with (partial) C++11 support. Minimum required versions are GCC 5.1 / Clang 3.5 / AppleClang 6.0 / Visual Studio 2015. To build the GUI application, you need to use the CMake build system. When building the command line tool, [PCRE](http://www.pcre.org/) is optional. It is used if you build with rules. There are multiple compilation choices: + * CMake - cross platform build tool * (Windows) Visual Studio * (Windows) Qt Creator + MinGW @@ -52,7 +55,7 @@ The minimum required Python version is 3.7. ### CMake -The minimum required version is CMake 3.13. +The minimum required version is CMake 3.22. Example, compiling Cppcheck with cmake: @@ -62,22 +65,22 @@ cmake --build build ``` If you want to compile the GUI you can use the flag. --DBUILD_GUI=ON +`-DBUILD_GUI=ON` For rules support (requires pcre) use the flag. --DHAVE_RULES=ON +`-DHAVE_RULES=ON` For release builds it is recommended that you use: --DUSE_MATCHCOMPILER=ON +`-DUSE_MATCHCOMPILER=ON` For building the tests use the flag. --DBUILD_TESTS=ON +`-DBUILD_TESTING=ON` -Using cmake you can generate project files for Visual Studio,XCode,etc. +Using CMake you can generate project files for Visual Studio, XCode, etc. #### Building a specific configuration -For single-configuration generators (like "Unix Makefiles") you can generate and build a specific configuration (e.g. "RelWithDebInfo") using: +For single-configuration generators (like "Unix Makefiles") you can generate and build a specific configuration (e.g. "`RelWithDebInfo`") using: ```shell cmake -S . -B build_RelWithDebInfo -DCMAKE_BUILD_TYPE=RelWithDebInfo .. @@ -93,13 +96,13 @@ cmake --build build --config RelWithDebInfo ### Visual Studio -Use the cppcheck.sln file. The file is configured for Visual Studio 2019, but the platform toolset can be changed easily to older or newer versions. The solution contains platform targets for both x86 and x64. +Use the `cppcheck.sln` file. The file is configured for Visual Studio 2019, but the platform toolset can be changed easily to older or newer versions. The solution contains platform targets for both x86 and x64. -To compile with rules, select "Release-PCRE" or "Debug-PCRE" configuration. pcre.lib (pcre64.lib for x64 builds) and pcre.h are expected to be in /externals then. A current version of PCRE for Visual Studio can be obtained using [vcpkg](https://github.com/microsoft/vcpkg). +To compile with rules, select "`Release-PCRE`" or "`Debug-PCRE`" configuration. `pcre.lib` (`pcre64.lib` for x64 builds) and `pcre.h` are expected to be in `/externals` then. A current version of PCRE for Visual Studio can be obtained using [vcpkg](https://github.com/microsoft/vcpkg). ### Visual Studio (from command line) -If you do not wish to use the Visual Studio IDE, you can compile cppcheck from the command line the following command. +If you do not wish to use the Visual Studio IDE, you can compile Cppcheck from the command line the following command. ```shell msbuild cppcheck.sln @@ -107,10 +110,10 @@ msbuild cppcheck.sln ### VS Code (on Windows) -Install MSYS2 to get GNU toolchain with g++ and gdb (https://www.msys2.org/). -Create a settings.json file in the .vscode folder with the following content (adjust path as necessary): +Install MSYS2 to get GNU toolchain with g++ and gdb (). +Create a `settings.json` file in the `.vscode` folder with the following content (adjust path as necessary): -``` +```json { "terminal.integrated.shell.windows": "C:\\msys64\\usr\\bin\\bash.exe", "terminal.integrated.shellArgs.windows": [ @@ -123,11 +126,11 @@ Create a settings.json file in the .vscode folder with the following content (ad } ``` -Run "make" in the terminal to build cppcheck. +Run `make` in the terminal to build Cppcheck. -For debugging create a launch.json file in the .vscode folder with the following content, which covers configuration for debugging cppcheck and misra.py: +For debugging create a `launch.json` file in the `.vscode` folder with the following content, which covers configuration for debugging Cppcheck and `misra.py`: -``` +```json { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. @@ -174,7 +177,7 @@ For debugging create a launch.json file in the .vscode folder with the following ### Qt Creator + MinGW The PCRE dll is needed to build the CLI. It can be downloaded here: -http://software-download.name/pcre-library-windows/ + ### GNU compilers @@ -204,22 +207,22 @@ g++ -o cppcheck -std=c++11 -Iexternals -Iexternals/simplecpp -Iexternals/tinyxml #### Flags -- `MATCHCOMPILER=yes` +* `MATCHCOMPILER=yes` Several `Token` matching patterns are converted into more efficient C++ code at compile time (requires Python to be installed). -- `FILESDIR=/usr/share/cppcheck` - Specifies the folder where cppcheck files (addons, cfg, platform) are installed to. +* `FILESDIR=/usr/share/cppcheck` + Specifies the folder where Cppcheck files (addons, cfg, platform) are installed to. -- `HAVE_RULES=yes` +* `HAVE_RULES=yes` Enables rules (requires PCRE to be installed). -- `CXXOPTS="-O2"` +* `CXXOPTS="-O2"` Enables most compiler optimizations. -- `CPPOPTS="-DNDEBUG"` +* `CPPOPTS="-DNDEBUG"` Disables assertions. -- `HAVE_BOOST=yes` +* `HAVE_BOOST=yes` Enables usage of more efficient container from Boost (requires Boost to be installed). ### MinGW @@ -230,7 +233,7 @@ mingw32-make If you encounter the following error with `MATCHCOMPILER=yes` you need to specify your Python interpreter via `PYTHON_INTERPRETER`. -``` +```text process_begin: CreateProcess(NULL, which python3, ...) failed. makefile:24: pipe: No error process_begin: CreateProcess(NULL, which python, ...) failed. @@ -238,10 +241,10 @@ makefile:27: pipe: No error makefile:30: *** Did not find a Python interpreter. Stop. ``` -### Other Compiler/IDE +### Other compiler/IDE 1. Create an empty project file / makefile. -2. Add all cpp files in the cppcheck cli and lib folders to the project file / makefile. +2. Add all cpp files in the Cppcheck cli and lib folders to the project file / makefile. 3. Add all cpp files in the externals folders to the project file / makefile. 4. Compile. @@ -255,17 +258,17 @@ mv cppcheck cppcheck.exe ## Packages -Besides building yourself on the platform of your choice there are also several ways to obtain pre-built packages.
+Besides building yourself on the platform of your choice there are also several ways to obtain pre-built packages. ### Official Official packages are maintained by the Cppcheck team. -- (Windows) An official Windows installer is available via the official Cppcheck SourceForge page: https://cppcheck.sourceforge.io. -- (Windows) Official builds of the current development versions are available via the [release-windows](https://github.com/danmar/cppcheck/actions/workflows/release-windows.yml) workflow. They are built nightly for the `main` branch and for each commit for release branches. As these are development versions please refrain from using these in production environments! - - A portable package (i.e. does not require installation) is available as the `portable` artifact. This is still a work-in-progress - see https://trac.cppcheck.net/ticket/10771 for details. - - An installer is available via the `installer` artifact. -- (Multi-Platform) A premium version with additional features provided by the original author of Cppcheck is available for purchase via https://www.cppcheck.com. +* (Windows) An official Windows installer is available via the official Cppcheck SourceForge page: . +* (Windows) Official builds of the current development versions are available via the [release-windows](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/release-windows.yml) workflow. They are built nightly for the `main` branch and for each commit for release branches. As these are development versions please refrain from using these in production environments! + * A portable package (i.e. does not require installation) is available as the `portable` artifact. This is still a work-in-progress - see for details. + * An installer is available via the `installer` artifact. +* (Multi-Platform) A premium version with additional features provided by the original author of Cppcheck is available for purchase via . ### Third-party @@ -273,23 +276,23 @@ Third-party packages are ***not*** maintained by the Cppcheck team but their res *Note:* The following list is purely informational and listed in no particular order. -*Note:* Please always try to obtain the package from the primary official source of your operating system/distro first and make sure you are getting the latest released/tagged version (see https://github.com/danmar/cppcheck/tags). Some packages might not carry the latest patch version though. +*Note:* Please always try to obtain the package from the primary official source of your operating system/distro first and make sure you are getting the latest released/tagged version (see ). Some packages might not carry the latest patch version though. *Note:* Some issues might be related to additional patches carried by the builds in these packages or by the packaging itself. Please try to verify the issue with an official build before reporting it upstream. Otherwise you might need toreport it to the respective maintainer of the package. -- (Windows / Outdated) A portable package is available via https://portableapps.com/apps/development/cppcheck-portable. -- (Windows / Outdated) A package is available via https://community.chocolatey.org/packages/cppcheck. -- (Windows / Outdated) A package is available via https://winget.run/pkg/Cppcheck/Cppcheck. -- (Windows) A package is available via https://scoop.sh/#/apps?q=cppcheck. -- (Linux/Unix) Many major distros offer Cppcheck packages via their integrated package managers (`yum`, `apt`, `pacman`, etc.). See https://pkgs.org/search/?q=cppcheck or https://repology.org/project/cppcheck for an overview. -- (Linux/Unix) Unless you are using a "rolling" distro, it is likely that they are not carrying the latest version. There are several external (mainly unsupported) repositories like AUR (ArchLinux), PPA (ubuntu), EPEL (CentOS/Fedora) etc. which might provide up-to-date packages. -- (Linux/Unix / Outdated) The Canonical Snapcraft packages (https://snapcraft.io/cppcheck / https://snapcraft.io/cppcheckgui) are unmaintained and contain very old (development) versions. Please refrain from using them! See https://trac.cppcheck.net/ticket/11641 for more details. -- (MacOS) A package is available via Homebrew (`brew`). See https://formulae.brew.sh/formula/cppcheck. -- (MacOS) A package is available via https://ports.macports.org/port/cppcheck. -- (Multi-Platform) A package is available via https://anaconda.org/conda-forge/cppcheck. -- (Multi-Platform) A package is available via https://conan.io/center/recipes/cppcheck. -- Packages are also available from various download portals (mainly the Windows installer - sometimes re-packaged). +* (Windows / Outdated) A portable package is available via . +* (Windows / Outdated) A package is available via . +* (Windows / Outdated) A package is available via . +* (Windows) A package is available via . +* (Linux/Unix) Many major distros offer Cppcheck packages via their integrated package managers (`yum`, `apt`, `pacman`, etc.). See or for an overview. +* (Linux/Unix) Unless you are using a "rolling" distro, it is likely that they are not carrying the latest version. There are several external (mainly unsupported) repositories like AUR (ArchLinux), PPA (Ubuntu), EPEL (CentOS/Fedora) etc. which might provide up-to-date packages. +* (Linux/Unix / Outdated) The Canonical Snapcraft packages ( / ) are unmaintained and contain very old (development) versions. Please refrain from using them! See for more details. +* (MacOS) A package is available via Homebrew (`brew`). See . +* (MacOS) A package is available via . +* (Multi-Platform) A package is available via . +* (Multi-Platform) A package is available via . +* Packages are also available from various download portals (mainly the Windows installer - sometimes re-packaged). ## Webpage -https://cppcheck.sourceforge.io/ + diff --git a/readmeja.md b/readmeja.md index 6d9dae60c95..7299d61745c 100644 --- a/readmeja.md +++ b/readmeja.md @@ -2,7 +2,7 @@ | Linux ビルド状態 | Windows ビルド状態 | Coverity Scan Build 状態 | |:--:|:--:|:--:| -| [![Linux ビルド状態](https://img.shields.io/travis/danmar/cppcheck/master.svg?label=Linux%20build)](https://travis-ci.org/danmar/cppcheck) | [![Windows ビルド状態](https://img.shields.io/appveyor/ci/danmar/cppcheck/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/danmar/cppcheck/branch/master) | [![Coverity Scan Build 状態](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512) | +| [![Linux ビルド状態](https://img.shields.io/travis/cppcheck-opensource/cppcheck/master.svg?label=Linux%20build)](https://travis-ci.org/cppcheck-opensource/cppcheck) | [![Windows ビルド状態](https://img.shields.io/appveyor/ci/cppcheck-opensource/cppcheck/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/cppcheck-opensource/cppcheck/branch/master) | [![Coverity Scan Build 状態](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512) | ## 名前について diff --git a/releasenotes.txt b/releasenotes.txt index e288b784a2e..5d94da2ebc3 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,11 +1,14 @@ -Release Notes for Cppcheck 2.20 +Release Notes for Cppcheck 2.21 Major bug fixes & crashes: - New checks: -- +- MISRA C 2012 rule 10.3 now warns on assigning integer literals 0 and 1 to bool in C99 and later while preserving the existing C89 behavior. +- funcArgNamesDifferentUnnamed warns on function declarations/definitions where a parameter in either location is unnamed +- uninitMemberVarNoCtor warns on user-defined types where some but not all members requiring initialization have in-class initializers. +- fcloseInLoopCondition warns when fclose() is used as a while loop condition, which may skip the loop body or double-close the file handle. C/C++ support: - @@ -14,12 +17,13 @@ GUI: - Changed interface: -- removed CMake option "DISABLE_CRTDBG_MAP_ALLOC" - Infrastructure & dependencies: - Other: -- The built-in "win*" and "unix*" platforms will now default to signed char type instead of unknown signedness. If you require unsigned chars please specify "--funsigned-char" +- Make it possible to specify the regular expression engine using the `engine` element in a rule XML. +- Added CLI option `--exitcode-suppress` to specify an error ID which should not result in a non-zero exitcode. +- Moved source code from https://github.com/danmar/cppcheck to https://github.com/cppcheck-opensource/cppcheck - diff --git a/samples/unreadVariable/out.txt b/samples/unreadVariable/out.txt index 2b1c295a8c6..1797e13dbbe 100644 --- a/samples/unreadVariable/out.txt +++ b/samples/unreadVariable/out.txt @@ -1,6 +1,3 @@ samples\unreadVariable\bad.cpp:5:34: style: Variable 's2' is assigned a value that is never used. [unreadVariable] std::string s1 = "test1", s2 = "test2"; ^ -samples\unreadVariable\bad.cpp:5:31: style: Variable 's2' is assigned a value that is never used. [unreadVariable] - std::string s1 = "test1", s2 = "test2"; - ^ diff --git a/selfcheck.sh b/selfcheck.sh new file mode 100755 index 00000000000..e9a39ec43cb --- /dev/null +++ b/selfcheck.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +cmake_output=cmake.output +selfcheck_options_extra="$1" + +cppcheck_bin=./cppcheck + +selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude,information --exception-handling --debug-warnings --check-level=exhaustive" +selfcheck_options="$selfcheck_options $selfcheck_options_extra" +cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" +qt_options="--library=qt -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_MOC_HAS_STRINGDATA" # TODO: use 69 as revision +naming_options="--addon-python=$(command -v python) --addon=naming.json" + +mkdir_cmd=$(command -v mkdir) +rm_cmd=$(command -v rm) + +# clear PATH to prevent unintentional process invocations +export PATH= + +ec=0 + +$cppcheck_bin $selfcheck_options \ + externals \ + || ec=1 + +$mkdir_cmd b1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options \ + --cppcheck-build-dir=b1 \ + frontend \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options \ + --cppcheck-build-dir=b1 \ + -Ifrontend \ + cli \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options \ + --cppcheck-build-dir=b1 --enable=internal \ + lib \ + || ec=1 + +$mkdir_cmd b2 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options $qt_options \ + --cppcheck-build-dir=b2 \ + -DQT_CHARTS_LIB \ + -I$cmake_output/gui -Ifrontend -Igui \ + gui/*.cpp $cmake_output/gui \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options \ + -Ifrontend -Icli \ + test/*.cpp \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options \ + -Icli \ + tools/dmake/*.cpp \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $qt_options \ + -I$cmake_output/tools/triage -Igui \ + tools/triage/*.cpp $cmake_output/tools/triage \ + || ec=1 + +$rm_cmd -rf b2 +$rm_cmd -rf b1 + +exit $ec \ No newline at end of file diff --git a/selfcheck_san.sh b/selfcheck_san.sh new file mode 100755 index 00000000000..92e34ba6e4f --- /dev/null +++ b/selfcheck_san.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +cmake_output="$1" +selfcheck_options_extra="$2" + +cppcheck_bin=$cmake_output/bin/cppcheck + +selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude,information --exception-handling --debug-warnings --check-level=exhaustive" +selfcheck_options="$selfcheck_options $selfcheck_options_extra" +cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" +qt_options="--library=qt -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_MOC_HAS_STRINGDATA" +qt_options="$qt_options --suppress=autoNoType:*/moc_*.cpp --suppress=symbolDatabaseWarning:*/moc_*.cpp" +naming_options="--addon-python=$(command -v python) --addon=naming.json" + +# clear PATH to prevent unintentional process invocations +export PATH= + +ec=0 + +$cppcheck_bin $selfcheck_options \ + externals \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options \ + frontend \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options \ + -Ifrontend \ + cli \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options \ + --enable=internal \ + lib \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $naming_options $qt_options \ + --suppress=constVariablePointer:*/moc_*.cpp \ + -DQT_CHARTS_LIB \ + -I$cmake_output/gui -Ifrontend -Igui \ + gui/*.cpp $cmake_output/gui \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options \ + -Ifrontend -Icli \ + test/*.cpp \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options \ + -Icli \ + tools/dmake/*.cpp \ + || ec=1 + +$cppcheck_bin $selfcheck_options $cppcheck_options $qt_options \ + -I$cmake_output/tools/triage -Igui \ + tools/triage/*.cpp $cmake_output/tools/triage \ + || ec=1 + +exit $ec \ No newline at end of file diff --git a/snap/gui/cppcheck-gui.desktop b/snap/gui/cppcheck-gui.desktop deleted file mode 100644 index bd540376da2..00000000000 --- a/snap/gui/cppcheck-gui.desktop +++ /dev/null @@ -1,9 +0,0 @@ -[Desktop Entry] -Type=Application -Name=Cppcheck -Comment=A tool for static C/C++ code analysis -Exec=cppcheck-gui -Icon=${SNAP}/meta/gui/cppcheck-gui.png -Terminal=true -StartupNotify=true -Categories=Development;Debugger;Qt; diff --git a/snap/gui/cppcheck-gui.png b/snap/gui/cppcheck-gui.png deleted file mode 100644 index 25d7aef5f31..00000000000 Binary files a/snap/gui/cppcheck-gui.png and /dev/null differ diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml deleted file mode 100644 index 030a2048afe..00000000000 --- a/snap/snapcraft.yaml +++ /dev/null @@ -1,50 +0,0 @@ -name: cppcheckgui -version: '1.81.99' -summary: A tool for static C/C++ code analysis -description: | - A tool for static C/C++ code analysis -grade: stable -confinement: strict -icon: snap/gui/cppcheck-gui.png -type: app - -apps: - cppcheckgui: - command: desktop-launch ${SNAP}/bin/cppcheck-gui - plugs: [home, unity7, x11, network-bind, network-control] - -parts: - cppcheckgui: - source-type: git - plugin: cmake - configflags: - - -DBUILD_GUI=ON - after: [desktop-qt5] - build-packages: - # A list of Ubuntu packages to be installed on the host to aid in building the part. - # These packages will not go into the final snap. - - build-essential - - qt5-default - - qtbase5-dev - - dpkg-dev - # For Qt5LinguistTools - - qttools5-dev - - qttools5-dev-tools - desktop-qt5: - stage-packages: - # A set of Ubuntu packages to be downloaded and unpacked to join the part before it’s built. - # Note that these packages are not installed on the host. - # Like the rest of the part, all files from these packages will make it into the final snap unless filtered out via the prime keyword. - - libqt5gui5 - - libqt5svg5 # for loading icon themes which are svg - - libtiff5-dev - - libjpeg8-dev - - libxkbcommon0 - - ttf-ubuntu-font-family - - dmz-cursor-theme - - light-themes - - shared-mime-info - - libgdk-pixbuf2.0-0 - - locales-all - - xcb - - libxcb1 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dca02d19194..14f3a8eac17 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -if (BUILD_TESTS) +if (BUILD_TESTING) add_subdirectory(signal) add_subdirectory(seh) @@ -79,7 +79,7 @@ if (BUILD_TESTS) set(oneValueArgs PLATFORM NAME) set(multiValueArgs ADD_LIBRARY) - cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + cmake_parse_arguments(PARSE "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) get_filename_component(LIBRARY ${CFG_TEST} NAME_WE) # TODO: get rid of this if(PARSE_ADD_LIBRARY) diff --git a/test/cfg/gtk.c b/test/cfg/gtk.c index 3e4e5b1cb06..bcee84c8264 100644 --- a/test/cfg/gtk.c +++ b/test/cfg/gtk.c @@ -82,6 +82,10 @@ void validCode(int argInt, GHashTableIter * hash_table_iter, GHashTable * hash_t // cppcheck-suppress valueFlowBailout // TODO: caused by ? printf("%s", str); g_free(str); + + // transfer none functions: return value should not be unreffed + const GApplication *app = g_application_get_default(); + printf("%p\n", app); } void g_malloc_test() diff --git a/test/cfg/libcurl.c b/test/cfg/libcurl.c index 07fd26b031f..f5faadbd0d1 100644 --- a/test/cfg/libcurl.c +++ b/test/cfg/libcurl.c @@ -12,6 +12,16 @@ #include #include +struct S_WriteHeader { + int x; +}; + +size_t cb_WriteHeader(void * /*ptr*/, size_t size, size_t nmemb, void *p) { + // cppcheck-suppress constVariablePointer + struct S_WriteHeader *s = (struct S_WriteHeader *)p; + return s->x ? size * nmemb : 0; +} + void validCode() { CURL *curl = curl_easy_init(); @@ -19,6 +29,9 @@ void validCode() CURLcode res; // cppcheck-suppress valueFlowBailoutIncompleteVar curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, cb_WriteHeader); + struct S_WriteHeader s; + curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &s); // #14692 res = curl_easy_perform(curl); if (res != CURLE_OK) { printf("error"); diff --git a/test/cfg/posix.c b/test/cfg/posix.c index 2e53d171dec..52607fe3a98 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -1312,7 +1312,7 @@ void uninitvar(int fd) pthread_mutex_t mutex, mutex1, mutex2, mutex3; // cppcheck-suppress uninitvar write(x1,"ab",2); - // TODO cppcheck-suppress uninitvar + // cppcheck-suppress uninitvar write(fd,buf,2); // #6325 // cppcheck-suppress uninitvar write(fd,"ab",x2); @@ -1408,7 +1408,7 @@ void timet_h(const struct timespec* ptp1) clock_settime(clk_id2, ptp1); struct timespec tp; - // FIXME cppcheck-suppress uninitvar + // cppcheck-suppress uninitvar clock_settime(CLOCK_REALTIME, &tp); // #6577 - false negative // cppcheck-suppress uninitvar clock_settime(clk_id3, &tp); diff --git a/test/cfg/qt.cpp b/test/cfg/qt.cpp index d508eeef487..78827d3583c 100644 --- a/test/cfg/qt.cpp +++ b/test/cfg/qt.cpp @@ -32,8 +32,9 @@ #include #include #include +#include -// TODO: this is actually avilable via Core5Compat but I could not get it to work with pkg-config +// TODO: this is actually available via Core5Compat but I could not get it to work with pkg-config #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #include #endif @@ -54,6 +55,33 @@ int ignoredReturnValue_QSize_width(const QSize &s) return s.width(); } + +void ignoredReturnValue_QDir(const QString& dirname) +{ + QDir dir(dirname); + + // cppcheck-suppress ignoredReturnValue + dir.exists("abc"); + + // cppcheck-suppress ignoredReturnErrorCode + dir.mkdir("abc"); + + // cppcheck-suppress ignoredReturnValue + dir.count(); + + // cppcheck-suppress ignoredReturnValue + dir.filePath("abc"); + + // cppcheck-suppress ignoredReturnValue + dir.entryList(); +} + +void assertWithSideEffect_QDir_exists(const char *path) { // #14720 + QDir dir(path); + assert(dir.exists()); + (void)dir; +} + void unusedVariable_QTransform() { // cppcheck-suppress unusedVariable @@ -700,6 +728,7 @@ namespace { private: int m_value; }; + // cppcheck-suppress shadowFunction void Counter1::setValue(int value) { if (value != m_value) { m_value = value; @@ -723,6 +752,7 @@ namespace { private: int m_value; }; + // cppcheck-suppress shadowFunction void Counter2::setValue(int value) { if (value != m_value) { m_value = value; diff --git a/test/cfg/std.c b/test/cfg/std.c index adc147c2333..997f8204f73 100644 --- a/test/cfg/std.c +++ b/test/cfg/std.c @@ -7,7 +7,7 @@ // No warnings about bad library configuration, unmatched suppressions, etc. exitcode=0 // -// cppcheck-suppress-file valueFlowBailout +// cppcheck-suppress-file [valueFlowBailout,purgedConfiguration] #include #include @@ -45,7 +45,7 @@ void test_int32_min() { } void test_int64_min() { - // cppcheck-suppress compareValueOutOfTypeRangeError ; tests that INT64_MIN is a signed expression + // TODO cppcheck-suppress knownConditionTrueFalse // #13814 if (INT64_MIN < 0) {} } @@ -287,6 +287,13 @@ char* nullPointer_fgets(char *buffer, int n, FILE *stream) return fgets(buffer, n, stream); } +void nullPointer_fseek(void) { // #10948 + FILE *p = fopen("foo", "r"); + // cppcheck-suppress nullPointerOutOfResources + fseek(p, 1, SEEK_SET); + fclose(p); +} + void memleak_aligned_alloc(void) { // cppcheck-suppress [unusedAllocatedMemory, unreadVariable, constVariablePointer] @@ -3512,6 +3519,13 @@ void invalidFunctionArg_strchr(const char *cs, int c) (void)strchr(cs, 256); } +void constParameterPointer_strchr(char *str) // #14453 +{ + char *sep = strchr(str, ':'); + if (sep) + *sep = '\0'; +} + void invalidFunctionArg_log10(float f, double d, const long double ld) { // cppcheck-suppress invalidFunctionArg diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 8a9976a94ae..0344b98455c 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -586,7 +586,6 @@ void bufferAccessOutOfBounds_std_ofstream_write(std::ofstream &os, const char* s (void)os.write(s,n); } -// cppcheck-suppress constParameterReference // TODO: FP void bufferAccessOutOfBounds_std_ifstream_get(std::ifstream& in, std::streambuf& sb) { char cBuf[10]; @@ -1059,7 +1058,7 @@ void returnValue_std_isgreater(void) { // cppcheck-suppress knownConditionTrueFalse if (std::isgreater(4,2) == 0) {} - // @todo support floats + // cppcheck-suppress knownConditionTrueFalse if (std::isgreater(4.0f,2.0f) == 0) {} } @@ -1067,7 +1066,7 @@ void returnValue_std_isgreaterequal(void) { // cppcheck-suppress knownConditionTrueFalse if (std::isgreaterequal(4,2) == 0) {} - // @todo support floats + // cppcheck-suppress knownConditionTrueFalse if (std::isgreaterequal(4.0f,2.0f) == 0) {} } @@ -1075,7 +1074,7 @@ void returnValue_std_isless(void) { // cppcheck-suppress knownConditionTrueFalse if (std::isless(4,2) == 0) {} - // @todo support floats + // cppcheck-suppress knownConditionTrueFalse if (std::isless(4.0f,2.0f) == 0) {} } @@ -1083,7 +1082,7 @@ void returnValue_std_islessequal(void) { // cppcheck-suppress knownConditionTrueFalse if (std::islessequal(4,2) == 0) {} - // @todo support floats + // cppcheck-suppress knownConditionTrueFalse if (std::islessequal(4.0f,2.0f) == 0) {} } @@ -1094,8 +1093,10 @@ void returnValue_std_islessgreater(void) // cppcheck-suppress knownConditionTrueFalse if (std::islessgreater(2,4) == 0) {} - if (std::islessgreater(4.0f,2.0f) == 0) {} // @todo support floats - if (std::islessgreater(2.0f,4.0f) == 0) {} // @todo support floats + // cppcheck-suppress knownConditionTrueFalse + if (std::islessgreater(4.0f,2.0f) == 0) {} + // cppcheck-suppress knownConditionTrueFalse + if (std::islessgreater(2.0f,4.0f) == 0) {} } void bufferAccessOutOfBounds(void) @@ -5003,7 +5004,7 @@ void beginEnd() //cppcheck-suppress ignoredReturnValue std::crend(v); - // cppcheck-suppress constVariable + // TODO cppcheck-suppress constVariable int arr[4]; //cppcheck-suppress ignoredReturnValue @@ -5025,6 +5026,39 @@ void beginEnd() std::crend(arr); } +struct S_constParameter_std_begin { // #11617 + int a[2]; +}; + +struct T_constParameter_std_begin { + std::vector v; +}; + +struct U_constParameter_std_begin { + std::vector v[1][1]; +}; + +void f(S_constParameter_std_begin& s) { + std::for_each(std::begin(s.a), std::end(s.a), [](int& i) { ++i; }); +} + +void f(T_constParameter_std_begin& t) { + std::for_each(std::begin(t.v), std::end(t.v), [](int& i) { ++i; }); +} + +void f(U_constParameter_std_begin& u) { + std::for_each(std::begin(u.v[0][0]), std::end(u.v[0][0]), [](int& i) { ++i; }); +} + +void g_constVariable_std_begin(int* p) { *p = 0; } + +int f_constVariable_std_begin() { + int arr[1]; + g_constVariable_std_begin(std::begin(arr)); + *std::begin(arr) = 1; + return arr[0]; +} + void smartPtr_get() { std::unique_ptr p; @@ -5166,6 +5200,20 @@ void constVariablePointer_push_back(std::vector& d, const std::vector& s } } +struct S_constVariablePointer_wstring { // #14575 + std::wstring m; + const std::wstring& get() const { return m; } +}; + +S_constVariablePointer_wstring* g_constVariablePointer_wstring(); + +void h_constVariablePointer_wstring(const wchar_t*); + +void f_constVariablePointer_wstring() { + S_constVariablePointer_wstring* s = g_constVariablePointer_wstring(); // cppcheck-suppress constVariablePointer + h_constVariablePointer_wstring(s->get().c_str()); +} + std::streampos constParameterPointer_istream_tellg(std::istream* p) { // #13801 return p->tellg(); } @@ -5318,4 +5366,4 @@ int containerOutOfBounds_std_initializer_list() { // #14340 // cppcheck-suppress derefInvalidIterator int i = *x.end(); return i + containerOutOfBounds_std_initializer_list_access(x); -} \ No newline at end of file +} diff --git a/test/cfg/windows.cpp b/test/cfg/windows.cpp index a07e1b09365..c01e57f6f91 100644 --- a/test/cfg/windows.cpp +++ b/test/cfg/windows.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -92,6 +93,10 @@ std::string constVariable_GetModuleFileName(void) { return std::string{path}; } +const TCHAR* constVariable_MAKEINTRESOURCE() { // #14564 + return MAKEINTRESOURCE(5 - 1); +} + int stringCompare_mbscmp(const unsigned char *string1, const unsigned char *string2) { // cppcheck-suppress stringCompare @@ -1223,3 +1228,13 @@ void SEH_unusedLabel() { // #13233 __finally { } } + +HWND constParameterPointer_CreateWindow(void* param) { // #14560 + return CreateWindow(L"MessageWnd", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, param); +} + +void constParameterPointer_SetupDiGetDeviceInstanceId(HDEVINFO info, SP_DEVINFO_DATA *data) { + const DWORD buffer_size = 256; + TCHAR buffer[buffer_size]; + SetupDiGetDeviceInstanceId(info, data, buffer, buffer_size, NULL); +} diff --git a/test/cfg/wxwidgets.cpp b/test/cfg/wxwidgets.cpp index 983f3e1bbc3..c25dfa8e1b4 100644 --- a/test/cfg/wxwidgets.cpp +++ b/test/cfg/wxwidgets.cpp @@ -972,6 +972,10 @@ void ignoredReturnValue_wxDC_GetSizeMM(const wxDC &dc, wxCoord *width, wxCoord * (void)dc.GetSizeMM(); } +void ignoredReturnValue_wxPanel_Layout(wxPanel* panel) { // #14403 + panel->Layout(); +} + wxSizerItem* invalidFunctionArgBool_wxSizer_Add(wxSizer *sizer, wxWindow * window, const wxSizerFlags &flags) { // No warning is expected for diff --git a/test/cli/fuzz-crash/crash-1c67200986f8cd9788ccf3dbb764d49cb67819b1 b/test/cli/fuzz-crash/crash-1c67200986f8cd9788ccf3dbb764d49cb67819b1 new file mode 100644 index 00000000000..06055955e6b --- /dev/null +++ b/test/cli/fuzz-crash/crash-1c67200986f8cd9788ccf3dbb764d49cb67819b1 @@ -0,0 +1 @@ +e U U,i \ No newline at end of file diff --git a/test/cli/fuzz-crash/crash-41fefbc326c326d02c9e1fe315280ddd326e8a5b b/test/cli/fuzz-crash/crash-41fefbc326c326d02c9e1fe315280ddd326e8a5b new file mode 100644 index 00000000000..b090d2bf345 --- /dev/null +++ b/test/cli/fuzz-crash/crash-41fefbc326c326d02c9e1fe315280ddd326e8a5b @@ -0,0 +1 @@ +#if< \ No newline at end of file diff --git a/test/cli/fuzz-crash/crash-c540e04fe675639b7ead821efc2f5c037b6c89e0 b/test/cli/fuzz-crash/crash-c540e04fe675639b7ead821efc2f5c037b6c89e0 new file mode 100644 index 00000000000..f2fb80ecd28 --- /dev/null +++ b/test/cli/fuzz-crash/crash-c540e04fe675639b7ead821efc2f5c037b6c89e0 @@ -0,0 +1 @@ +o o(){i n;for(i x:v)n=n+<1;} diff --git a/test/cli/fuzz-crash_c/crash-18b7d7437e79f7e1b843b676e0c3beaf4929d043 b/test/cli/fuzz-crash_c/crash-18b7d7437e79f7e1b843b676e0c3beaf4929d043 new file mode 100644 index 00000000000..6a015200e02 --- /dev/null +++ b/test/cli/fuzz-crash_c/crash-18b7d7437e79f7e1b843b676e0c3beaf4929d043 @@ -0,0 +1 @@ +v(){p?1:p..} \ No newline at end of file diff --git a/test/cli/helloworld/helloworld.slnx b/test/cli/helloworld/helloworld.slnx new file mode 100644 index 00000000000..ae14b4c329b --- /dev/null +++ b/test/cli/helloworld/helloworld.slnx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/cli/helloworld/helloworld_slnx.cppcheck b/test/cli/helloworld/helloworld_slnx.cppcheck new file mode 100644 index 00000000000..cf0bff648cc --- /dev/null +++ b/test/cli/helloworld/helloworld_slnx.cppcheck @@ -0,0 +1,6 @@ + + + + helloworld.slnx + false + diff --git a/test/cli/helloworld_test.py b/test/cli/helloworld_test.py index c4ffec69c9c..65c0e4921a0 100644 --- a/test/cli/helloworld_test.py +++ b/test/cli/helloworld_test.py @@ -107,7 +107,7 @@ def test_addon_relative_path(): filename = os.path.join('helloworld', 'main.c') assert ret == 0, stdout assert stdout == ('Checking %s ...\n' - 'Checking %s: SOME_CONFIG...\n' % (filename, filename)) + 'Checking %s: SOME_CONFIG=SOME_CONFIG...\n' % (filename, filename)) assert stderr == ('[%s:5]: (error) Division by zero.\n' '[%s:4]: (style) misra violation (use --rule-texts= to get proper output)\n' % (filename, filename)) @@ -125,7 +125,7 @@ def test_addon_with_gui_project(tmp_path): assert ret == 0, stdout assert stdout.strip().split('\n') == [ 'Checking %s ...' % filename, - 'Checking %s: SOME_CONFIG...' % filename + 'Checking %s: SOME_CONFIG=SOME_CONFIG...' % filename ] assert stderr == ('[%s:5]: (error) Division by zero.\n' '[%s:4]: (style) misra violation (use --rule-texts= to get proper output)\n' % (filename, filename)) @@ -223,11 +223,12 @@ def test_cppcheck_project_local_path_select_one_multiple(): def test_cppcheck_project_local_path_analyze_all(): __test_cppcheck_project_local_path(['--analyze-all-vs-configs'], 'Debug|Win32 Debug|x64 Release|Win32 Release|x64') -def test_cppcheck_project_relative_path(): +@pytest.mark.parametrize("project_file", ["helloworld.cppcheck", "helloworld_slnx.cppcheck"]) +def test_cppcheck_project_relative_path(project_file): args = [ '--template=cppcheck1', '--platform=win64', - '--project=' + os.path.join('helloworld', 'helloworld.cppcheck') + '--project=' + os.path.join('helloworld', project_file) ] ret, stdout, stderr = cppcheck(args, cwd=__script_dir) filename = os.path.join('helloworld', 'main.c') @@ -235,11 +236,12 @@ def test_cppcheck_project_relative_path(): assert __getVsConfigs(stdout, filename) == 'Debug|x64' assert stderr == '[%s:5]: (error) Division by zero.\n' % filename -def test_cppcheck_project_absolute_path(): +@pytest.mark.parametrize("project_file", ["helloworld.cppcheck", "helloworld_slnx.cppcheck"]) +def test_cppcheck_project_absolute_path(project_file): args = [ '--template=cppcheck1', '--platform=win64', - '--project=' + os.path.join(__proj_dir, 'helloworld.cppcheck') + '--project=' + os.path.join(__proj_dir, project_file) ] ret, stdout, stderr = cppcheck(args) filename = os.path.join(__proj_dir, 'main.c') @@ -296,11 +298,12 @@ def test_suppress_project_absolute(tmp_path): assert ret == 0, stdout assert stderr == '' -def test_exclude(): +@pytest.mark.parametrize("project_file", ["helloworld.cppcheck", "helloworld_slnx.cppcheck"]) +def test_exclude(project_file): args = [ '-i' + 'helloworld', '--platform=win64', - '--project=' + os.path.join('helloworld', 'helloworld.cppcheck') + '--project=' + os.path.join('helloworld', project_file) ] ret, stdout, _ = cppcheck(args, cwd=__script_dir) assert ret == 1 @@ -360,7 +363,7 @@ def test_missing_include_system(): # #11283 ] _, _, stderr = cppcheck(args, cwd=__script_dir) - assert stderr.replace('\\', '/') == 'helloworld/main.c:1:2: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n' + assert stderr.replace('\\', '/') == 'helloworld/main.c:1:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n' def test_sarif(): diff --git a/test/cli/inline-suppress-polyspace_test.py b/test/cli/inline-suppress-polyspace_test.py new file mode 100644 index 00000000000..ad7e7df3b55 --- /dev/null +++ b/test/cli/inline-suppress-polyspace_test.py @@ -0,0 +1,63 @@ + +# python -m pytest inline-suppress-polyspace_test.py + +import os +from testutils import assert_cppcheck + +__script_dir = os.path.dirname(os.path.abspath(__file__)) + + +def test_unmatched_polyspace_suppression(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, 'wt') as f: + f.write('int f(void); /* polyspace MISRA2012:8.2 */\n') + + args = ['--addon=misra', '--template=simple', '--enable=style,information', '--inline-suppr', 'test.c'] + + out_exp = ['Checking test.c ...'] + err_exp = ['test.c:1:14: information: Unmatched suppression: misra-c2012-8.2 [unmatchedPolyspaceSuppression]'] + + assert_cppcheck(args, ec_exp=0, err_exp=err_exp, out_exp=out_exp, cwd=str(tmp_path)) + + +def test_1(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, 'wt') as f: + f.write('int f(); /* polyspace MISRA2012:8.2 */\n') + + args = ['--addon=misra', '--template=simple', '--enable=style,information', '--inline-suppr', 'test.c'] + + out_exp = ['Checking test.c ...'] + err_exp = [] + + assert_cppcheck(args, ec_exp=0, err_exp=err_exp, out_exp=out_exp, cwd=str(tmp_path)) + + +def test_block(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, 'wt') as f: + f.write('/* polyspace +1 MISRA2012:8.2 */\n' + 'int f();\n' # <- suppression applies to this line + 'int g();\n') # <- suppression does not apply to this line + + args = ['--addon=misra', '--template=simple', '--enable=style,information', '--inline-suppr', 'test.c'] + + out_exp = ['Checking test.c ...'] + err_exp = ['test.c:3:6: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-8.2]'] + + assert_cppcheck(args, ec_exp=0, err_exp=err_exp, out_exp=out_exp, cwd=str(tmp_path)) + + +def test_begin_end(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, 'wt') as f: + f.write('/* polyspace-begin MISRA2012:8.2 */\n' + 'int f();\n' + '/* polyspace-end MISRA2012:8.2 */\n') + + args = ['--addon=misra', '--template=simple', '--enable=style,information', '--inline-suppr', 'test.c'] + + out_exp = ['Checking test.c ...'] + err_exp = [] + + assert_cppcheck(args, ec_exp=0, err_exp=err_exp, out_exp=out_exp, cwd=str(tmp_path)) diff --git a/test/cli/inline-suppress_test.py b/test/cli/inline-suppress_test.py index 7b8be839df4..ac3dc643485 100644 --- a/test/cli/inline-suppress_test.py +++ b/test/cli/inline-suppress_test.py @@ -82,7 +82,7 @@ def test_unmatched_suppression(): ret, stdout, stderr = cppcheck(args, cwd=__script_dir) lines = stderr.splitlines() assert lines == [ - '{}2.c:2:0: information: Unmatched suppression: some_warning_id [unmatchedSuppression]'.format(__proj_inline_suppres_path) + '{}2.c:2:1: information: Unmatched suppression: some_warning_id [unmatchedSuppression]'.format(__proj_inline_suppres_path) ] assert stdout == '' assert ret == 1, stdout @@ -100,7 +100,7 @@ def test_unmatched_suppression_path_with_extra_stuff(): ret, stdout, stderr = cppcheck(args, cwd=__script_dir) lines = stderr.splitlines() assert lines == [ - '{}2.c:2:0: information: Unmatched suppression: some_warning_id [unmatchedSuppression]'.format(__proj_inline_suppres_path) + '{}2.c:2:1: information: Unmatched suppression: some_warning_id [unmatchedSuppression]'.format(__proj_inline_suppres_path) ] assert stdout == '' assert ret == 1, stdout @@ -431,8 +431,8 @@ def __test_unused_function_unmatched(tmpdir, extra_args): lines = stderr.splitlines() lines.sort() assert lines == [ - '{}unusedFunctionUnmatched.cpp:5:0: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path), - '{}unusedFunctionUnmatched.cpp:5:0: information: Unmatched suppression: unusedFunction [unmatchedSuppression]'.format(__proj_inline_suppres_path) + '{}unusedFunctionUnmatched.cpp:5:1: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path), + '{}unusedFunctionUnmatched.cpp:5:1: information: Unmatched suppression: unusedFunction [unmatchedSuppression]'.format(__proj_inline_suppres_path) ] assert stdout == '' assert ret == 0, stdout @@ -478,7 +478,7 @@ def test_unused_function_disabled_unmatched(): ret, stdout, stderr = cppcheck(args, cwd=__script_dir) assert stderr.splitlines() == [ - '{}unusedFunctionUnmatched.cpp:5:0: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) + '{}unusedFunctionUnmatched.cpp:5:1: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) ] assert stdout == '' assert ret == 0, stdout @@ -496,8 +496,8 @@ def test_unmatched_cfg(): ret, stdout, stderr = cppcheck(args, cwd=__script_dir) assert stderr.splitlines() == [ - '{}cfg.c:5:0: information: Unmatched suppression: id [unmatchedSuppression]'.format(__proj_inline_suppres_path), - '{}cfg.c:9:0: information: Unmatched suppression: id [unmatchedSuppression]'.format(__proj_inline_suppres_path), + '{}cfg.c:5:5: information: Unmatched suppression: id [unmatchedSuppression]'.format(__proj_inline_suppres_path), + '{}cfg.c:9:5: information: Unmatched suppression: id [unmatchedSuppression]'.format(__proj_inline_suppres_path), ] assert stdout == '' assert ret == 0, stdout @@ -518,7 +518,7 @@ def test_unused_function_disabled_unmatched_j(): ret, stdout, stderr = cppcheck(args, cwd=__script_dir) assert stderr.splitlines() == [ - '{}unusedFunctionUnmatched.cpp:5:0: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) + '{}unusedFunctionUnmatched.cpp:5:1: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) ] assert stdout == '' assert ret == 0, stdout @@ -536,7 +536,7 @@ def test_misra_disabled_unmatched(): #14232 ret, stdout, stderr = cppcheck(args, cwd=__script_dir) assert stderr.splitlines() == [ - '{}misraUnmatched.c:5:0: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) + '{}misraUnmatched.c:5:1: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) ] assert stdout == '' assert ret == 0, stdout @@ -554,7 +554,7 @@ def test_premium_disabled_unmatched(): #13663 ret, stdout, stderr = cppcheck(args, cwd=__script_dir) assert stderr.splitlines() == [ - '{}premiumUnmatched.cpp:5:0: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) + '{}premiumUnmatched.cpp:5:1: information: Unmatched suppression: uninitvar [unmatchedSuppression]'.format(__proj_inline_suppres_path) ] assert stdout == '' assert ret == 0, stdout \ No newline at end of file diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index cab96a7f6bb..5ff4f8d7d22 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -205,14 +205,35 @@ def test_lib_lookup_relative_noext_notfound(tmpdir): assert exitcode == 1, stdout if stdout else stderr lines = __remove_std_lookup_log(stdout.splitlines(), exepath) assert lines == [ - "looking for library 'config/gnu.cfg'", - "looking for library '{}/config/gnu.cfg'".format(exepath), - "looking for library '{}/cfg/config/gnu.cfg'".format(exepath), + "looking for library 'config/gnu'", + "looking for library '{}/config/gnu'".format(exepath), + "looking for library '{}/cfg/config/gnu'".format(exepath), "library not found: 'config/gnu'", "cppcheck: Failed to load library configuration file 'config/gnu'. File not found" ] +# TODO: this can never be found - bail out early? +def test_lib_lookup_relative_noext_trailing_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=library', '--library=config/gnu/', test_file]) + exepath = os.path.dirname(exe) + if sys.platform == 'win32': + exepath = exepath.replace('\\', '/') + assert exitcode == 1, stdout if stdout else stderr + lines = __remove_std_lookup_log(stdout.splitlines(), exepath) + assert lines == [ + "looking for library 'config/gnu/'", + "looking for library '{}/config/gnu/'".format(exepath), + "looking for library '{}/cfg/config/gnu/'".format(exepath), + "library not found: 'config/gnu/'", + "cppcheck: Failed to load library configuration file 'config/gnu/'. File not found" + ] + + def test_lib_lookup_absolute(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -258,6 +279,48 @@ def test_lib_lookup_absolute_notfound(tmpdir): ] +def test_lib_lookup_absolute_noext_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + cfg_file = os.path.join(tmpdir, 'test') + + exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=library', '--library={}'.format(cfg_file), test_file]) + exepath = os.path.dirname(exe) + if sys.platform == 'win32': + exepath = exepath.replace('\\', '/') + assert exitcode == 1, stdout + lines = __remove_std_lookup_log(stdout.splitlines(), exepath) + assert lines == [ + "looking for library '{}'".format(cfg_file), + "library not found: '{}'".format(cfg_file), + "cppcheck: Failed to load library configuration file '{}'. File not found".format(cfg_file) + ] + + +# TODO: this can never be found - bail out early? +def test_lib_lookup_absolute_noext_trailing_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + cfg_file = os.path.join(tmpdir, 'test') + cfg_file_trail = cfg_file + os.path.sep + + exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=library', '--library={}'.format(cfg_file_trail), test_file]) + exepath = os.path.dirname(exe) + if sys.platform == 'win32': + exepath = exepath.replace('\\', '/') + assert exitcode == 1, stdout + lines = __remove_std_lookup_log(stdout.splitlines(), exepath) + assert lines == [ + "looking for library '{}'".format(cfg_file_trail), + "library not found: '{}'".format(cfg_file_trail), + "cppcheck: Failed to load library configuration file '{}'. File not found".format(cfg_file_trail) + ] + + def test_lib_lookup_nofile(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -544,14 +607,38 @@ def test_platform_lookup_relative_noext_notfound(tmpdir): lines = stdout.splitlines() assert lines == [ "looking for platform 'platform/none'", - "try to load platform file '{}/platform/none.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platform/none.xml".format(cwd, cwd), - "try to load platform file '{}/platforms/platform/none.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/platform/none.xml".format(cwd, cwd), - "try to load platform file '{}/platform/none.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platform/none.xml".format(exepath, exepath), - "try to load platform file '{}/platforms/platform/none.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/platform/none.xml".format(exepath, exepath), + "try to load platform file '{}/platform/none' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platform/none".format(cwd, cwd), + "try to load platform file '{}/platforms/platform/none' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/platform/none".format(cwd, cwd), + "try to load platform file '{}/platform/none' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platform/none".format(exepath, exepath), + "try to load platform file '{}/platforms/platform/none' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/platform/none".format(exepath, exepath), "cppcheck: error: unrecognized platform: 'platform/none'." ] +# TODO: this can never be found - bail out early? +def test_platform_lookup_relative_noext_trailing_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=platform', '--platform=platform/none/', test_file]) + cwd = os.getcwd() + exepath = os.path.dirname(exe) + if sys.platform == 'win32': + cwd = cwd.replace('\\', '/') + exepath = exepath.replace('\\', '/') + assert exitcode == 1, stdout if stdout else stderr + lines = stdout.splitlines() + assert lines == [ + "looking for platform 'platform/none/'", + "try to load platform file '{}/platform/none/' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platform/none/".format(cwd, cwd), + "try to load platform file '{}/platforms/platform/none/' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/platform/none/".format(cwd, cwd), + "try to load platform file '{}/platform/none/' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platform/none/".format(exepath, exepath), + "try to load platform file '{}/platforms/platform/none/' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/platform/none/".format(exepath, exepath), + "cppcheck: error: unrecognized platform: 'platform/none/'." + ] + + def test_platform_lookup_absolute(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -590,6 +677,42 @@ def test_platform_lookup_absolute_notfound(tmpdir): ] +def test_platform_lookup_absolute_noext_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + platform_file = os.path.join(tmpdir, 'test') + + exitcode, stdout, stderr = cppcheck(['--debug-lookup=platform', '--platform={}'.format(platform_file), test_file]) + assert exitcode == 1, stdout if stdout else stderr + lines = stdout.splitlines() + assert lines == [ + "looking for platform '{}'".format(platform_file), + "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(platform_file, platform_file), + "cppcheck: error: unrecognized platform: '{}'.".format(platform_file) + ] + + +# TODO: this can never be found - bail out early? +def test_platform_lookup_absolute_noext_trailing_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + platform_file = os.path.join(tmpdir, 'test') + platform_file_trail = platform_file + os.path.sep + + exitcode, stdout, stderr = cppcheck(['--debug-lookup=platform', '--platform={}'.format(platform_file_trail), test_file]) + assert exitcode == 1, stdout if stdout else stderr + lines = stdout.splitlines() + assert lines == [ + "looking for platform '{}'".format(platform_file_trail), + "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(platform_file_trail, platform_file_trail), + "cppcheck: error: unrecognized platform: '{}'.".format(platform_file_trail) + ] + + @pytest.mark.skip # TODO: fails when not run from the root folder def test_platform_lookup_nofile(tmpdir): test_file = os.path.join(tmpdir, 'test.c') @@ -644,12 +767,14 @@ def test_addon_lookup(tmpdir): exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=misra', test_file]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 0, stdout if stdout else stderr lines = stdout.splitlines() assert lines == [ "looking for addon 'misra.py'", "looking for addon '{}misra.py'".format(exepath_sep), - "looking for addon '{}addons/misra.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/misra.py'".format(exepath_sep), 'Checking {} ...'.format(test_file) ] @@ -662,12 +787,14 @@ def test_addon_lookup_ext(tmpdir): exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=misra.py', test_file]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 0, stdout if stdout else stderr lines = stdout.splitlines() assert lines == [ "looking for addon 'misra.py'", "looking for addon '{}misra.py'".format(exepath_sep), - "looking for addon '{}addons/misra.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/misra.py'".format(exepath_sep), 'Checking {} ...'.format(test_file) ] @@ -680,12 +807,14 @@ def test_addon_lookup_notfound(tmpdir): exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=none', test_file]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 1, stdout lines = stdout.splitlines() assert lines == [ "looking for addon 'none.py'", "looking for addon '{}none.py'".format(exepath_sep), - "looking for addon '{}addons/none.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/none.py'".format(exepath_sep), 'Did not find addon none.py' ] @@ -696,13 +825,15 @@ def test_addon_lookup_notfound_project(tmpdir): # #13940 / #13941 exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=none', '--project={}'.format(project_file)]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 1, stdout lines = stdout.splitlines() assert lines == [ # TODO: needs to look relative to the project file first "looking for addon 'none.py'", "looking for addon '{}none.py'".format(exepath_sep), - "looking for addon '{}addons/none.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/none.py'".format(exepath_sep), 'Did not find addon none.py' ] @@ -713,12 +844,14 @@ def test_addon_lookup_notfound_compdb(tmpdir): exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=none', '--project={}'.format(compdb_file)]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 1, stdout lines = stdout.splitlines() assert lines == [ "looking for addon 'none.py'", "looking for addon '{}none.py'".format(exepath_sep), - "looking for addon '{}addons/none.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/none.py'".format(exepath_sep), 'Did not find addon none.py' ] @@ -731,12 +864,14 @@ def test_addon_lookup_ext_notfound(tmpdir): exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=none.py', test_file]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 1, stdout lines = stdout.splitlines() assert lines == [ "looking for addon 'none.py'", "looking for addon '{}none.py'".format(exepath_sep), - "looking for addon '{}addons/none.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/none.py'".format(exepath_sep), 'Did not find addon none.py' ] @@ -749,16 +884,19 @@ def test_addon_lookup_relative_notfound(tmpdir): exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=addon/misra.py', test_file]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 1, stdout lines = stdout.splitlines() assert lines == [ "looking for addon 'addon/misra.py'", "looking for addon '{}addon/misra.py'".format(exepath_sep), - "looking for addon '{}addons/addon/misra.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/addon/misra.py'".format(exepath_sep), 'Did not find addon addon/misra.py' ] +# FIXME: an addon requires a file extension as we need to differentiate between .py and .json addons def test_addon_lookup_relative_noext_notfound(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -767,16 +905,40 @@ def test_addon_lookup_relative_noext_notfound(tmpdir): exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=addon/misra', test_file]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 1, stdout lines = stdout.splitlines() assert lines == [ "looking for addon 'addon/misra.py'", "looking for addon '{}addon/misra.py'".format(exepath_sep), - "looking for addon '{}addons/addon/misra.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/addon/misra.py'".format(exepath_sep), 'Did not find addon addon/misra.py' ] +# TODO: this can never be found - bail out early? +def test_addon_lookup_relative_noext_trailing_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + exitcode, stdout, _, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=addon/misra/', test_file]) + exepath = os.path.dirname(exe) + exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') + assert exitcode == 1, stdout + lines = stdout.splitlines() + assert lines == [ + # TODO: should not append extension + "looking for addon 'addon/misra/.py'", + "looking for addon '{}addon/misra/.py'".format(exepath_sep), + "looking for addon '{}addons/addon/misra/.py'".format(exepath_sep), + 'Did not find addon addon/misra/.py' + ] + + def test_addon_lookup_absolute(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -811,6 +973,43 @@ def test_addon_lookup_absolute_notfound(tmpdir): ] +# FIXME: an addon requires a file extension as we need to differentiate between .py and .json addons +def test_addon_lookup_absolute_noext_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + addon_file = os.path.join(tmpdir, 'test') + addon_file_py = os.path.join(tmpdir, 'test.py') # TODO: do not add extension + + exitcode, stdout, stderr = cppcheck(['--debug-lookup=addon', '--addon={}'.format(addon_file), test_file]) + assert exitcode == 1, stdout if stdout else stderr + lines = stdout.splitlines() + assert lines == [ + "looking for addon '{}'".format(addon_file_py), + 'Did not find addon {}'.format(addon_file_py) + ] + + +# TODO: this can never be found - bail out early? +def test_addon_lookup_absolute_noext_trailing_notfound(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + addon_file = os.path.join(tmpdir, 'test') + addon_file_trail = addon_file + os.path.sep + addon_file_trail_py = addon_file_trail + '.py' # TODO: do not add extension + + exitcode, stdout, stderr = cppcheck(['--debug-lookup=addon', '--addon={}'.format(addon_file_trail), test_file]) + assert exitcode == 1, stdout if stdout else stderr + lines = stdout.splitlines() + assert lines == [ + "looking for addon '{}'".format(addon_file_trail_py), + 'Did not find addon {}'.format(addon_file_trail_py) + ] + + def test_addon_lookup_nofile(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -825,12 +1024,14 @@ def test_addon_lookup_nofile(tmpdir): exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=addon', '--addon=misra', test_file]) exepath = os.path.dirname(exe) exepath_sep = exepath + os.path.sep + if sys.platform == 'win32': + exepath_sep = exepath_sep.replace('\\', '/') assert exitcode == 0, stdout if stdout else stderr lines = stdout.splitlines() assert lines == [ "looking for addon 'misra.py'", "looking for addon '{}misra.py'".format(exepath_sep), - "looking for addon '{}addons/misra.py'".format(exepath_sep), # TODO: mixed separators + "looking for addon '{}addons/misra.py'".format(exepath_sep), 'Checking {} ...'.format(test_file) ] diff --git a/test/cli/more-projects_test.py b/test/cli/more-projects_test.py index 03dc00ed0f3..504a2b14431 100644 --- a/test/cli/more-projects_test.py +++ b/test/cli/more-projects_test.py @@ -258,7 +258,7 @@ def test_project_std(tmpdir): -@pytest.mark.skip() # clang-tidy is not available in all cases +@pytest.mark.skip() # clang-tidy is not available in all cases - TODO: enable conditionally def test_clang_tidy(tmpdir): test_file = os.path.join(tmpdir, 'test.cpp') with open(test_file, 'wt') as f: @@ -657,7 +657,7 @@ def test_project_file_duplicate_2(tmpdir): assert stderr == '' -def test_project_file_duplicate_3(tmpdir): +def test_project_file_duplicate_3(tmpdir): # #12834 test_file_a = os.path.join(tmpdir, 'a.c') with open(test_file_a, 'wt'): pass @@ -687,33 +687,18 @@ def test_project_file_duplicate_3(tmpdir): """.format(in_file_a, in_file_b, in_file_c, in_file_d, in_file_e, in_file_f, tmpdir)) args = ['--project={}'.format(project_file)] - args.append('-j1') # TODO: remove when fixed exitcode, stdout, stderr = cppcheck(args, cwd=tmpdir) assert exitcode == 0 lines = stdout.splitlines() - # TODO: only a single file should be checked - if sys.platform == 'win32': - assert lines == [ - 'Checking {} ...'.format(test_file_a), - '1/3 files checked 33% done', - 'Checking {} ...'.format(test_file_a), - '2/3 files checked 66% done', - 'Checking {} ...'.format(test_file_a), - '3/3 files checked 100% done' - ] - else: - assert lines == [ - 'Checking {} ...'.format(test_file_a), - '1/2 files checked 50% done', - 'Checking {} ...'.format(test_file_a), - '2/2 files checked 100% done' - ] + assert lines == [ + 'Checking {} ...'.format(test_file_a) + ] assert stderr == '' @pytest.mark.skipif(sys.platform != 'win32', reason="requires Windows") -def test_project_file_duplicate_4(tmpdir): +def test_project_file_duplicate_4(tmpdir): # #12834 test_file_a = os.path.join(tmpdir, 'a.c') with open(test_file_a, 'wt'): pass @@ -756,19 +741,12 @@ def test_project_file_duplicate_4(tmpdir): args2[0], args2[1], args2[2], args2[3], args2[4], args2[5], args2[6])) args = ['--project={}'.format(project_file)] - args.append('-j1') # TODO: remove when fixed exitcode, stdout, stderr = cppcheck(args, cwd=tmpdir) assert exitcode == 0 lines = stdout.splitlines() - # TODO: only a single file should be checked assert lines == [ - 'Checking {} ...'.format(test_file_a), - '1/3 files checked 33% done', - 'Checking {} ...'.format(test_file_a), - '2/3 files checked 66% done', - 'Checking {} ...'.format(test_file_a), - '3/3 files checked 100% done' + 'Checking {} ...'.format(test_file_a) ] assert stderr == '' diff --git a/test/cli/other_test.py b/test/cli/other_test.py index c4ae2fab5cf..243f600b5a6 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -9,10 +9,18 @@ import subprocess import shutil -from testutils import cppcheck, assert_cppcheck, cppcheck_ex, __lookup_cppcheck_exe +from testutils import cppcheck, assert_cppcheck, cppcheck_ex, __lookup_cppcheck_exe, create_compile_commands from xml.etree import ElementTree +try: + # TODO: handle exitcode? + subprocess.call(['clang-tidy', '--version']) + __has_clang_tidy = True +except OSError: + __has_clang_tidy = False + + def __remove_verbose_log(l : list): l.remove('Defines:') l.remove('Undefines:') @@ -169,9 +177,67 @@ def test_progress(tmpdir): "progress: Tokenize (typedef) 62%\n" "progress: Tokenize (typedef) 75%\n" "progress: Tokenize (typedef) 87%\n" - "progress: SymbolDatabase 0%\n" - "progress: SymbolDatabase 12%\n" - "progress: SymbolDatabase 87%\n" + "progress: Tokenize (typedef) 100%\n" + "progress: SymbolDatabase (find all scopes) 0%\n" + "progress: SymbolDatabase (find all scopes) 12%\n" + "progress: SymbolDatabase (find all scopes) 87%\n" + "progress: SymbolDatabase (find all scopes) 100%\n" + "progress: ValueFlow 0%\n" + "progress: ValueFlow::valueFlowImpossibleValues(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowImpossibleValues(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSymbolicOperators(symboldatabase, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSymbolicOperators(symboldatabase, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowSymbolicInfer(symboldatabase, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSymbolicInfer(symboldatabase, settings) 1 100%\n" + "progress: ValueFlow::valueFlowArrayBool(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowArrayBool(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowArrayElement(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowArrayElement(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowRightShift(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowRightShift(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowInferCondition(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowInferCondition(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowFunctionReturn(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowFunctionReturn(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowLifetime(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowLifetime(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowUninit(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowUninit(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSmartPointer(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSmartPointer(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowIterators(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowIterators(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowIteratorInfer(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowIteratorInfer(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowSafeFunctions(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSafeFunctions(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow 100%\n" + "progress: Run checkers 0%\n" + "progress: Run checkers 100%\n" ) assert stderr == "" @@ -362,7 +428,7 @@ def test_addon_misra(tmpdir): assert lines == [ 'Checking {} ...'.format(test_file) ] - assert stderr == '{}:2:1: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]\ntypedef int MISRA_5_6_VIOLATION;\n^\n'.format(test_file) + assert stderr == '{}:2:13: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]\ntypedef int MISRA_5_6_VIOLATION;\n ^\n'.format(test_file) def test_addon_y2038(tmpdir): @@ -730,7 +796,7 @@ def test_addon_misc(tmpdir): f.write(""" extern void f() { - char char* [] = {"a" "b"} + const char* c[] = {"a" "b"}; } """) @@ -742,7 +808,7 @@ def test_addon_misc(tmpdir): assert lines == [ 'Checking {} ...'.format(test_file) ] - assert stderr == '{}:4:26: style: String concatenation in array initialization, missing comma? [misc-stringConcatInArrayInit]\n'.format(test_file) + assert stderr == '{}:4:28: style: String concatenation in array initialization, missing comma? [misc-stringConcatInArrayInit]\n'.format(test_file) def test_invalid_addon_json(tmpdir): @@ -896,30 +962,197 @@ def test_unused_function_include(tmpdir): __test_unused_function_include(tmpdir, []) -# TODO: test with all other types -def test_showtime_top5_file(tmpdir): - test_file = os.path.join(tmpdir, 'test.cpp') +# TODO: test with multiple files +def __test_showtime(tmp_path, showtime, exp_res, exp_last, use_compdb=False, use_addons=False, use_clang_tidy=False, extra_args=None): + test_file = tmp_path / 'test.cpp' # the use of C++ is intentional with open(test_file, 'wt') as f: - f.write(""" - int main(int argc) - { - } - """) + f.write( +""" +void f() +{ + (void)(*((int*)0)); // cppcheck-suppress nullPointer +} +""") + + args = [ + f'--showtime={showtime}', + '--quiet', + '--inline-suppr' + ] + + if use_addons: + args += ['--addon=misra', '--addon=misc'] + + if use_clang_tidy: + args += ['--clang-tidy'] + args += ['--suppress=clang-tidy-misc-use-internal-linkage'] + args += ['--suppress=clang-tidy-google-readability-casting'] + args += ['--suppress=clang-tidy-modernize-avoid-c-style-cast'] + args += ['--suppress=clang-tidy-hicpp-use-nullptr'] + args += ['--suppress=clang-tidy-modernize-use-nullptr'] - args = ['--showtime=top5_file', '--quiet', test_file] + if use_compdb: + compdb_file = tmp_path / 'compile_commands.json' + create_compile_commands(compdb_file, [test_file]) + + args.append(f'--project={compdb_file}') + else: + args.append(str(test_file)) + + if extra_args: + args += extra_args exitcode, stdout, stderr = cppcheck(args) - assert exitcode == 0 # TODO: needs to be 1 + assert exitcode == 0 lines = stdout.splitlines() - assert len(lines) == 7 - assert lines[0] == '' - for i in range(1, 5): - if lines[i].startswith('valueFlowLifetime'): - assert lines[i].endswith(' - 2 result(s))') - elif lines[i].startswith('valueFlowEnumValue'): - assert lines[i].endswith(' - 2 result(s))') - else: - assert lines[i].endswith(' result(s))') + exp_len = exp_res + if 'cppcheck internal API usage' in stdout: + exp_len += 1 + if use_addons: + exp_len += 1 # TODO: should have individual entries for each addon and whole program analysis + # TODO: add entry for clang-tidy analysis + exp_len += 1 # last line + assert len(lines) == exp_len + for i in range(1, exp_res): + assert 'avg.' in lines[i] + assert lines[exp_len-1].startswith(exp_last) + assert not 'avg.' in lines[exp_len-1] + assert stderr == '' + + +def __test_showtime_top5_file(tmp_path, use_compdb=False): + __test_showtime(tmp_path, 'top5_file', 5, 'Check time: ', use_compdb=use_compdb) + + +def test_showtime_top5_file(tmp_path): + __test_showtime_top5_file(tmp_path) + + +def test_showtime_top5_file_compdb(tmp_path): + __test_showtime_top5_file(tmp_path, use_compdb=True) + + +def __test_showtime_top5_summary(tmp_path, use_compdb=False): + __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', use_compdb=use_compdb) + + +def test_showtime_top5_summary(tmp_path): + __test_showtime_top5_summary(tmp_path) + + +def test_showtime_top5_summary_compdb(tmp_path): + __test_showtime_top5_summary(tmp_path, use_compdb=True) + + +def __test_showtime_file(tmp_path, use_compdb=False, use_addons=False, use_clang_tidy=False): + exp_res = 79 + # project analysis does not call Preprocessor::getConfig() + if use_compdb: + exp_res -= 1 + __test_showtime(tmp_path, 'file', exp_res, 'Check time: ', use_compdb=use_compdb, use_addons=use_addons, use_clang_tidy=use_clang_tidy) + + +def test_showtime_file(tmp_path): + __test_showtime_file(tmp_path) + + +def test_showtime_file_compdb(tmp_path): + __test_showtime_file(tmp_path, use_compdb=True) + + +def test_showtime_file_addon(tmp_path): + __test_showtime_file(tmp_path, use_addons=True) + + +def test_showtime_file_addon_compdb(tmp_path): + __test_showtime_file(tmp_path, use_addons=True, use_compdb=True) + + +@pytest.mark.skipif(not __has_clang_tidy, reason='clang-tidy is not available') +def test_showtime_file_clang_tidy(tmp_path): + __test_showtime_file(tmp_path, use_clang_tidy=True) + + +@pytest.mark.skipif(not __has_clang_tidy, reason='clang-tidy is not available') +def test_showtime_file_clang_tidy_compdb(tmp_path): + __test_showtime_file(tmp_path, use_clang_tidy=True, use_compdb=True) + + +def __test_showtime_summary(tmp_path, use_compdb=False, use_addons=False, use_clang_tidy=False): + exp_res = 79 + # project analysis does not call Preprocessor::getConfig() + if use_compdb: + exp_res -= 1 + __test_showtime(tmp_path, 'summary', exp_res, 'Overall time: ', use_compdb=use_compdb, use_addons=use_addons, use_clang_tidy=use_clang_tidy) + + +def test_showtime_summary(tmp_path): + __test_showtime_summary(tmp_path) + + +def test_showtime_summary_compdb(tmp_path): + __test_showtime_summary(tmp_path, use_compdb=True) + + +def test_showtime_summary_addon(tmp_path): + __test_showtime_summary(tmp_path, use_addons=True) + + +def test_showtime_summary_addon_compdb(tmp_path): + __test_showtime_summary(tmp_path, use_addons=True, use_compdb=True) + + +@pytest.mark.skipif(not __has_clang_tidy, reason='clang-tidy is not available') +def test_showtime_summary_clang_tidy(tmp_path): + __test_showtime_summary(tmp_path, use_clang_tidy=True) + + +@pytest.mark.skipif(not __has_clang_tidy, reason='clang-tidy is not available') +def test_showtime_summary_clang_tidy_compdb(tmp_path): + __test_showtime_summary(tmp_path, use_clang_tidy=True, use_compdb=True) + + +def __test_showtime_file_total(tmp_path, use_compdb=False): + __test_showtime(tmp_path, 'file-total', 0, 'Check time: ', use_compdb=use_compdb) + + +def test_showtime_file_total(tmp_path): + __test_showtime_file_total(tmp_path) + + +def test_showtime_file_total_compdb(tmp_path): + __test_showtime_file_total(tmp_path, True) + + +def test_showtime_unique(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt') as f: + f.write( +""" +void f() +{ + (void)(*((int*)0)); // cppcheck-suppress nullPointer +} +""") + + args = [ + '--showtime=summary', + '--quiet', + '--inline-suppr', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + multi_res = [] + for line in stdout.splitlines(): + # TODO: remove when we no longer emit empty line + if not line: + continue + if any(i in line for i in ['1 result(s)', 'Overall time:']): + continue + multi_res.append(line) + assert multi_res == [] assert stderr == '' @@ -1216,7 +1449,7 @@ def test_file_duplicate_2(tmpdir): assert stderr == '' -def test_file_duplicate_3(tmpdir): +def test_file_duplicate_3(tmpdir): # #12834 test_file_a = os.path.join(tmpdir, 'a.c') with open(test_file_a, 'wt'): pass @@ -1230,43 +1463,18 @@ def test_file_duplicate_3(tmpdir): in_file_f = os.path.join(tmpdir, 'dummy', '..', 'a.c') args = [in_file_a, in_file_b, in_file_c, in_file_d, in_file_e, in_file_f, str(tmpdir)] - args.append('-j1') # TODO: remove when fixed exitcode, stdout, stderr = cppcheck(args, cwd=tmpdir) assert exitcode == 0, stdout if stdout else stderr lines = stdout.splitlines() - # TODO: only a single file should be checked - if sys.platform == 'win32': - assert lines == [ - 'Checking {} ...'.format('a.c'), - '1/6 files checked 16% done', - 'Checking {} ...'.format('a.c'), - '2/6 files checked 33% done', - 'Checking {} ...'.format('a.c'), - '3/6 files checked 50% done', - 'Checking {} ...'.format(test_file_a), - '4/6 files checked 66% done', - 'Checking {} ...'.format(test_file_a), - '5/6 files checked 83% done', - 'Checking {} ...'.format(test_file_a), - '6/6 files checked 100% done' - ] - else: - assert lines == [ - 'Checking {} ...'.format('a.c'), - '1/4 files checked 25% done', - 'Checking {} ...'.format('a.c'), - '2/4 files checked 50% done', - 'Checking {} ...'.format(test_file_a), - '3/4 files checked 75% done', - 'Checking {} ...'.format(test_file_a), - '4/4 files checked 100% done' - ] + assert lines == [ + 'Checking {} ...'.format('a.c') + ] assert stderr == '' @pytest.mark.skipif(sys.platform != 'win32', reason="requires Windows") -def test_file_duplicate_4(tmpdir): +def test_file_duplicate_4(tmpdir): # #12834 test_file_a = os.path.join(tmpdir, 'a.c') with open(test_file_a, 'wt'): pass @@ -1284,25 +1492,12 @@ def test_file_duplicate_4(tmpdir): for a in args1: args2.append(a.replace('\\', '/')) args = args1 + args2 - args.append('-j1') # TODO: remove when fixed exitcode, stdout, stderr = cppcheck(args, cwd=tmpdir) assert exitcode == 0, stdout if stdout else stderr lines = stdout.splitlines() - # TODO: only a single file should be checked assert lines == [ - 'Checking {} ...'.format('a.c'), - '1/6 files checked 16% done', - 'Checking {} ...'.format('a.c'), - '2/6 files checked 33% done', - 'Checking {} ...'.format('a.c'), - '3/6 files checked 50% done', - 'Checking {} ...'.format(test_file_a), - '4/6 files checked 66% done', - 'Checking {} ...'.format(test_file_a), - '5/6 files checked 83% done', - 'Checking {} ...'.format(test_file_a), - '6/6 files checked 100% done' + 'Checking {} ...'.format('a.c') ] assert stderr == '' @@ -2335,7 +2530,7 @@ def __test_inline_suppr(tmp_path, extra_args): # #13087 assert exitcode == 0, stdout assert stdout == '' assert stderr.splitlines() == [ - '{}:4:0: information: Unmatched suppression: memleak [unmatchedSuppression]'.format(test_file) + '{}:4:1: information: Unmatched suppression: memleak [unmatchedSuppression]'.format(test_file) ] @@ -2353,8 +2548,6 @@ def test_inline_suppr_builddir(tmp_path): __test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j1']) -# TODO: the suppressions are generated outside of the scope which captures the analysis information -@pytest.mark.xfail(strict=True) def test_inline_suppr_builddir_cached(tmp_path): build_dir = tmp_path / 'b1' os.mkdir(build_dir) @@ -2368,8 +2561,6 @@ def test_inline_suppr_builddir_j(tmp_path): __test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j2']) -# TODO: the suppressions are generated outside of the scope which captures the analysis information -@pytest.mark.xfail(strict=True) def test_inline_suppr_builddir_j_cached(tmp_path): build_dir = tmp_path / 'b1' os.mkdir(build_dir) @@ -2567,7 +2758,7 @@ def __test_addon_suppr(tmp_path, extra_args): assert exitcode == 0, stdout assert stdout == '' assert stderr.splitlines() == [ - '{}:4:1: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]'.format(test_file), + '{}:4:13: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]'.format(test_file), ] @@ -3238,13 +3429,6 @@ def test_check_unused_templates_func(tmp_path): # #13714 assert stdout.splitlines() == [] assert stderr.splitlines() == [] # no error since the unused templates are not being checked -try: - # TODO: handle exitcode? - subprocess.call(['clang-tidy', '--version']) - has_clang_tidy = True -except OSError: - has_clang_tidy = False - def __test_clang_tidy(tmpdir, use_compdb): test_file = os.path.join(tmpdir, 'test.cpp') with open(test_file, 'wt') as f: @@ -3275,18 +3459,18 @@ def __test_clang_tidy(tmpdir, use_compdb): ] -@pytest.mark.skipif(not has_clang_tidy, reason='clang-tidy is not available') +@pytest.mark.skipif(not __has_clang_tidy, reason='clang-tidy is not available') @pytest.mark.xfail(strict=True) # TODO: clang-tidy is only invoked with FileSettings - see #12053 def test_clang_tidy(tmpdir): # #12053 __test_clang_tidy(tmpdir, False) -@pytest.mark.skipif(not has_clang_tidy, reason='clang-tidy is not available') +@pytest.mark.skipif(not __has_clang_tidy, reason='clang-tidy is not available') def test_clang_tidy_project(tmpdir): __test_clang_tidy(tmpdir, True) -@pytest.mark.skipif(not has_clang_tidy, reason='clang-tidy is not available') +@pytest.mark.skipif(not __has_clang_tidy, reason='clang-tidy is not available') def test_clang_tidy_error_exit(tmp_path): # #13828 / #13829 test_file = tmp_path / 'test.cpp' with open(test_file, 'wt') as f: @@ -3351,14 +3535,49 @@ def test_suppress_unmatched_wildcard(tmp_path): # #13660 exitcode, stdout, stderr = cppcheck(args, cwd=tmp_path) assert exitcode == 0, stdout assert stdout.splitlines() == [] - # TODO: invalid locations - see #13659 assert stderr.splitlines() == [ - 'test*.c:-1:0: information: Unmatched suppression: id [unmatchedSuppression]', - 'test*.c:-1:0: information: Unmatched suppression: id2 [unmatchedSuppression]', - 'tes?.c:-1:0: information: Unmatched suppression: id2 [unmatchedSuppression]' + 'test*.c:0:0: information: Unmatched suppression: id [unmatchedSuppression]', + 'test*.c:0:0: information: Unmatched suppression: id2 [unmatchedSuppression]', + 'tes?.c:0:0: information: Unmatched suppression: id2 [unmatchedSuppression]' ] +def test_suppress_unmatched_wildcard_cached(tmp_path): # #14585 + test_file = tmp_path / 'test.c' + with open(test_file, 'wt') as f: + f.write( +"""void f() +{ + (void)(*((int*)0)); +} +""") + + build_dir = tmp_path / 'b1' + os.makedirs(build_dir) + + # need to run in the temporary folder because the path of the suppression has to match + args = [ + '-q', + '--template=simple', + '--enable=information', + '--cppcheck-build-dir={}'.format(build_dir), + '--suppress=nullPointer:test*.c', + 'test.c' + ] + + stderr_exp = [] + + exitcode, stdout, stderr = cppcheck(args, cwd=tmp_path) + assert exitcode == 0, stdout + assert stdout.splitlines() == [] + assert stderr.splitlines() == stderr_exp + + exitcode, stdout, stderr = cppcheck(args, cwd=tmp_path) + assert exitcode == 0, stdout + assert stdout.splitlines() == [] + assert stderr.splitlines() == stderr_exp + + def test_suppress_unmatched_wildcard_unchecked(tmp_path): # make sure that unmatched wildcards suppressions are reported if files matching the expressions were processesd # but isSuppressed() has never been called (i.e. no findings in file at all) @@ -3380,12 +3599,11 @@ def test_suppress_unmatched_wildcard_unchecked(tmp_path): exitcode, stdout, stderr = cppcheck(args, cwd=tmp_path) assert exitcode == 0, stdout assert stdout.splitlines() == [] - # TODO: invalid locations - see #13659 assert stderr.splitlines() == [ - 'test*.c:-1:0: information: Unmatched suppression: id [unmatchedSuppression]', - 'tes?.c:-1:0: information: Unmatched suppression: id [unmatchedSuppression]', - '*:-1:0: information: Unmatched suppression: id2 [unmatchedSuppression]', - 'test*.c:-1:0: information: Unmatched suppression: * [unmatchedSuppression]' + 'test*.c:0:0: information: Unmatched suppression: id [unmatchedSuppression]', + 'tes?.c:0:0: information: Unmatched suppression: id [unmatchedSuppression]', + '*:0:0: information: Unmatched suppression: id2 [unmatchedSuppression]', + 'test*.c:0:0: information: Unmatched suppression: * [unmatchedSuppression]' ] @@ -3839,12 +4057,12 @@ def test_unmatched_file(tmp_path): # #14248 / #14249 ret, stdout, stderr = cppcheck(args) assert stdout == '' assert stderr.splitlines() == [ - f'{lib_file}:-1:0: information: Unmatched suppression: error [unmatchedSuppression]', - f'{lib_file}:-1:0: information: Unmatched suppression: error2 [unmatchedSuppression]', - f'{lib_file}:-1:0: information: Unmatched suppression: error3 [unmatchedSuppression]', - f'{lib_file}:-1:0: information: Unmatched suppression: error4 [unmatchedSuppression]', - f'{lib_file}:-1:0: information: Unmatched suppression: error5 [unmatchedSuppression]', - f'{lib_file}:-1:0: information: Unmatched suppression: error6 [unmatchedSuppression]' + f'{lib_file}:0:0: information: Unmatched suppression: error [unmatchedSuppression]', + f'{lib_file}:0:0: information: Unmatched suppression: error2 [unmatchedSuppression]', + f'{lib_file}:0:0: information: Unmatched suppression: error3 [unmatchedSuppression]', + f'{lib_file}:0:0: information: Unmatched suppression: error4 [unmatchedSuppression]', + f'{lib_file}:0:0: information: Unmatched suppression: error5 [unmatchedSuppression]', + f'{lib_file}:0:0: information: Unmatched suppression: error6 [unmatchedSuppression]' ] assert ret == 0, stdout @@ -4018,7 +4236,7 @@ def test_no_valid_configuration(tmp_path): '{}:1:2: error: No header in #include [syntaxError]'.format(test_file), '{}:1:2: error: No header in #include [syntaxError]'.format(test_file), '{}:1:2: error: No header in #include [syntaxError]'.format(test_file), - '{}:0:0: information: This file is not analyzed. Cppcheck failed to extract a valid configuration. Use -v for more details. [noValidConfiguration]'.format(test_file) + '{}:0:0: information: This file is not analyzed. No working configuration could be extracted. Use -v for more details. [noValidConfiguration]'.format(test_file) ] @@ -4100,22 +4318,435 @@ def __test_active_checkers(tmp_path, active_cnt, total_cnt, use_misra=False, use def test_active_unusedfunction_only(tmp_path): - __test_active_checkers(tmp_path, 1, 975, use_unusedfunction_only=True) + __test_active_checkers(tmp_path, 1, 186, use_unusedfunction_only=True) def test_active_unusedfunction_only_builddir(tmp_path): checkers_exp = [ 'CheckUnusedFunctions::check' ] - __test_active_checkers(tmp_path, 1, 975, use_unusedfunction_only=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 186, use_unusedfunction_only=True, checkers_exp=checkers_exp) def test_active_unusedfunction_only_misra(tmp_path): - __test_active_checkers(tmp_path, 1, 1175, use_unusedfunction_only=True, use_misra=True) + __test_active_checkers(tmp_path, 1, 386, use_unusedfunction_only=True, use_misra=True) def test_active_unusedfunction_only_misra_builddir(tmp_path): checkers_exp = [ 'CheckUnusedFunctions::check' ] - __test_active_checkers(tmp_path, 1, 1175, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 386, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) + + +def test_analyzerinfo(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write( +"""void f() +{ + (void)(*((int*)0)); +} +""") + + build_dir = tmp_path / 'b1' + os.makedirs(build_dir) + + test_a1_file = build_dir / 'test.a1' + + args = [ + '-q', + '--debug-analyzerinfo', + '--template=simple', + '--cppcheck-build-dir={}'.format(build_dir), + '--enable=all', + str(test_file) + ] + + stderr_exp = [ + '{}:3:14: error: Null pointer dereference: (int*)0 [nullPointer]'.format(test_file), + "{}:1:6: style: The function 'f' is never used. [unusedFunction]".format(test_file) + ] + + def run_and_assert_cppcheck(stdout_exp): + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0, stdout + assert stdout.splitlines() == stdout_exp + assert stderr.splitlines() == stderr_exp + + test_file_s = str(test_file).replace('\\', '/') + test_a1_file_s = str(test_a1_file).replace('\\', '/') + + # no cached results + run_and_assert_cppcheck([ + "no cached result '{}' for '{}' found".format(test_a1_file_s, test_file_s) + ]) + + # cached results + run_and_assert_cppcheck([ + "skipping analysis - loaded 1 cached finding(s) from '{}' for '{}'".format(test_a1_file_s, test_file_s) + ]) + + # modified file + with open(test_file, 'a') as f: + f.write('\n#define DEF') + + run_and_assert_cppcheck([ + "discarding cached result from '{}' for '{}' - hash mismatch".format(test_a1_file_s, test_file_s) + ]) + + # invalid XML + with open(test_a1_file, 'a') as f: + f.write('.') + + run_and_assert_cppcheck([ + "discarding cached result - failed to load '{}' for '{}' (XML_ERROR_PARSING_TEXT)".format(test_a1_file_s, test_file_s) + ]) + + # missing root node + with open(test_a1_file, 'w') as f: + f.write('') + + run_and_assert_cppcheck([ + "discarding cached result from '{}' for '{}' - no root node found".format(test_a1_file_s, test_file_s) + ]) + + # mismatched root node + with open(test_a1_file, 'w') as f: + f.write('') + + run_and_assert_cppcheck([ + "discarding cached result from '{}' for '{}' - unexpected root node".format(test_a1_file_s, test_file_s) + ]) + + # missing 'hash' attribute + with open(test_a1_file, 'w') as f: + f.write('') + + run_and_assert_cppcheck([ + "discarding cached result from '{}' for '{}' - no 'hash' attribute found".format(test_a1_file_s, test_file_s) + ]) + + # invalid 'hash' attribute + with open(test_a1_file, 'w') as f: + f.write('') + + run_and_assert_cppcheck([ + "discarding cached result from '{}' for '{}' - hash mismatch".format(test_a1_file_s, test_file_s) + ]) + + # TODO: + # - invalid error + # - internalError + + +def test_ctu_function_call_path_slash(tmp_path): # #14591 + test_file = tmp_path / 'test.cpp' + with open(test_file, "w") as f: + f.write( +"""void g(T* p) +{ + *p = 0; +} + +void f(T* p) +{ + p = nullptr; + g(p); +} +""") + + build_dir = tmp_path / 'b1' + os.makedirs(build_dir) + + args = [ + '-q', + '--template=simple', + '--cppcheck-build-dir={}'.format(build_dir), + str(test_file) + ] + + exitcode, _, _ = cppcheck(args) + assert exitcode == 0 + + test_a1_file = build_dir / 'test.a1' + analyzerinfo = ElementTree.fromstring(test_a1_file.read_text()) + function_call_paths = analyzerinfo.findall('FileInfo/function-call/path') + assert len(function_call_paths) == 1 + file = function_call_paths[0].attrib['file'] + assert file + assert not '\\' in file # the path was incorrectly converted to native + + +# TODO: Remove duplication/builddir when 7079 is merged +def test_inline_block_suppr_builddir_twice(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, 'wt') as f: + f.write(""" +// cppcheck-suppress-begin [zerodiv] +x = 10 / 0; +// cppcheck-suppress-end [zerodiv] +""") + + build_dir = tmp_path / 'b' + os.mkdir(build_dir) + + args = [ + '-q', + '--cppcheck-build-dir={}'.format(build_dir), + '--enable=all', + '--inline-suppr', + str(test_file) + ] + + for _ in range(2): + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + assert stdout == '' + assert stderr == '' + + +def test_dui_include(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write('void f() {}') + + inc_file = tmp_path / 'inc.h' + with open(inc_file, "w") as f: + f.write( +""" +void f_i() +{ + (void)(*((int*)0)); +} +""") + + args = [ + '-q', + '--template=simple', + f'--include={inc_file}', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + assert stdout == '' + assert stderr.splitlines() == [ + f'{inc_file}:4:14: error: Null pointer dereference: (int*)0 [nullPointer]' + ] + + +def test_dui_include_missing(tmp_path): # #14675 + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write('void f() {}') + + args = [ + '-q', + '--template=simple', + '--include=missing.h', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + assert stdout == '' + assert stderr.splitlines() == [ + f"{test_file}:0:0: error: Can not open include file 'missing.h' that is explicitly included. [missingIncludeExplicit]" + ] + + +def test_dui_include_relative(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write('void f() {}') + + inc_file = tmp_path / 'inc.h' + with open(inc_file, "w") as f: + f.write( +""" +void f_i() +{ + (void)(*((int*)0)); +} +""") + + args = [ + '-q', + '--template=simple', + '--include=inc.h', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args, cwd=tmp_path) + assert exitcode == 0 + assert stdout == '' + assert stderr.splitlines() == [ + 'inc.h:4:14: error: Null pointer dereference: (int*)0 [nullPointer]' + ] + + +def test_dui_include_relative_missing(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write('void f() {}') + + inc_file = tmp_path / 'inc.h' + with open(inc_file, "w") as f: + f.write( +""" +void f_i() +{ + (void)(*((int*)0)); +} +""") + + args = [ + '-q', + '--template=simple', + '--include=inc.h', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args,) + assert exitcode == 0 + assert stdout == '' + assert stderr.splitlines() == [ + f"{test_file}:0:0: error: Can not open include file 'inc.h' that is explicitly included. [missingIncludeExplicit]" + ] + + +def test_dui_include_absolute_missing(tmp_path): # #14675 + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write('void f() {}') + + args = [ + '-q', + '--template=simple', + '--include=/share/include/missing.h', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + assert stdout == '' + assert stderr.splitlines() == [ + f"{test_file}:0:0: error: Can not open include file '/share/include/missing.h' that is explicitly included. [missingIncludeExplicit]" + ] + + +@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") +def test_ipc(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write('void f() {}') + + args = [ + '-q', + '--debug-ipc', + '-j2', + '--executor=process', + '--no-cppcheck-build-dir', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + assert stdout.splitlines() == [ + 'writeToPipe - 5 - 0', + 'handleRead - 5 - 0' + ] + assert stderr.splitlines() == [] + + +@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") +def test_ipc_suppressions(tmp_path): + test1_file = tmp_path / 'test1.c' + with open(test1_file, "w") as f: + f.write('void f() {}') + + test2_file = tmp_path / 'test2.c' + with open(test2_file, "w") as f: + f.write('void f() {}') + + test3_file = tmp_path / 'test3.c' + with open(test3_file, "w") as f: + f.write('void f() {}') + + args = [ + '-q', + '--debug-ipc', + '-j2', + '--executor=process', + '--no-cppcheck-build-dir', + '--suppress=id0:test1.c', + str(tmp_path) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + # sort the lines since the order is not fixed + stdout_exp = [ + 'writeToPipe - 4 - id0:test1.c;0;1;0;', + 'handleRead - 4 - id0:test1.c;0;1;0;', + 'writeToPipe - 5 - 0', + 'handleRead - 5 - 0', + 'writeToPipe - 5 - 0', + 'handleRead - 5 - 0', + 'writeToPipe - 5 - 0', + 'handleRead - 5 - 0' + ] + stdout_exp.sort() + stdout_lines = stdout.splitlines() + stdout_lines.sort() + assert stdout_lines == stdout_exp + assert stderr.splitlines() == [] + + +@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") +def test_ipc_inline_suppressions(tmp_path): + test1_file = tmp_path / 'test1.c' + with open(test1_file, "w") as f: + f.write('void f() {} // cppcheck-suppress id1') + + test2_file = tmp_path / 'test2.c' + with open(test2_file, "w") as f: + f.write('void f() {} // cppcheck-suppress id2') + + test3_file = tmp_path / 'test3.c' + with open(test3_file, "w") as f: + f.write('void f() {} // cppcheck-suppress id3') + + args = [ + '-q', + '--debug-ipc', + '-j2', + '--executor=process', + '--no-cppcheck-build-dir', + '--inline-suppr', + str(tmp_path) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + # sort the lines since the order is not fixed + stdout_exp = [ + f'writeToPipe - 3 - id1:{test1_file}:1;13;1;0;', + f'handleRead - 3 - id1:{test1_file}:1;13;1;0;', + 'writeToPipe - 5 - 0', + 'handleRead - 5 - 0', + f'writeToPipe - 3 - id2:{test2_file}:1;13;1;0;', + f'handleRead - 3 - id2:{test2_file}:1;13;1;0;', + 'writeToPipe - 5 - 0', + 'handleRead - 5 - 0', + f'writeToPipe - 3 - id3:{test3_file}:1;13;1;0;', + f'handleRead - 3 - id3:{test3_file}:1;13;1;0;', + 'writeToPipe - 5 - 0', + 'handleRead - 5 - 0' + ] + stdout_exp.sort() + stdout_lines = stdout.splitlines() + stdout_lines.sort() + assert stdout_lines == stdout_exp + assert stderr.splitlines() == [] \ No newline at end of file diff --git a/test/cli/performance_test.py b/test/cli/performance_test.py index 90daf9b58cc..55da3b3b04e 100644 --- a/test/cli/performance_test.py +++ b/test/cli/performance_test.py @@ -146,6 +146,29 @@ def test_slow_exprid(tmpdir): my_env["DISABLE_VALUEFLOW"] = "1" cppcheck([filename], env=my_env) +@pytest.mark.timeout(35) +def test_stack_overflow_AST(tmpdir): + # 14435 + filename = os.path.join(tmpdir, 'hang.cpp') + with open(filename, 'wt') as f: + f.write(""" +#define ROW 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +#define ROW8 ROW ROW ROW ROW ROW ROW ROW ROW +#define ROW64 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 +#define ROW512 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 +#define ROW4096 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 +#define ROW32768 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096 +void f(std::vector& v) { + v = { + ROW32768 0 + }; +} + """) + + my_env = os.environ.copy() + my_env["DISABLE_VALUEFLOW"] = "1" + cppcheck([filename], env=my_env) + @pytest.mark.timeout(10) def test_slow_initlist_varchanged(tmpdir): diff --git a/test/cli/project_test.py b/test/cli/project_test.py index ec1ef56d7d1..7421ca406a6 100644 --- a/test/cli/project_test.py +++ b/test/cli/project_test.py @@ -7,7 +7,7 @@ from testutils import cppcheck -@pytest.mark.parametrize("project_ext", ["json", "sln", "vcxproj", "bpr", "cppcheck"]) +@pytest.mark.parametrize("project_ext", ["json", "sln", "slnx", "vcxproj", "bpr", "cppcheck"]) def test_missing_project(project_ext): project_file = "file.{}".format(project_ext) @@ -33,6 +33,7 @@ def __test_project_error(tmpdir, ext, content, expected): @pytest.mark.parametrize("project_ext, expected", [ ("json", "compilation database is not a JSON array"), ("sln", "Visual Studio solution file is empty"), + ("slnx", "Visual Studio solution file is not a valid XML - XML_ERROR_EMPTY_DOCUMENT"), ("vcxproj", "Visual Studio project file is not a valid XML - XML_ERROR_EMPTY_DOCUMENT"), ("bpr", "Borland project file is not a valid XML - XML_ERROR_EMPTY_DOCUMENT"), ("cppcheck", "Cppcheck GUI project file is not a valid XML - XML_ERROR_EMPTY_DOCUMENT") @@ -64,7 +65,7 @@ def test_json_entry_file_not_found(tmpdir): "--project=" + str(project_file) ]) assert 0 == ret - assert stderr == f"nofile:0:0: error: File is missing: {missing_file_posix} [missingFile]\n" + assert stderr == f"{missing_file}:0:0: error: File is missing: {missing_file_posix} [missingFile]\n" def test_json_no_arguments(tmpdir): @@ -138,6 +139,46 @@ def test_sln_project_file_not_found(tmpdir): __test_project_error(tmpdir, "sln", content, expected) +def test_slnx_no_xml_root(tmpdir): + content = '' + + expected = "Visual Studio solution file has no XML root node" + + __test_project_error(tmpdir, "slnx", content, expected) + + +def test_slnx_no_projects(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + " \r\n" \ + "\r\n" + + expected = "no projects found in Visual Studio solution file" + + __test_project_error(tmpdir, "slnx", content, expected) + + +def test_slnx_project_file_not_found(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + " \r\n" \ + ' \r\n' \ + "\r\n" + + expected = "Visual Studio project file is not a valid XML - XML_ERROR_FILE_NOT_FOUND\n" \ + "cppcheck: error: failed to load '{}' from Visual Studio solution".format(os.path.join(tmpdir, "test.vcxproj")) + if sys.platform == "win32": + expected = expected.replace('\\', '/') + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_vcxproj_no_xml_root(tmpdir): content = '' diff --git a/test/cli/testutils.py b/test/cli/testutils.py index f352af49f15..2140c42205b 100644 --- a/test/cli/testutils.py +++ b/test/cli/testutils.py @@ -5,6 +5,7 @@ import subprocess import time import tempfile +import json # Create Cppcheck project file import sys @@ -45,6 +46,22 @@ def create_gui_project_file(project_file, root_path=None, import_project=None, p f.write(cppcheck_xml) +def create_compile_commands(compdb_file, files): + compdb = [] + # TODO: bail out on empty list + for f in files: + compdb.append( + { + "file": str(f), + "directory": os.path.dirname(f), + "command": "gcc -c {}".format(os.path.basename(f)) + } + ) + compdb_j = json.dumps(compdb) + with open(compdb_file, 'wt') as f: + f.write(compdb_j) + + def __lookup_cppcheck_exe(): # path the script is located in script_path = os.path.dirname(os.path.realpath(__file__)) diff --git a/test/fixture.cpp b/test/fixture.cpp index b59b47855f7..de42837a56e 100644 --- a/test/fixture.cpp +++ b/test/fixture.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include "library.h" #include "options.h" #include "redirect.h" +#include "timer.h" #include #include @@ -88,6 +89,7 @@ TestFixture::TestFixture(const char * const _name) : classname(_name) {} +TestFixture::~TestFixture() = default; bool TestFixture::prepareTest(const char testname[]) { @@ -97,25 +99,34 @@ bool TestFixture::prepareTest(const char testname[]) prepareTestInternal(); // Check if tests should be executed - if (testToRun.empty() || testToRun == testname) { - // Tests will be executed - prepare them - mTestname = testname; - ++countTests; - if (quiet_tests) { - std::putchar('.'); // Use putchar to write through redirection of std::cout/cerr - std::fflush(stdout); - } else { - std::cout << classname << "::" << mTestname << std::endl; - } - return !dry_run; + if (!testsToRun.empty()) { + const bool match = testsToRun.count(testname); + if ((match && exclude_tests) || (!match && !exclude_tests)) + return false; + } + + // Tests will be executed - prepare them + mTestname = testname; + ++countTests; + std::string fullTestName = classname + "::" + mTestname; + if (quiet_tests) { + std::putchar('.'); // Use putchar to write through redirection of std::cout/cerr + std::fflush(stdout); + } else { + std::cout << fullTestName << std::endl; } - return false; + if (timer_results) + mTimer.reset(new Timer(fullTestName, timer_results)); + return !dry_run; } void TestFixture::teardownTest() { teardownTestInternal(); + if (mTimer) + mTimer->stop(); + { const std::string s = errout_str(); if (!s.empty()) @@ -346,12 +357,13 @@ void TestFixture::printHelp() " -q Do not print the test cases that have run.\n" " -h, --help Print this help.\n" " -n Print no summaries.\n" - " -d Do not execute the tests.\n"; + " -d Do not execute any tests (dry run).\n" + " -x Exclude the specified tests.\n"; } -void TestFixture::run(const std::string &str) +void TestFixture::run(const std::set &tests) { - testToRun = str; + testsToRun = tests; try { if (quiet_tests) { std::cout << '\n' << classname << ':'; @@ -379,7 +391,9 @@ void TestFixture::processOptions(const options& args) { quiet_tests = args.quiet(); dry_run = args.dry_run(); + exclude_tests = args.exclude_tests(); exename = args.exe(); + timer_results = args.timer_results(); } std::size_t TestFixture::runTests(const options& args) @@ -387,21 +401,31 @@ std::size_t TestFixture::runTests(const options& args) countTests = 0; errmsg.str(""); + const auto& which_tests = args.which_tests(); + const auto exclude_tests = args.exclude_tests(); + // TODO: bail out when given class/test is not found? - for (std::string classname : args.which_test()) { - std::string testname; - if (classname.find("::") != std::string::npos) { - testname = classname.substr(classname.find("::") + 2); - classname.erase(classname.find("::")); + for (TestInstance * test : TestRegistry::theInstance().tests()) + { + std::set tests; + if (!which_tests.empty()) { + const auto it = which_tests.find(test->classname); + const bool match = it != which_tests.cend(); + if (match && exclude_tests && it->second.empty()) // only bailout when the whole fixture is excluded + continue; + if (!match && !exclude_tests) + continue; + if (match) + tests = it->second; } - for (TestInstance * test : TestRegistry::theInstance().tests()) { - if (classname.empty() || test->classname == classname) { - TestFixture* fixture = test->create(); - fixture->processOptions(args); - fixture->run(testname); - } - } + TestFixture* fixture; + const auto f = [&](){ + fixture = test->create(); + }; + Timer::run(test->classname + " - create", args.timer_results(), f); + fixture->processOptions(args); + fixture->run(tests); } if (args.summary() && !args.dry_run()) { diff --git a/test/fixture.h b/test/fixture.h index 5983ae66a3a..b927dc5de65 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,8 +32,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -42,6 +42,8 @@ class options; class Tokenizer; +class Timer; +class TimerResultsIntf; class TestFixture : public ErrorLogger { private: @@ -56,9 +58,11 @@ class TestFixture : public ErrorLogger { protected: std::string exename; - std::string testToRun; + std::set testsToRun; bool quiet_tests{}; bool dry_run{}; + bool exclude_tests{}; + TimerResultsIntf* timer_results{}; bool mNewTemplate{}; virtual void run() = 0; @@ -130,21 +134,13 @@ class TestFixture : public ErrorLogger { void processOptions(const options& args); - template - static T& getCheck() + static Check& getCheck(Check& check) { - for (Check *check : Check::instances()) { - //cppcheck-suppress useStlAlgorithm - if (T* c = dynamic_cast(check)) - return *c; - } - throw std::runtime_error("instance not found"); + return check; } - template - static void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) + static void runChecks(Check& check, const Tokenizer &tokenizer, ErrorLogger *errorLogger) { - Check& check = getCheck(); check.runChecks(tokenizer, errorLogger); } @@ -284,19 +280,22 @@ class TestFixture : public ErrorLogger { std::ostringstream mOutput; std::ostringstream mErrout; - void reportOut(const std::string &outmsg, Color c = Color::Reset) override; + std::unique_ptr mTimer; + + void reportOut(const std::string &outmsg, Color /*c*/ = Color::Reset) override; void reportErr(const ErrorMessage &msg) override; void reportMetric(const std::string &metric) override { (void) metric; } - void run(const std::string &str); + void run(const std::set &tests); public: static void printHelp(); const std::string classname; explicit TestFixture(const char * _name); + ~TestFixture() override; static std::size_t runTests(const options& args); }; @@ -331,8 +330,7 @@ class TestInstance { #define ASSERT_EQUALS_ENUM_LOC( EXPECTED, ACTUAL, FILE_, LINE_ ) assertEqualsEnum(FILE_, LINE_, (EXPECTED), (ACTUAL)) #define ASSERT_EQUALS_ENUM_LOC_MSG( EXPECTED, ACTUAL, MSG, FILE_, LINE_ ) assertEqualsEnum(FILE_, LINE_, (EXPECTED), (ACTUAL), MSG) #define TODO_ASSERT_EQUALS_ENUM( WANTED, CURRENT, ACTUAL ) todoAssertEqualsEnum(__FILE__, __LINE__, WANTED, CURRENT, ACTUAL) -#define ASSERT_THROW_EQUALS( CMD, EXCEPTION, EXPECTED ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const EXCEPTION&e) { assertEquals(__FILE__, __LINE__, EXPECTED, e.errorMessage); } catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false) -#define ASSERT_THROW_EQUALS_2( CMD, EXCEPTION, EXPECTED ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const AssertFailedError&) { throw; } catch (const EXCEPTION&e) { assertEquals(__FILE__, __LINE__, EXPECTED, e.what()); } catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false) +#define ASSERT_THROW_EQUALS( CMD, EXCEPTION, EXPECTED ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const AssertFailedError&) { throw; } catch (const EXCEPTION&e) { assertEquals(__FILE__, __LINE__, EXPECTED, e.what()); } catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false) #define ASSERT_THROW_INTERNAL( CMD, TYPE ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const AssertFailedError&) { throw; } catch (const InternalError& e) { assertEqualsEnum(__FILE__, __LINE__, InternalError::TYPE, e.type); } catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false) #define ASSERT_THROW_INTERNAL_EQUALS( CMD, TYPE, EXPECTED ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const AssertFailedError&) { throw; } catch (const InternalError& e) { assertEqualsEnum(__FILE__, __LINE__, InternalError::TYPE, e.type); assertEquals(__FILE__, __LINE__, EXPECTED, e.errorMessage); } catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false) #define ASSERT_NO_THROW( CMD ) do { try { (void)(CMD); } catch (const AssertFailedError&) { throw; } catch (...) { assertNoThrowFail(__FILE__, __LINE__, true); } } while (false) diff --git a/test/helpers.cpp b/test/helpers.cpp index 25b4564ed38..252658cc531 100644 --- a/test/helpers.cpp +++ b/test/helpers.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/test/main.cpp b/test/main.cpp index afe3e3b4171..e0495583494 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2023 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include "fixture.h" #include +#include int main(int argc, char *argv[]) { @@ -34,6 +35,13 @@ int main(int argc, char *argv[]) TestFixture::printHelp(); return EXIT_SUCCESS; } + if (!args.errors().empty()) { + for (const auto& error : args.errors()) + { + std::cout << "error: " << error << '\n'; + } + return EXIT_FAILURE; + } const std::size_t failedTestsCount = TestFixture::runTests(args); return (failedTestsCount == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/test/options.cpp b/test/options.cpp index e8b3be139ae..54527b26ecd 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -16,24 +16,50 @@ #include "options.h" +#include "timer.h" + options::options(int argc, const char* const argv[]) - : mWhichTests(argv + 1, argv + argc) - ,mQuiet(mWhichTests.count("-q") != 0) - ,mHelp(mWhichTests.count("-h") != 0 || mWhichTests.count("--help")) - ,mSummary(mWhichTests.count("-n") == 0) - ,mDryRun(mWhichTests.count("-d") != 0) - ,mExe(argv[0]) + : mExe(argv[0]) { - for (auto it = mWhichTests.cbegin(); it != mWhichTests.cend();) { - if (!it->empty() && (((*it)[0] == '-') || (it->find("::") != std::string::npos && mWhichTests.count(it->substr(0, it->find("::")))))) - it = mWhichTests.erase(it); - else - ++it; + const std::set args(argv + 1, argv + argc); + for (const auto& arg : args) { + if (arg.empty()) + continue; // empty argument + if (arg[0] == '-') { + if (arg == "-q") + mQuiet = true; + else if (arg == "-h" || arg == "--help") + mHelp = true; + else if (arg == "-n") + mSummary = false; + else if (arg == "-d") + mDryRun = true; + else if (arg == "-x") + mExcludeTests = true; + else if (arg == "-t") + mTimerResults.reset(new TimerResults); + else + mErrors.emplace_back("unknown option '" + arg + "'"); + continue; // command-line switch + } + const auto pos = arg.find("::"); + if (pos == std::string::npos) { + mWhichTests[arg] = {}; // run whole fixture + continue; + } + const std::string fixture = arg.substr(0, pos); + const auto it = mWhichTests.find(fixture); + if (it != mWhichTests.cend() && it->second.empty()) + continue; // whole fixture is already included + const std::string test = arg.substr(pos+2); + mWhichTests[fixture].emplace(test); // run individual test } +} - if (mWhichTests.empty()) { - mWhichTests.insert(""); - } +options::~options() +{ + if (mTimerResults) + mTimerResults->showResults(10, false); } bool options::quiet() const @@ -56,7 +82,7 @@ bool options::dry_run() const return mDryRun; } -const std::set& options::which_test() const +const std::map>& options::which_tests() const { return mWhichTests; } @@ -65,3 +91,18 @@ const std::string& options::exe() const { return mExe; } + +bool options::exclude_tests() const +{ + return mExcludeTests; +} + +TimerResultsIntf* options::timer_results() const +{ + return mTimerResults.get(); +} + +const std::vector& options::errors() const +{ + return mErrors; +} diff --git a/test/options.h b/test/options.h index 18df1dd79b2..b327721351c 100644 --- a/test/options.h +++ b/test/options.h @@ -17,8 +17,14 @@ #ifndef OPTIONS_H #define OPTIONS_H +#include +#include #include #include +#include + +class TimerResultsIntf; +class TimerResults; /** * @brief Class to parse command-line parameters for ./testrunner . @@ -29,6 +35,7 @@ class options { public: /** Call from main() to populate object */ options(int argc, const char* const argv[]); + ~options(); /** Don't print the name of each method being tested. */ bool quiet() const; /** Print help. */ @@ -37,8 +44,15 @@ class options { bool summary() const; /** Perform dry run. */ bool dry_run() const; - /** Which test should be run. Empty string means 'all tests' */ - const std::set& which_test() const; + /** Exclude provided lists of tests. */ + bool exclude_tests() const; + /** The timer results. */ + TimerResultsIntf* timer_results() const; + /** Which tests should be run. */ + const std::map>& which_tests() const; + + /** Errors encountered during option processing. */ + const std::vector& errors() const; const std::string& exe() const; @@ -47,11 +61,14 @@ class options { options& operator =(const options&) = delete; private: - std::set mWhichTests; - const bool mQuiet; - const bool mHelp; - const bool mSummary; - const bool mDryRun; + std::map> mWhichTests; + std::vector mErrors; + bool mQuiet{}; + bool mHelp{}; + bool mSummary{true}; + bool mDryRun{}; + bool mExcludeTests{}; + std::unique_ptr mTimerResults; std::string mExe; }; diff --git a/test/testanalyzerinformation.cpp b/test/testanalyzerinformation.cpp index 13dd721f0a4..0936dbbf3f2 100644 --- a/test/testanalyzerinformation.cpp +++ b/test/testanalyzerinformation.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,6 +39,7 @@ class TestAnalyzerInformation : public TestFixture { }; void run() override { + TEST_CASE(getAnalyzerInfoFileFromFilesTxt); TEST_CASE(getAnalyzerInfoFile); TEST_CASE(duplicateFile); TEST_CASE(filesTextDuplicateFile); @@ -46,12 +47,15 @@ class TestAnalyzerInformation : public TestFixture { TEST_CASE(skipAnalysis); } - void getAnalyzerInfoFile() const { + void getAnalyzerInfoFileFromFilesTxt() const { constexpr char filesTxt[] = "file1.a4:::file1.c\n"; - std::istringstream f1(filesTxt); - ASSERT_EQUALS("file1.a4", AnalyzerInformationTest::getAnalyzerInfoFileFromFilesTxt(f1, "file1.c", "", 0)); - std::istringstream f2(filesTxt); - ASSERT_EQUALS("file1.a4", AnalyzerInformationTest::getAnalyzerInfoFileFromFilesTxt(f2, "./file1.c", "", 0)); + std::istringstream f(filesTxt); + ASSERT_EQUALS("file1.a4", AnalyzerInformationTest::getAnalyzerInfoFileFromFilesTxt(f, "file1.c", "", 0)); + f.str(filesTxt); + ASSERT_EQUALS("file1.a4", AnalyzerInformationTest::getAnalyzerInfoFileFromFilesTxt(f, "./file1.c", "", 0)); + } + + void getAnalyzerInfoFile() const { ASSERT_EQUALS("builddir/file1.c.analyzerinfo", AnalyzerInformation::getAnalyzerInfoFile("builddir", "file1.c", "", 0)); ASSERT_EQUALS("builddir/file1.c.analyzerinfo", AnalyzerInformation::getAnalyzerInfoFile("builddir", "some/path/file1.c", "", 0)); } @@ -59,14 +63,14 @@ class TestAnalyzerInformation : public TestFixture { void filesTextDuplicateFile() const { std::list fileSettings; fileSettings.emplace_back("a.c", Standards::Language::C, 10); - fileSettings.back().fileIndex = 0; + fileSettings.back().file.setFsFileId(0); fileSettings.emplace_back("a.c", Standards::Language::C, 10); - fileSettings.back().fileIndex = 1; + fileSettings.back().file.setFsFileId(1); const char expected[] = "a.a1:::a.c\n" "a.a2::1:a.c\n"; - ASSERT_EQUALS(expected, AnalyzerInformationTest::getFilesTxt({}, "", fileSettings)); + ASSERT_EQUALS(expected, AnalyzerInformationTest::getFilesTxt({}, fileSettings)); } void duplicateFile() const { @@ -90,19 +94,19 @@ class TestAnalyzerInformation : public TestFixture { ASSERT_EQUALS(true, info.parse("a:b::d")); ASSERT_EQUALS("a", info.afile); ASSERT_EQUALS("b", info.cfg); - ASSERT_EQUALS(0, info.fileIndex); + ASSERT_EQUALS(0, info.fsFileId); ASSERT_EQUALS("d", info.sourceFile); ASSERT_EQUALS(true, info.parse("e:f:12:g")); ASSERT_EQUALS("e", info.afile); ASSERT_EQUALS("f", info.cfg); - ASSERT_EQUALS(12, info.fileIndex); + ASSERT_EQUALS(12, info.fsFileId); ASSERT_EQUALS("g", info.sourceFile); ASSERT_EQUALS(true, info.parse("odr1.a1:::C:/dm/cppcheck-fix-13333/test/cli/whole-program/odr1.cpp")); ASSERT_EQUALS("odr1.a1", info.afile); ASSERT_EQUALS("", info.cfg); - ASSERT_EQUALS(0, info.fileIndex); + ASSERT_EQUALS(0, info.fsFileId); ASSERT_EQUALS("C:/dm/cppcheck-fix-13333/test/cli/whole-program/odr1.cpp", info.sourceFile); } @@ -122,7 +126,7 @@ class TestAnalyzerInformation : public TestFixture { ); ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); - ASSERT_EQUALS(false, AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); + ASSERT_EQUALS("'premium-invalidLicense' encountered", AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); ASSERT_EQUALS(0, errorList.size()); } @@ -141,7 +145,7 @@ class TestAnalyzerInformation : public TestFixture { ); ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); - ASSERT_EQUALS(false, AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); + ASSERT_EQUALS("'premium-internalError' encountered", AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); ASSERT_EQUALS(0, errorList.size()); } @@ -160,7 +164,7 @@ class TestAnalyzerInformation : public TestFixture { ); ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); - ASSERT_EQUALS(false, AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); + ASSERT_EQUALS("'internalError' encountered", AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); ASSERT_EQUALS(0, errorList.size()); } @@ -181,7 +185,7 @@ class TestAnalyzerInformation : public TestFixture { ); ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); - ASSERT_EQUALS(true, AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); + ASSERT_EQUALS("", AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); ASSERT_EQUALS(1, errorList.size()); } @@ -197,7 +201,7 @@ class TestAnalyzerInformation : public TestFixture { ); ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); - ASSERT_EQUALS(true, AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); + ASSERT_EQUALS("", AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); ASSERT_EQUALS(0, errorList.size()); } @@ -218,7 +222,7 @@ class TestAnalyzerInformation : public TestFixture { ); ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); - ASSERT_EQUALS(false, AnalyzerInformationTest::skipAnalysis(doc, 99, errorList)); + ASSERT_EQUALS("hash mismatch", AnalyzerInformationTest::skipAnalysis(doc, 99, errorList)); ASSERT_EQUALS(0, errorList.size()); } @@ -230,7 +234,37 @@ class TestAnalyzerInformation : public TestFixture { const tinyxml2::XMLError xmlError = doc.Parse(""); ASSERT_EQUALS(tinyxml2::XML_ERROR_EMPTY_DOCUMENT, xmlError); - ASSERT_EQUALS(false, AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); + ASSERT_EQUALS("no root node found", AnalyzerInformationTest::skipAnalysis(doc, 100, errorList)); + ASSERT_EQUALS(0, errorList.size()); + } + + // Unexpected root node + { + std::list errorList; + tinyxml2::XMLDocument doc; + + const tinyxml2::XMLError xmlError = doc.Parse( + "" + "" + ); + ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); + + ASSERT_EQUALS("unexpected root node", AnalyzerInformationTest::skipAnalysis(doc, 99, errorList)); + ASSERT_EQUALS(0, errorList.size()); + } + + // No 'hash' attribute found + { + std::list errorList; + tinyxml2::XMLDocument doc; + + const tinyxml2::XMLError xmlError = doc.Parse( + "" + "" + ); + ASSERT_EQUALS(tinyxml2::XML_SUCCESS, xmlError); + + ASSERT_EQUALS("no 'hash' attribute found", AnalyzerInformationTest::skipAnalysis(doc, 99, errorList)); ASSERT_EQUALS(0, errorList.size()); } } diff --git a/test/testassert.cpp b/test/testassert.cpp index 412a7cb750b..e14825e46b2 100644 --- a/test/testassert.cpp +++ b/test/testassert.cpp @@ -39,8 +39,8 @@ class TestAssert : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckAssert check; + runChecks(check, tokenizer, this); } void run() override { diff --git a/test/testastutils.cpp b/test/testastutils.cpp index 8ca2412a095..eb9559ed39d 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.cpp @@ -81,8 +81,8 @@ class TestAstUtils : public TestFixture { ASSERT_EQUALS(true, findLambdaEndToken("[](void) mutable -> const * int { return x; }")); ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const ** int { return x; }")); ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const * const* int { return x; }")); - ASSERT_EQUALS(false, findLambdaEndToken("int** a[] { new int*[2] { new int, new int} }", "[ ]")); - ASSERT_EQUALS(false, findLambdaEndToken("int** a[] { new int*[2] { new int, new int} }", "[ 2")); + ASSERT_EQUALS(false, findLambdaEndToken("int** a[] { new int*[2] { new int, new int} };", "[ ]")); + ASSERT_EQUALS(false, findLambdaEndToken("int** a[] { new int*[2] { new int, new int} };", "[ 2")); ASSERT_EQUALS(false, findLambdaEndToken("shared_ptr sp{ new Type *[2] {new Type, new Type}, Deleter{ 2 } };", "[ 2")); ASSERT_EQUALS(true, findLambdaEndToken("int i = 5 * []{ return 7; }();", "[", /*checkNext*/ false)); } diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 1091a03e9ff..2474c2fe6a5 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,7 +47,8 @@ class TestAutoVariables : public TestFixture { SimpleTokenizer tokenizer(settings1, *this, options.cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - runChecks(tokenizer, this); + CheckAutoVariables check; + runChecks(check, tokenizer, this); } void run() override { @@ -69,6 +70,7 @@ class TestAutoVariables : public TestFixture { TEST_CASE(testautovar15); // ticket #6538 TEST_CASE(testautovar16); // ticket #8114 TEST_CASE(testautovar17); + TEST_CASE(testautovar18); TEST_CASE(testautovar_array1); TEST_CASE(testautovar_array2); TEST_CASE(testautovar_array3); @@ -130,6 +132,7 @@ class TestAutoVariables : public TestFixture { TEST_CASE(returnReference26); TEST_CASE(returnReference27); TEST_CASE(returnReference28); + TEST_CASE(returnReference29); TEST_CASE(returnReferenceFunction); TEST_CASE(returnReferenceContainer); TEST_CASE(returnReferenceLiteral); @@ -516,6 +519,15 @@ class TestAutoVariables : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void testautovar18() { + check("struct S { int* p; };\n" + "void foo(struct S* s) {\n" + " int x;\n" + " s[2].p = &x;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:5]: (error) Address of local auto-variable assigned to a function parameter. [autoVariables]\n", errout_str()); + } + void testautovar_array1() { check("void func1(int* arr[2])\n" "{\n" @@ -711,8 +723,7 @@ class TestAutoVariables : public TestFixture { " g(&s);\n" "}"); ASSERT_EQUALS( - "[test.cpp:4:5]: (error) Address of local auto-variable assigned to a function parameter. [autoVariables]\n" - "[test.cpp:4:5]: (error) Address of local auto-variable assigned to a function parameter. [autoVariables]\n", // duplicate + "[test.cpp:4:5]: (error) Address of local auto-variable assigned to a function parameter. [autoVariables]\n", errout_str()); } @@ -1748,6 +1759,19 @@ class TestAutoVariables : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void returnReference29() + { + check("const std::string& f() {\n" // #12548 + " return std::string{};\n" + "}\n" + "const std::string& g() {\n" + " return {};\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:23]: (error) Reference to temporary returned. [returnTempReference]\n" + "[test.cpp:5:12]: (error) Reference to temporary returned. [returnTempReference]\n", + errout_str()); + } + void returnReferenceFunction() { check("int& f(int& a) {\n" " return a;\n" @@ -2643,8 +2667,7 @@ class TestAutoVariables : public TestFixture { " auto it = g().begin();\n" " return it;\n" "}"); - ASSERT_EQUALS("[test.cpp:3:24] -> [test.cpp:3:16] -> [test.cpp:4:5]: (error) Using iterator that is a temporary. [danglingTemporaryLifetime]\n" - "[test.cpp:3:24] -> [test.cpp:4:12]: (error) Returning iterator that will be invalid when returning. [returnDanglingLifetime]\n", + ASSERT_EQUALS("[test.cpp:3:24] -> [test.cpp:3:16] -> [test.cpp:4:5]: (error) Using iterator that is a temporary. [danglingTemporaryLifetime]\n", errout_str()); check("std::vector g();\n" @@ -2915,6 +2938,30 @@ class TestAutoVariables : public TestFixture { " return it;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:44] -> [test.cpp:2:22] -> [test.cpp:4:12]: (error) Returning iterator to local container 'x' that will be invalid when returning. [returnDanglingLifetime]\n", errout_str()); + + check("void f(std::vector& m) {\n" + " int x;\n" + " m.push_back(&x);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:17] -> [test.cpp:3:17] -> [test.cpp:2:9] -> [test.cpp:3:5]: (error) Non-local variable 'm' will use object that points to local variable 'x'. [danglingLifetime]\n", errout_str()); + + check("struct P {\n" + " int h() const;\n" + " int x;\n" + " int& r;\n" + "};\n" + "int f(const P& p) {\n" + " return p.h();\n" + "}\n" + "struct C {\n" + " void g() {\n" + " int i = 1;\n" + " P q(m, i);\n" + " f(q);\n" + " }\n" + " int m;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void danglingLifetimeContainerView() @@ -3142,6 +3189,14 @@ class TestAutoVariables : public TestFixture { ASSERT_EQUALS( "[test.cpp:3:12] -> [test.cpp:2:10] -> [test.cpp:3:12]: (error) Returning pointer to local variable 'a' that will be invalid when returning. [returnDanglingLifetime]\n", errout_str()); + + check("std::string_view f() {\n" // #14465 + " std::vector v;\n" + " return *v.begin();\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:12] -> [test.cpp:3:12]: (error) Returning object that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); } void danglingLifetimeUniquePtr() @@ -4017,7 +4072,7 @@ class TestAutoVariables : public TestFixture { "}"); ASSERT_EQUALS( "[test.cpp:3:28] -> [test.cpp:3:28] -> [test.cpp:2:9] -> [test.cpp:4:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n" - "[test.cpp:3:32] -> [test.cpp:3:32] -> [test.cpp:2:9] -> [test.cpp:4:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n", // duplicate + "[test.cpp:3:32] -> [test.cpp:3:32] -> [test.cpp:2:9] -> [test.cpp:4:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n", errout_str()); check("std::vector f() {\n" @@ -4027,7 +4082,7 @@ class TestAutoVariables : public TestFixture { "}"); ASSERT_EQUALS( "[test.cpp:3:25] -> [test.cpp:3:25] -> [test.cpp:2:9] -> [test.cpp:4:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n" - "[test.cpp:3:29] -> [test.cpp:3:29] -> [test.cpp:2:9] -> [test.cpp:4:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n", // duplicate + "[test.cpp:3:29] -> [test.cpp:3:29] -> [test.cpp:2:9] -> [test.cpp:4:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n", errout_str()); check("std::vector f() {\n" @@ -4036,7 +4091,7 @@ class TestAutoVariables : public TestFixture { "}"); ASSERT_EQUALS( "[test.cpp:3:13] -> [test.cpp:3:13] -> [test.cpp:2:9] -> [test.cpp:3:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n" - "[test.cpp:3:17] -> [test.cpp:3:17] -> [test.cpp:2:9] -> [test.cpp:3:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n", // duplicate + "[test.cpp:3:17] -> [test.cpp:3:17] -> [test.cpp:2:9] -> [test.cpp:3:12]: (error) Returning object that points to local variable 'i' that will be invalid when returning. [returnDanglingLifetime]\n", errout_str()); check("std::vector f(int& x) {\n" @@ -4693,6 +4748,21 @@ class TestAutoVariables : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); + check("struct S {\n" + " int* a[1];\n" + " int* b[1][1];\n" + "};\n" + "void f(S* s) {\n" + " int i = 0;\n" + " s->a[0] = &i;\n" + "}\n" + "void g(S* s) {\n" + " int i = 0;\n" + " s->b[0][0] = &i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7:5]: (error) Address of local auto-variable assigned to a function parameter. [autoVariables]\n" + "[test.cpp:11:5]: (error) Address of local auto-variable assigned to a function parameter. [autoVariables]\n", + errout_str()); } void deadPointer() { diff --git a/test/testbool.cpp b/test/testbool.cpp index 70860a8c169..ccf4d7860c4 100644 --- a/test/testbool.cpp +++ b/test/testbool.cpp @@ -88,8 +88,8 @@ class TestBool : public TestFixture { SimpleTokenizer tokenizer(settings, *this, options.cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check... - runChecks(tokenizer, this); + CheckBool check; + runChecks(check, tokenizer, this); } @@ -273,7 +273,7 @@ class TestBool : public TestFixture { "}"); ASSERT_EQUALS( "[test.cpp:2:17]: (warning) Comparison of a boolean expression with an integer other than 0 or 1. [compareBoolExpressionWithInt]\n" - "[test.cpp:2:32]: (warning) Comparison of a boolean expression with an integer other than 0 or 1. [compareBoolExpressionWithInt]\n", // duplicate + "[test.cpp:2:32]: (warning) Comparison of a boolean expression with an integer other than 0 or 1. [compareBoolExpressionWithInt]\n", errout_str()); check("void f(int x) {\n" diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index ec02406dcc8..5d545606387 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,8 +35,9 @@ class TestBufferOverrun : public TestFixture { TestBufferOverrun() : TestFixture("TestBufferOverrun") {} private: - /*const*/ Settings settings0 = settingsBuilder().library("std.cfg").severity(Severity::warning).severity(Severity::style).severity(Severity::portability).build(); + /*const*/ Settings settings0 = settingsBuilder().library("std.cfg").severity(Severity::warning).severity(Severity::style).build(); const Settings settings0_i = settingsBuilder(settings0).certainty(Certainty::inconclusive).build(); + const Settings settings0_p = settingsBuilder(settings0).severity(Severity::portability).build(); const Settings settings1 = settingsBuilder(settings0).severity(Severity::performance).certainty(Certainty::inconclusive).build(); struct CheckOptions @@ -55,8 +56,8 @@ class TestBufferOverrun : public TestFixture { SimpleTokenizer tokenizer(settings, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for buffer overruns.. - runChecks(tokenizer, this); + CheckBufferOverrun check; + runChecks(check, tokenizer, this); } // TODO: get rid of this @@ -65,8 +66,8 @@ class TestBufferOverrun : public TestFixture { SimpleTokenizer tokenizer(settings0_i, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for buffer overruns.. - runChecks(tokenizer, this); + CheckBufferOverrun check; + runChecks(check, tokenizer, this); } #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) @@ -78,8 +79,8 @@ class TestBufferOverrun : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check for buffer overruns.. - runChecks(tokenizer, this); + CheckBufferOverrun check; + runChecks(check, tokenizer, this); } void run() override { @@ -225,6 +226,7 @@ class TestBufferOverrun : public TestFixture { TEST_CASE(buffer_overrun_34); //#11035 TEST_CASE(buffer_overrun_35); //#2304 TEST_CASE(buffer_overrun_36); + TEST_CASE(buffer_overrun_37); TEST_CASE(buffer_overrun_errorpath); TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch TEST_CASE(buffer_overrun_function_array_argument); @@ -3496,6 +3498,15 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void buffer_overrun_37() { // #14703 + check("void f() {\n" + " const char *dst[256];\n" + " static const char * const src[] = {\"a\", \"b\", \"c\"};\n" + " memcpy(dst, src, sizeof(src));\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void buffer_overrun_errorpath() { setMultiline(); Settings s = settings0; @@ -3789,40 +3800,40 @@ class TestBufferOverrun : public TestFixture { check("void f() {\n" " char a[10];\n" " char *p = a + 100;\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:17]: (portability) Undefined behaviour, pointer arithmetic 'a+100' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("char *f() {\n" " char a[10];\n" " return a + 100;\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:14]: (portability) Undefined behaviour, pointer arithmetic 'a+100' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("void f(int i) {\n" " char x[10];\n" " if (i == 123) {}\n" " dostuff(x+i);\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:4:14]: (portability) Undefined behaviour, when 'i' is 123 the pointer arithmetic 'x+i' is out of bounds. [pointerOutOfBoundsCond]\n", errout_str()); check("void f(int i) {\n" " char x[10];\n" " if (i == -1) {}\n" " dostuff(x+i);\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:4:14]: (portability) Undefined behaviour, when 'i' is -1 the pointer arithmetic 'x+i' is out of bounds. [pointerOutOfBoundsCond]\n", errout_str()); check("void f() {\n" // #6350 - fp when there is cast of buffer " wchar_t buf[64];\n" " p = (unsigned char *) buf + sizeof (buf);\n" - "}", dinit(CheckOptions, $.cpp = false)); + "}", settings0_p, false); ASSERT_EQUALS("", errout_str()); check("int f() {\n" " const char d[] = \"0123456789\";\n" " char *cp = d + 3;\n" " return cp - d;\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("", errout_str()); } @@ -3831,7 +3842,7 @@ class TestBufferOverrun : public TestFixture { " char *p = malloc(10);\n" " p += 100;\n" " free(p);" - "}"); + "}", settings0_p); TODO_ASSERT_EQUALS("[test.cpp:3]: (portability) Undefined behaviour, pointer arithmetic 'p+100' is out of bounds.\n", "", errout_str()); check("void f() {\n" @@ -3839,7 +3850,7 @@ class TestBufferOverrun : public TestFixture { " p += 10;\n" " *p = 0;\n" " free(p);" - "}"); + "}", settings0_p); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) p is out of bounds.\n", "", errout_str()); check("void f() {\n" @@ -3848,7 +3859,7 @@ class TestBufferOverrun : public TestFixture { " p -= 10;\n" " *p = 0;\n" " free(p);" - "}"); + "}", settings0_p); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -3857,7 +3868,7 @@ class TestBufferOverrun : public TestFixture { " p = p - 1;\n" " *p = 0;\n" " free(p);" - "}"); + "}", settings0_p); ASSERT_EQUALS("", errout_str()); } @@ -3865,7 +3876,7 @@ class TestBufferOverrun : public TestFixture { check("struct S { int a[10]; };\n" "void f(struct S *s) {\n" " int *p = s->a + 100;\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:19]: (portability) Undefined behaviour, pointer arithmetic 's->a+100' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("template class Vector\n" @@ -3881,36 +3892,36 @@ class TestBufferOverrun : public TestFixture { " const T* P2 = PDat + 1;\n" " const T* P1 = P2 - 1;\n" "}\n" - "Vector> Foo;\n"); + "Vector> Foo;\n", settings0_p); ASSERT_EQUALS("", errout_str()); } void pointer_out_of_bounds_4() { check("const char* f() {\n" " g(\"Hello\" + 6);\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("", errout_str()); check("const char* f() {\n" " g(\"Hello\" + 7);\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:2:15]: (portability) Undefined behaviour, pointer arithmetic '\"Hello\"+7' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("const char16_t* f() {\n" " g(u\"Hello\" + 6);\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("", errout_str()); check("const char16_t* f() {\n" " g(u\"Hello\" + 7);\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:2:16]: (portability) Undefined behaviour, pointer arithmetic 'u\"Hello\"+7' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("void f() {\n" // #4647 " int val = 5;\n" " std::string hi = \"hi\" + val;\n" " std::cout << hi << std::endl;\n" - "}\n"); + "}\n", settings0_p); ASSERT_EQUALS("[test.cpp:3:27]: (portability) Undefined behaviour, pointer arithmetic '\"hi\"+val' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("void f(const char* s, int len) {\n" // #11026 @@ -3920,7 +3931,7 @@ class TestBufferOverrun : public TestFixture { "void g() {\n" " f(\"a\", 1);\n" " f(\"bbb\", 3);\n" - "}\n"); + "}\n", settings0_p); ASSERT_EQUALS("", errout_str()); check("void f(int i, const char* a) {\n" // #11140 @@ -3933,14 +3944,14 @@ class TestBufferOverrun : public TestFixture { "void h() {\n" " for (int i = 0; \"012\"[i]; ++i)\n" " f(i, \"345\");\n" - "}\n"); + "}\n", settings0_p); ASSERT_EQUALS("", errout_str()); } void pointer_out_of_bounds_5() { // #10227 check("int foo(char str[6]) {\n" " return !((0 && *(\"STRING\" + 14) == 0) || memcmp(str, \"STRING\", 6) == 0);\n" - "}\n"); + "}\n", settings0_p); ASSERT_EQUALS("", errout_str()); } @@ -3950,26 +3961,26 @@ class TestBufferOverrun : public TestFixture { check("char *f() {\n" " char x[10];\n" " return x-1;\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:13]: (portability) Undefined behaviour, pointer arithmetic 'x-1' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("void f(int i) {\n" " char x[10];\n" " if (i == 123) {}\n" " dostuff(x-i);\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:4:14]: (portability) Undefined behaviour, when 'i' is 123 the pointer arithmetic 'x-i' is out of bounds. [pointerOutOfBoundsCond]\n", errout_str()); check("void f(int i) {\n" " char x[10];\n" " if (i == -20) {}\n" " dostuff(x-i);\n" - "}"); + "}", settings0_p); TODO_ASSERT_EQUALS("[test.cpp:4]: (portability) Undefined behaviour, when 'i' is -20 the pointer arithmetic 'x-i' is out of bounds.\n", "", errout_str()); check("void f(const char *x[10]) {\n" " return x-4;\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("", errout_str()); } @@ -4173,6 +4184,15 @@ class TestBufferOverrun : public TestFixture { " a[i] = NULL;\n" "}"); ASSERT_EQUALS("[test.cpp:4:6]: (error) Array 'a[2]' accessed at index 2, which is out of bounds. [arrayIndexOutOfBounds]\n", errout_str()); + + check("void f(const uint8_t* a) {\n" // 10421 + " uint8_t* p = (uint8_t*)malloc(20U * sizeof(uint8_t));\n" + " if (!p) return false;\n" + " for (uint8_t i = 1; i < 30; ++i)\n" + " p[i] = a[i];\n" + " free(p);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:10]: (error) Array 'p[20]' accessed at index 29, which is out of bounds. [arrayIndexOutOfBounds]\n", errout_str()); } // statically allocated buffer @@ -4600,6 +4620,41 @@ class TestBufferOverrun : public TestFixture { " mysprintf(a, \"abcd\");\n" "}", settings); ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" // #901 + " const char b[] = \"b\";\n" + " char a[1];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void g() {\n" + " const char* b = \"b\";\n" + " char a[1];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void h() {\n" + " const std::string b = \"b\";\n" + " char a[1];\n" + " sprintf(a, \"%s\", b.c_str());\n" + "}\n" + "void i() {\n" + " const char b[] = \"b\";\n" + " char a[2];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void j() {\n" + " const char* b = \"b\";\n" + " char a[2];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void k() {\n" + " const std::string b = \"b\";\n" + " char a[2];\n" + " sprintf(a, \"%s\", b.c_str());\n" + "}\n", settings0); + ASSERT_EQUALS("[test.cpp:4:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n" + "[test.cpp:9:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n" + "[test.cpp:14:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n", + errout_str()); } void minsize_mul() { @@ -5114,7 +5169,8 @@ class TestBufferOverrun : public TestFixture { void getErrorMessages() { // Ticket #2292: segmentation fault when using --errorlist - const Check& c = getCheck(); + CheckBufferOverrun check; + const Check& c = getCheck(check); c.getErrorMessages(this, nullptr); // we are not interested in the output - just consume it ignore_errout(); @@ -5287,14 +5343,14 @@ class TestBufferOverrun : public TestFixture { check("void f() {\n" " char arr[10];\n" " char *p = arr + 20;\n" - "}"); + "}", settings0_p); ASSERT_EQUALS("[test.cpp:3:19]: (portability) Undefined behaviour, pointer arithmetic 'arr+20' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("char(*g())[1];\n" // #7950 "void f() {\n" " int a[2];\n" " int* b = a + sizeof(*g());\n" - "}\n"); + "}\n", settings0_p); ASSERT_EQUALS("", errout_str()); } @@ -5307,9 +5363,9 @@ class TestBufferOverrun : public TestFixture { CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); - // Check code.. std::list fileInfo; - Check& c = getCheck(); + CheckBufferOverrun check; + Check& c = getCheck(check); fileInfo.push_back(c.getFileInfo(tokenizer, settings0, "")); c.analyseWholeProgram(*ctu, fileInfo, settings0, *this); // TODO: check result while (!fileInfo.empty()) { @@ -5351,6 +5407,15 @@ class TestBufferOverrun : public TestFixture { " f(a);\n" "}\n"); ASSERT_EQUALS("[test.cpp:7:12] -> [test.cpp:9:6] -> [test.cpp:3:12]: (error) Array index out of bounds; 'p' buffer size is 4 and it is accessed at offset 20. [ctuArrayIndex]\n", errout_str()); + + ctu("void bar(int *p) { p[4] = 42; }\n" // #13403 + "void f() {\n" + " int *p = (int*)malloc(4 * sizeof(int));\n" + " if (!p) return;\n" + " bar(p);\n" + " free(p);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:12] -> [test.cpp:4:9] -> [test.cpp:5:8] -> [test.cpp:1:20]: (error) Array index out of bounds; 'p' buffer size is 16 and it is accessed at offset 16. [ctuArrayIndex]\n", errout_str()); } void ctu_array() { @@ -5515,6 +5580,19 @@ class TestBufferOverrun : public TestFixture { " f(s);\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + setMultiline(); + ctu("void g(char* p) {\n" + " memset(p + 10, 0, 10);\n" + "}\n" + "void f() {\n" + " char a[10] = {};\n" + " g(a);\n" + "}"); + ASSERT_EQUALS("[test.cpp:2:12]: error: Pointer arithmetic overflow; 'p' buffer size is 10 [ctuPointerArith]\n" + "[test.cpp:6:6]: note: Calling function g, 1st argument is accessed out of bounds\n" + "[test.cpp:2:12]: note: Using argument p\n", + errout_str()); } void objectIndex() { diff --git a/test/testcheck.cpp b/test/testcheck.cpp index 8ea4cef38d8..3ae2cad3d8f 100644 --- a/test/testcheck.cpp +++ b/test/testcheck.cpp @@ -17,6 +17,7 @@ */ #include "check.h" +#include "checks.h" #include "fixture.h" #include @@ -28,23 +29,12 @@ class TestCheck : public TestFixture { private: void run() override { - TEST_CASE(instancesSorted); TEST_CASE(classInfoFormat); } - void instancesSorted() const { - for (auto i = Check::instances().cbegin(); i != Check::instances().cend(); ++i) { - auto j = i; - ++j; - if (j != Check::instances().cend()) { - ASSERT_EQUALS(true, (*i)->name() < (*j)->name()); - } - } - } - void classInfoFormat() const { - for (auto i = Check::instances().cbegin(); i != Check::instances().cend(); ++i) { - const std::string info = (*i)->classInfo(); + for (const Check * const c : CheckInstances::get()) { + const std::string info = c->classInfo(); if (!info.empty()) { ASSERT('\n' != info[0]); // No \n in the beginning ASSERT('\n' == info.back()); // \n at end diff --git a/test/testcheckersreport.cpp b/test/testcheckersreport.cpp new file mode 100644 index 00000000000..eafe7b8848f --- /dev/null +++ b/test/testcheckersreport.cpp @@ -0,0 +1,56 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2025 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "addoninfo.h" +#include "checkersreport.h" +#include "fixture.h" +#include "settings.h" + +class TestCheckersReport : public TestFixture { +public: + TestCheckersReport() : TestFixture("TestCheckersReport") {} + +private: + void run() final { + // AddonInfo::checkers + TEST_CASE(addonInfoCheckers); + } + + void addonInfoCheckers() const { + AddonInfo a; + a.name = "test"; + a.checkers["abcdefghijklmnopqrstuvwxyz::abcdefghijklmnopqrstuvwxyz"] = "123"; + Settings s; + s.addonInfos.emplace_back(a); + const std::set activeCheckers; + CheckersReport r(s, activeCheckers); + const std::string report = r.getReport(""); + const auto pos = report.rfind("\n\n"); + ASSERT(pos != std::string::npos); + + const char expected[] = + "test checkers\n" + "-------------\n" + "No abcdefghijklmnopqrstuvwxyz::abcdefghijklmnopqrstuvwxyz require:123\n"; + + ASSERT_EQUALS(expected, report.substr(pos+2)); + } +}; + +REGISTER_TEST(TestCheckersReport) diff --git a/test/testclangimport.cpp b/test/testclangimport.cpp index c67767db0ba..6a39b563982 100644 --- a/test/testclangimport.cpp +++ b/test/testclangimport.cpp @@ -1,5 +1,5 @@ // Cppcheck - A tool for static C/C++ code analysis -// Copyright (C) 2007-2025 Cppcheck team. +// Copyright (C) 2007-2026 Cppcheck team. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -1328,7 +1328,7 @@ class TestClangImport : public TestFixture { const Token *tok = Token::findsimplematch(tokenizer.tokens(), "\"hello\""); ASSERT(!!tok); ASSERT(!!tok->valueType()); - ASSERT_EQUALS("const signed char *", tok->valueType()->str()); + ASSERT_EQUALS("const char *", tok->valueType()->str()); } void stdinLoc() { diff --git a/test/testclass.cpp b/test/testclass.cpp index 04f298774d1..c1b801c208b 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -195,6 +195,7 @@ class TestClass : public TestFixture { TEST_CASE(const98); TEST_CASE(const99); TEST_CASE(const100); + TEST_CASE(const101); TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -734,6 +735,13 @@ class TestClass : public TestFixture { " void Two() = delete;\n" "};\n"); ASSERT_EQUALS("", errout_str()); + + checkDuplInheritedMembers("struct B { void f(); };\n" // #14583 + "struct D : B {\n" + " template \n" + " void f();\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } #define checkCopyConstructor(...) checkCopyConstructor_( __FILE__, __LINE__, __VA_ARGS__) @@ -6965,6 +6973,31 @@ class TestClass : public TestFixture { ASSERT_EQUALS("", errout_str()); // don't crash } + void const101() { + checkConst("struct error {\n" // #14450 + " error() = default;\n" + "};\n" + "struct S : U {\n" + " int f() { return this->error(); }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + checkConst("struct S {\n" // #14702 + " int i;\n" + " void f() {\n" + " S& r = *this;\n" + " r.i = 0;\n" + " }\n" + "};\n" + "struct T : std::array {\n" + " void g() {\n" + " for (int& r : *this)\n" + " r = 0;\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n" @@ -7741,6 +7774,19 @@ class TestClass : public TestFixture { " }\n" "};"); ASSERT_EQUALS("[test.cpp:8:10]: (style, inconclusive) Technically the member function 'Fred::f2' can be const. [functionConst]\n", errout_str()); + + checkConst("struct T {\n" // #14390 + " std::vector v;\n" + " void f() {\n" + " for (const auto& p : v)\n" + " *p = 0;\n" + " }\n" + " void g() {\n" + " for (auto* p : v)\n" + " *p = 0;\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void const_shared_ptr() { // #8674 @@ -8822,6 +8868,16 @@ class TestClass : public TestFixture { "};\n"); ASSERT_EQUALS("[test.cpp:2:14] -> [test.cpp:5:6]: (style) The destructor '~D' overrides a destructor in a base class but is not marked with a 'override' specifier. [missingOverride]\n", errout_str()); + + checkOverride("struct B {\n" // #14581 + " virtual void f();\n" + "};\n" + "struct D : B {\n" + " void f() override;\n" + " template \n" + " void f();\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void overrideCVRefQualifiers() { @@ -9222,7 +9278,8 @@ class TestClass : public TestFixture { void ctu(const std::vector &code) { - Check &check = getCheck(); + CheckClass checkClass; + Check &check = getCheck(checkClass); // getFileInfo std::list fileInfo; @@ -9274,8 +9331,8 @@ class TestClass : public TestFixture { SimpleTokenizer tokenizer(settings1, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - const Check& c = getCheck(); + CheckClass check; + const Check& c = getCheck(check); Check::FileInfo * fileInfo = (c.getFileInfo)(tokenizer, settings1, ""); delete fileInfo; diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 3b343cbc92e..135b7c782be 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,6 @@ #include "settings.h" #include "standards.h" #include "suppressions.h" -#include "timer.h" #include "utils.h" #include @@ -300,10 +299,14 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(suppressionsNoFile1); TEST_CASE(suppressionsNoFile2); TEST_CASE(suppressionsNoFile3); - TEST_CASE(suppressionSingle); - TEST_CASE(suppressionSingleFile); - TEST_CASE(suppressionTwo); - TEST_CASE(suppressionTwoSeparate); + TEST_CASE(suppressSingle); + TEST_CASE(suppressSingleFile); + TEST_CASE(suppressTwo); + TEST_CASE(suppressTwoSeparate); + TEST_CASE(exitcodeSuppressSingle); + TEST_CASE(exitcodeSuppressSingleFile); + TEST_CASE(exitcodeSuppressTwo); + TEST_CASE(exitcodeSuppressTwoSeparate); TEST_CASE(templates); TEST_CASE(templatesGcc); TEST_CASE(templatesVs); @@ -414,6 +417,7 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(ruleFileInvalidSeverity1); TEST_CASE(ruleFileInvalidSeverity2); TEST_CASE(ruleFileInvalidPattern); + TEST_CASE(ruleFileInvalidEngine); #else TEST_CASE(ruleFileNotSupported); #endif @@ -493,6 +497,8 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(safetyOverride); TEST_CASE(noSafety); TEST_CASE(noSafetyOverride); + TEST_CASE(debugAnalyzerinfo); + TEST_CASE(debugIpc); TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -1230,7 +1236,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--error-exitcode=", "file.cpp"}; // Fails since exit code not given ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void errorExitcodeStr() { @@ -1238,7 +1244,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--error-exitcode=foo", "file.cpp"}; // Fails since invalid exit code ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void exitcodeSuppressionsOld() { @@ -1389,7 +1395,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j", "file.cpp"}; // Fails since -j is missing thread count ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer (invalid_argument).\n", logger->str()); } void jobsInvalid() { @@ -1397,7 +1403,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j", "e", "file.cpp"}; // Fails since invalid count given for -j ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer (invalid_argument).\n", logger->str()); } void jobsNoJobs() { @@ -1427,7 +1433,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--max-configs=", "file.cpp"}; // Fails since --max-configs= is missing limit ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void maxConfigsInvalid() { @@ -1435,7 +1441,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--max-configs=e", "file.cpp"}; // Fails since invalid count given for --max-configs= ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void maxConfigsTooSmall() { @@ -1615,6 +1621,14 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("--cert-c-int-precision=12", settings->premiumArgs); } + void premiumOptionsCertCIntPrecisionInvalid() { + REDIRECT; + asPremium(); + const char * const argv[] = {"cppcheck", "--premium-cert-c-int-precision=abc", "file.c"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: argument to '--premium-cert-c-int-precision=' is not valid - not an integer (invalid_argument).\n", logger->str()); + } + void premiumOptionsLicenseFile() { REDIRECT; asPremium(); @@ -1666,7 +1680,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--report-progress=", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--report-progress=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--report-progress=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void reportProgress3() { @@ -1955,30 +1969,28 @@ class TestCmdlineParser : public TestFixture { return e; } - void suppressionSingle() { + void suppressSingle() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(true, supprs->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1))); } - void suppressionSingleFile() { + void suppressSingleFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar:file.cpp", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(true, supprs->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); } - void suppressionTwo() { + void suppressTwo() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar,noConstructor", "file.cpp"}; - TODO_ASSERT_EQUALS(static_cast(CmdLineParser::Result::Success), static_cast(CmdLineParser::Result::Fail), static_cast(parseFromArgs(argv))); - TODO_ASSERT_EQUALS(true, false, supprs->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); - TODO_ASSERT_EQUALS(true, false, supprs->nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); - TODO_ASSERT_EQUALS("", "cppcheck: error: Failed to add suppression. Invalid id \"uninitvar,noConstructor\"\n", logger->str()); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: Failed to add suppression. Invalid id \"uninitvar,noConstructor\"\n", logger->str()); } - void suppressionTwoSeparate() { + void suppressTwoSeparate() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "--suppress=noConstructor", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); @@ -1986,6 +1998,35 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(true, supprs->nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); } + void exitcodeSuppressSingle() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("uninitvar", "file.cpp", 1))); + } + + void exitcodeSuppressSingleFile() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar:file.cpp", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); + } + + void exitcodeSuppressTwo() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar,noConstructor", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: Failed to add suppression. Invalid id \"uninitvar,noConstructor\"\n", logger->str()); + } + + void exitcodeSuppressTwoSeparate() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar", "--exitcode-suppress=noConstructor", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); + } + void templates() { REDIRECT; const char * const argv[] = {"cppcheck", "--template={file}:{line},{severity},{id},{message}", "--template-location={file}:{line}:{column} {info}", "file.cpp"}; @@ -2139,7 +2180,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--xml", "--xml-version=a", "file.cpp"}; // FAils since unknown XML format version ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--xml-version=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--xml-version=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void doc() { @@ -2160,21 +2201,21 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=summary", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::SUMMARY); + ASSERT_EQUALS_ENUM(Settings::ShowTime::SUMMARY, settings->showtime); } void showtimeFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=file", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::FILE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::FILE, settings->showtime); } void showtimeFileTotal() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=file-total", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::FILE_TOTAL); + ASSERT_EQUALS_ENUM(Settings::ShowTime::FILE_TOTAL, settings->showtime); } void showtimeTop5() { @@ -2188,21 +2229,21 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=top5_file", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::TOP5_FILE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::TOP5_FILE, settings->showtime); } void showtimeTop5Summary() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=top5_summary", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::TOP5_SUMMARY); + ASSERT_EQUALS_ENUM(Settings::ShowTime::TOP5_SUMMARY, settings->showtime); } void showtimeNone() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=none", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::NONE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::NONE, settings->showtime); } void showtimeEmpty() { @@ -2362,7 +2403,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=seven"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iterations=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iterations=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void valueFlowMaxIterationsInvalid3() { @@ -2390,7 +2431,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--checks-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--checks-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--checks-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } #ifdef HAS_THREADING_MODEL_FORK @@ -2412,7 +2453,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-l", "one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-l' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-l' is not valid - not an integer (invalid_argument).\n", logger->str()); } #else void loadAverageNotSupported() { @@ -2449,7 +2490,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--max-ctu-depth=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-ctu-depth=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-ctu-depth=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void performanceValueflowMaxTime() { @@ -2463,7 +2504,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void performanceValueFlowMaxIfCount() { @@ -2477,7 +2518,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-if-count=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-if-count=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-if-count=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void templateMaxTime() { @@ -2491,7 +2532,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--template-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--template-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--template-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void templateMaxTimeInvalid2() { @@ -2512,7 +2553,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--typedef-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--typedef-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--typedef-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void typedefMaxTimeInvalid2() { @@ -2647,7 +2688,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--rule=.*\\", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parser->parseFromArgs(3, argv)); - ASSERT_EQUALS("cppcheck: error: failed to compile rule pattern '.*\\' (pcre_compile failed: \\ at end of pattern).\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: failed to compile rule pattern '.*\\' (\\ at end of pattern).\n", logger->str()); } #else void ruleNotSupported() { @@ -2664,6 +2705,7 @@ class TestCmdlineParser : public TestFixture { ScopedFile file("rule.xml", "\n" "\n" + "pcre\n" "raw\n" ".+\n" "\n" @@ -2686,12 +2728,14 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(2, settings->rules.size()); auto it = settings->rules.cbegin(); + ASSERT_EQUALS_ENUM(Regex::Engine::Pcre, it->engine); ASSERT_EQUALS("raw", it->tokenlist); ASSERT_EQUALS(".+", it->pattern); ASSERT_EQUALS_ENUM(Severity::error, it->severity); ASSERT_EQUALS("ruleId1", it->id); ASSERT_EQUALS("ruleSummary1", it->summary); ++it; + ASSERT_EQUALS_ENUM(Regex::Engine::Pcre, it->engine); ASSERT_EQUALS("define", it->tokenlist); ASSERT_EQUALS(".*", it->pattern); ASSERT_EQUALS_ENUM(Severity::warning, it->severity); @@ -2715,6 +2759,7 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(1, settings->rules.size()); auto it = settings->rules.cbegin(); + ASSERT_EQUALS_ENUM(Regex::Engine::Pcre, it->engine); ASSERT_EQUALS("define", it->tokenlist); ASSERT_EQUALS(".+", it->pattern); ASSERT_EQUALS_ENUM(Severity::error, it->severity); @@ -2882,7 +2927,19 @@ class TestCmdlineParser : public TestFixture { "\n"); const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parser->parseFromArgs(3, argv)); - ASSERT_EQUALS("cppcheck: error: unable to load rule-file 'rule.xml' - pattern '.+\\' failed to compile (pcre_compile failed: \\ at end of pattern).\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: unable to load rule-file 'rule.xml' - pattern '.+\\' failed to compile (\\ at end of pattern).\n", logger->str()); + } + + void ruleFileInvalidEngine() { + REDIRECT; + ScopedFile file("rule.xml", + "\n" + "llvm\n" + ".+\n" + "\n"); + const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: unknown regex engine 'llvm'.\n", logger->str()); } #else void ruleFileNotSupported() { @@ -3186,7 +3243,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--max-template-recursion=", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-template-recursion=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-template-recursion=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void emitDuplicates() { @@ -3424,6 +3481,20 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(false, settings->safety); } + void debugAnalyzerinfo() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--debug-analyzerinfo", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->debugainfo); + } + + void debugIpc() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--debug-ipc", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->debugipc); + } + void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"}; diff --git a/test/testcondition.cpp b/test/testcondition.cpp index d1ec9b1e17a..8172f74aab6 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,6 @@ #include "settings.h" #include -#include #include class TestCondition : public TestFixture { @@ -95,6 +94,8 @@ class TestCondition : public TestFixture { TEST_CASE(identicalConditionAfterEarlyExit); TEST_CASE(innerConditionModified); + TEST_CASE(overlappingInnerCondition); + TEST_CASE(clarifyCondition1); // if (a = b() < 0) TEST_CASE(clarifyCondition2); // if (a & b == c) TEST_CASE(clarifyCondition3); // if (! a & b) @@ -110,6 +111,8 @@ class TestCondition : public TestFixture { TEST_CASE(alwaysTrueContainer); TEST_CASE(alwaysTrueLoop); TEST_CASE(alwaysTrueTryCatch); + TEST_CASE(alwaysTrueSideEffect); + TEST_CASE(alwaysTruePremiumMisra); TEST_CASE(multiConditionAlwaysTrue); TEST_CASE(duplicateCondition); @@ -146,8 +149,8 @@ class TestCondition : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Run checks.. - runChecks(tokenizer, this); + CheckCondition check; + runChecks(check, tokenizer, this); } #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) @@ -159,8 +162,8 @@ class TestCondition : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Run checks.. - runChecks(tokenizer, this); + CheckCondition check; + runChecks(check, tokenizer, this); } void assignAndCompare() { @@ -524,7 +527,8 @@ class TestCondition : public TestFixture { SimpleTokenizer tokenizer(settings1, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - runChecks(tokenizer, this); + CheckCondition check; + runChecks(check, tokenizer, this); } void multicompare() { @@ -2673,6 +2677,18 @@ class TestCondition : public TestFixture { check("void f1(const std::string &s) { if(s.size() >= 0) if(s.empty()) {}} "); // CheckOther says: Unsigned expression 's.size()' can't be negative so it is unnecessary to test it. [unsignedPositive] ASSERT_EQUALS("", errout_str()); + check("void f1(const std::string &s) { if(42 < s.size()) if(s.empty()) {}}"); + ASSERT_EQUALS("[test.cpp:1:39] -> [test.cpp:1:61]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); + + check("void f1(const std::string &s) { if(s.empty()) if(42 < s.size()) {}}"); + ASSERT_EQUALS("[test.cpp:1:43] -> [test.cpp:1:53]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); + + check("void f(const std::string& s, int n) {\n" // #14716 + " if (s.size() < n)\n" + " if (s.empty()) {}\n" + "}"); + ASSERT_EQUALS("", errout_str()); + // TODO: These are identical condition since size cannot be negative check("void f1(const std::string &s) { if(s.size() <= 0) if(s.empty()) {}}"); ASSERT_EQUALS("", errout_str()); @@ -2819,6 +2835,30 @@ class TestCondition : public TestFixture { " }\n" "}"); ASSERT_EQUALS("", errout_str()); + + check("void f(const int* p, const int* e) {\n" // #14595 + " for (; p;) {\n" + " if (p == e) {}\n" + " if (p) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:4:13]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", errout_str()); + + check("int f(const int *q, const int *s) {\n" // #14711 + " if (*q && *s)\n" + " return *q;\n" + " return 0;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int x, int y) {\n" + " int a[] = { x, y };\n" + " if (a[0] == 1) {\n" + " if (a[0] == 1) {}\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:3:14] -> [test.cpp:4:18]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", + errout_str()); } void identicalConditionAfterEarlyExit() { @@ -3005,6 +3045,31 @@ class TestCondition : public TestFixture { " }\n" "}"); ASSERT_EQUALS("", errout_str()); + + check("void g(int[]);\n" // #14724 + "void f(int a[]) {\n" + " if (a[0] == 1) {\n" + " g(a);\n" + " if (a[0] == 1) {}\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); + } + + void overlappingInnerCondition() { + check("void f(int x) {\n" + " if (x == 1) {\n" + " if (x & 7) {}\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:15]: (warning) Overlapping inner 'if' condition is always true. [overlappingInnerCondition]\n", errout_str()); + + check("void f(int x) {\n" + " if (x & 7) {\n" + " if (x == 1) {}\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); } // clarify conditions with = and comparison @@ -4600,11 +4665,7 @@ class TestCondition : public TestFixture { " if (o[1] == '\\0') {}\n" " }\n" "}\n"); - if (std::numeric_limits::is_signed) { - ASSERT_EQUALS("[test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } else { - ASSERT_EQUALS("[test.cpp:4:25] -> [test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } + ASSERT_EQUALS("[test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" // #11449 " int i = x;\n" @@ -4678,7 +4739,7 @@ class TestCondition : public TestFixture { " }\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:18]: (style) Condition 'S::s' is always true [knownConditionTrueFalse]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:18]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", errout_str()); check("void f() {\n" // #10811 " int i = 0;\n" @@ -4805,6 +4866,51 @@ class TestCondition : public TestFixture { " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" // #14392 + " bool g() const { return m; }\n" + " bool m{};\n" + "};\n" + "bool f(S s) {\n" + " if (s.g()) {\n" + " bool b = s.g();\n" + " return b;\n" + " }\n" + " return false;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:12] -> [test.cpp:7:21]: (style) Assigned value 's.g()' is always true [knownConditionTrueFalse]\n", errout_str()); + + check("void f(const void* p) {\n" // #11519 + " bool b = false;\n" + " if (!p && !b) {}\n" + " if (!b) {}\n" + " (void)b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:15]: (style) Condition '!b' is always true [knownConditionTrueFalse]\n" + "[test.cpp:4:9]: (style) Condition '!b' is always true [knownConditionTrueFalse]\n", + errout_str()); + + check("struct C {\n" // #12532 + " void f() const;\n" + " int a, b;\n" + "};\n" + "void C::f() const {\n" + " if (a)\n" + " return;\n" + " if (!b) {}\n" + " if (a) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:9] -> [test.cpp:9:9]: (warning) Identical condition 'a', second condition is always false [identicalConditionAfterEarlyExit]\n", + errout_str()); + + check("bool b() { return false; }\n" // #10452 + "void f() {\n" + " if (b()) {}\n" + " if (!b()) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) Condition 'b()' is always false [knownConditionTrueFalse]\n" + "[test.cpp:4:9]: (style) Condition '!b()' is always true [knownConditionTrueFalse]\n", + errout_str()); } void alwaysTrueSymbolic() @@ -5038,6 +5144,46 @@ class TestCondition : public TestFixture { " if (i < 0) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct A { int x; int y; };" + "void use(int);\n" + "void test(A a) {\n" + " int i = a.x;\n" + " int j = a.x;\n" + " use(j);\n" + " if (i == j) {}\n" + " if (i == a.x) {}\n" + " if (j == a.x) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:6:11]: (style) Condition 'i==j' is always true [knownConditionTrueFalse]\n" + "[test.cpp:7:11]: (style) Condition 'i==a.x' is always true [knownConditionTrueFalse]\n" + "[test.cpp:8:11]: (style) Condition 'j==a.x' is always true [knownConditionTrueFalse]\n", + errout_str()); + + check("struct S { int i; };\n" // #12795 + "struct T {\n" + " std::map m;\n" + " S* get(const std::string& s) { return m[s]; }\n" + " void modify() { for (const auto& e : m) e.second->i = 0; }\n" + "};\n" + "void f(T& t) {\n" + " const S* p = t.get(\"abc\");\n" + " const int o = p->i;\n" + " t.modify();\n" + " if (p->i == o) {}\n" + "}\n"); + TODO_ASSERT_EQUALS("", + "[test.cpp:11:14]: (style) Condition 'p->i==o' is always true [knownConditionTrueFalse]\n", + errout_str()); + + check("void f(int x) {\n" // #12320 + " int a = 0, b = 0, c = 0;\n" + " a = x;\n" + " if (a) b = x;\n" + " if (b) c = x;\n" + " if (c) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void alwaysTrueInfer() { @@ -5340,11 +5486,7 @@ class TestCondition : public TestFixture { " buffer.back() == '\\n' ||\n" " buffer.back() == '\\0') {}\n" "}\n"); - if (std::numeric_limits::is_signed) { - ASSERT_EQUALS("[test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } else { - ASSERT_EQUALS("[test.cpp:3:22] -> [test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } + ASSERT_EQUALS("[test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); // #9353 check("struct X { std::string s; };\n" @@ -5608,6 +5750,32 @@ class TestCondition : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void alwaysTrueSideEffect() { + check("bool check(const char* const);\n" // #14416 + "void create(const char*);\n" + "void f(const char* n) {\n" + " if (!check(n)) {\n" + " create(n);\n" + " if (check(n)) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void alwaysTruePremiumMisra() { + const char code[] = "void f() {\n" + " if (3 > 2) {}\n" + "}"; + + check(code); + ASSERT_EQUALS("", errout_str()); + + Settings misraSettings; + misraSettings.premiumArgs = "--misra-c-2012"; + check(code, misraSettings); + ASSERT_EQUALS("[test.cpp:2:9]: (style) Condition '3>2' is always true [knownConditionTrueFalse]\n", errout_str()); + } + void multiConditionAlwaysTrue() { check("void f() {\n" " int val = 0;\n" @@ -5882,6 +6050,28 @@ class TestCondition : public TestFixture { " if (strlen(s2) > 0) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void g(int*);\n" // #14428 + "int f(int* const p) {\n" + " int i = 0;\n" + " if (*p == 0)\n" + " g(p);\n" + " if (*p == 0)\n" + " i = 1;\n" + " return i;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void g(const int*);\n" + "int f(const int* const p) {\n" + " int i = 0;\n" + " if (*p == 0)\n" + " g(p);\n" + " if (*p == 0)\n" + " i = 1;\n" + " return i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:12] -> [test.cpp:6:12]: (style) The if condition is the same as the previous if condition [duplicateCondition]\n", errout_str()); } void checkInvalidTestForOverflow() { @@ -6239,28 +6429,24 @@ class TestCondition : public TestFixture { check("void f(const unsigned char u) {\n" " if (u > 0) {}\n" - " if (u < 0) {}\n" // warn - " if (u >= 0) {}\n" // warn + " if (u < 0) {}\n" + " if (u >= 0) {}\n" " if (u <= 0) {}\n" " if (u > 255) {}\n" // warn " if (u < 255) {}\n" " if (u >= 255) {}\n" " if (u <= 255) {}\n" // warn " if (0 < u) {}\n" - " if (0 > u) {}\n" // warn - " if (0 <= u) {}\n" // warn + " if (0 > u) {}\n" + " if (0 <= u) {}\n" " if (0 >= u) {}\n" " if (255 < u) {}\n" // warn " if (255 > u) {}\n" " if (255 <= u) {}\n" " if (255 >= u) {}\n" // warn "}\n", settingsUnix64); - ASSERT_EQUALS("[test.cpp:3:14]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always false. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:4:14]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always true. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:6:14]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n" + ASSERT_EQUALS("[test.cpp:6:14]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n" "[test.cpp:9:14]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always true. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:11:9]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always false. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:12:9]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always true. [compareValueOutOfTypeRangeError]\n" "[test.cpp:14:9]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n" "[test.cpp:17:9]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always true. [compareValueOutOfTypeRangeError]\n", errout_str()); @@ -6270,6 +6456,35 @@ class TestCondition : public TestFixture { "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:14]: (style) Comparing expression of type 'bool' against value 2. Condition is always true. [compareValueOutOfTypeRangeError]\n", errout_str()); + + check("void f(const std::uint32_t& u) {\n" // #9078 + " if (u >= UINT32_MAX) {}\n" + " if (u <= UINT32_MAX) {}\n" + " if (u > UINT32_MAX) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:14]: (style) Comparing expression of type 'const unsigned int &' against value 4294967295. Condition is always true. [compareValueOutOfTypeRangeError]\n" + "[test.cpp:4:13]: (style) Comparing expression of type 'const unsigned int &' against value 4294967295. Condition is always false. [compareValueOutOfTypeRangeError]\n", + errout_str()); + + check("void f() {\n" + " long long ll = 1024 * 1024 * 1024;\n" + " if (ll * 8 < INT_MAX) {}\n" + " if (INT_MAX > ll * 8) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("bool f(int a, int b) {\n" // #12896 + " if (a < INT_MIN && b > INT_MAX)\n" + " return true;\n" + " return false;\n" + "}\n" + "bool g(int x) {\n" // #6796 + " return (x > INT_MAX) ? true : false;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:13]: (style) Comparing expression of type 'signed int' against value -2147483648. Condition is always false. [compareValueOutOfTypeRangeError]\n" + "[test.cpp:2:28]: (style) Comparing expression of type 'signed int' against value 2147483647. Condition is always false. [compareValueOutOfTypeRangeError]\n" + "[test.cpp:7:17]: (style) Comparing expression of type 'signed int' against value 2147483647. Condition is always false. [compareValueOutOfTypeRangeError]\n", + errout_str()); } void knownConditionCast() { diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 54af2d0a1c3..0eb91ba8cca 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -92,6 +92,7 @@ class TestConstructors : public TestFixture { TEST_CASE(noConstructor13); // #9998 TEST_CASE(noConstructor14); // #10770 TEST_CASE(noConstructor15); // #5499 + TEST_CASE(noConstructor16); TEST_CASE(forwardDeclaration); // ticket #4290/#3190 @@ -758,6 +759,46 @@ class TestConstructors : public TestFixture { ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'C::i2' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } + void noConstructor16() { + check("struct S {\n" // #14546 + " int a = 0, b;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:16]: (warning) Member variable 'S::b' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + + check("struct S {\n" + " int a, b;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" + " explicit S(int);\n" + " S(const S&);\n" + " int i;\n" + "};\n" + "struct T {\n" + " S s;\n" + " int j{};\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + const char code[] = "struct S { int i = 0; };\n" // #14697 + "struct T {\n" + " S s;\n" + " int j;\n" + "};\n" + "struct U {\n" + " std::string a;\n" + " int k;\n" + "};\n"; + const Settings s = settingsBuilder(settings).cpp(Standards::CPP11).build(); + check(code, s); + ASSERT_EQUALS("", errout_str()); + check(code); + ASSERT_EQUALS("[test.cpp:4:9]: (warning) Member variable 'T::j' has no initializer. [uninitMemberVarNoCtor]\n" + "[test.cpp:8:9]: (warning) Member variable 'U::k' has no initializer. [uninitMemberVarNoCtor]\n", + errout_str()); + } + // ticket #4290 "False Positive: style (noConstructor): The class 'foo' does not have a constructor." // ticket #3190 "SymbolDatabase: Parse of sub class constructor fails" void forwardDeclaration() { diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index 2de32efb022..84db6db6c28 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -618,7 +618,7 @@ class TestCppcheck : public TestFixture { // the internal errorlist is cleared after each check() call ASSERT_EQUALS(1, errorLogger.errmsgs.size()); auto it = errorLogger.errmsgs.cbegin(); - ASSERT_EQUALS("test.cpp:0:0: information: The configuration 'X' was not checked because its code equals another one. [purgedConfiguration]", + ASSERT_EQUALS("test.cpp:0:0: information: The configuration 'X=X' was not checked because its code equals another one. [purgedConfiguration]", it->toString(false, templateFormat, "")); } diff --git a/test/testerrorlogger.cpp b/test/testerrorlogger.cpp index 42537ca36fb..23b3233995c 100644 --- a/test/testerrorlogger.cpp +++ b/test/testerrorlogger.cpp @@ -51,7 +51,10 @@ class TestErrorLogger : public TestFixture { TEST_CASE(ErrorMessageConstructLocations); TEST_CASE(ErrorMessageVerbose); TEST_CASE(ErrorMessageVerboseLocations); + TEST_CASE(ErrorMessageVerboseSymbol); + TEST_CASE(ErrorMessageVerboseNewline); TEST_CASE(ErrorMessageFromInternalError); + TEST_CASE(ErrorMessageCode); TEST_CASE(CustomFormat); TEST_CASE(CustomFormat2); TEST_CASE(CustomFormatLocations); @@ -284,6 +287,27 @@ class TestErrorLogger : public TestFixture { ASSERT_EQUALS("[foo.cpp:5] -> [bar.cpp:8]: (error) Verbose error", msg.toString(true, templateFormat, "")); } + void ErrorMessageVerboseSymbol() const { + std::list locs(1, fooCpp5); + ErrorMessage msg(std::move(locs), "", Severity::error, "$symbol:sym\nProgramming error with $symbol.\nVerbose error about $symbol", "errorId", Certainty::normal); + ASSERT_EQUALS(1, msg.callStack.size()); + ASSERT_EQUALS("Programming error with sym.", msg.shortMessage()); + ASSERT_EQUALS("Verbose error about sym", msg.verboseMessage()); + ASSERT_EQUALS("[foo.cpp:5]: (error) Programming error with sym.", msg.toString(false, templateFormat, "")); + ASSERT_EQUALS("[foo.cpp:5]: (error) Verbose error about sym", msg.toString(true, templateFormat, "")); + ASSERT_EQUALS("sym\n", msg.symbolNames()); + } + + void ErrorMessageVerboseNewline() const { + std::list locs(1, fooCpp5); + ErrorMessage msg(std::move(locs), "", Severity::error, "Programming error.\nVerbose error\nEven more verbose", "errorId", Certainty::normal); + ASSERT_EQUALS(1, msg.callStack.size()); + ASSERT_EQUALS("Programming error.", msg.shortMessage()); + ASSERT_EQUALS("Verbose error\nEven more verbose", msg.verboseMessage()); + ASSERT_EQUALS("[foo.cpp:5]: (error) Programming error.", msg.toString(false, templateFormat, "")); + ASSERT_EQUALS("[foo.cpp:5]: (error) Verbose error\nEven more verbose", msg.toString(true, templateFormat, "")); + } + void ErrorMessageFromInternalError() const { // TODO: test with token { @@ -337,10 +361,31 @@ class TestErrorLogger : public TestFixture { testReportType(ReportType::misraCpp2023, Severity::style, "premium-misra-cpp-2023-dir-0.3.2", "Required", "Dir 0.3.2"); testReportType(ReportType::misraCpp2008, Severity::style, "premium-misra-cpp-2008-3-4-1", "Required", "3-4-1"); testReportType(ReportType::misraC2012, Severity::style, "premium-misra-c-2012-dir-4.6", "Advisory", "Dir 4.6"); + testReportType(ReportType::misraC2012, Severity::style, "premium-misra-c-2012-10.4-positive-number", "Required", "10.4"); + testReportType(ReportType::misraC2012, Severity::style, "premium-misra-c-2012-10.4", "Required", "10.4"); testReportType(ReportType::misraC2012, Severity::style, "misra-c2012-dir-4.6", "Advisory", "Dir 4.6"); testReportType(ReportType::certC, Severity::error, "resourceLeak", "L3", "FIO42-C"); } + void ErrorMessageCode() const { + ScopedFile file("code.cpp", + "int i;\n" + "int i2;\n" + "int i3;\n" + ); + + ErrorMessage::FileLocation codeCpp3_5{"code.cpp", 3, 5}; + std::list locs = { codeCpp3_5 }; + ErrorMessage msg(std::move(locs), "", Severity::error, "Programming error.\nVerbose error", "errorId", Certainty::normal); + ASSERT_EQUALS(1, msg.callStack.size()); + ASSERT_EQUALS("Programming error.", msg.shortMessage()); + ASSERT_EQUALS("Verbose error", msg.verboseMessage()); + ASSERT_EQUALS("code.cpp:3:5: error: Programming error. [errorId]\n" + "int i3;\n" + " ^", + msg.toString(false, "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\n{code}", "")); + } + void CustomFormat() const { std::list locs(1, fooCpp5); ErrorMessage msg(std::move(locs), "", Severity::error, "Programming error.\nVerbose error", "errorId", Certainty::normal); @@ -554,7 +599,7 @@ class TestErrorLogger : public TestFixture { "0 " "0 "; ErrorMessage msg; - ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid CWE ID - not an integer"); + ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid CWE ID - not an integer (invalid_argument)"); } { // invalid hash @@ -570,7 +615,7 @@ class TestErrorLogger : public TestFixture { "0 " "0 "; ErrorMessage msg; - ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid hash - not an integer"); + ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid hash - not an integer (invalid_argument)"); } { // out-of-range CWE ID diff --git a/test/testexceptionsafety.cpp b/test/testexceptionsafety.cpp index 753a1ddd454..46c995c231b 100644 --- a/test/testexceptionsafety.cpp +++ b/test/testexceptionsafety.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,8 +75,8 @@ class TestExceptionSafety : public TestFixture { SimpleTokenizer tokenizer(settings1, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check char variable usage.. - runChecks(tokenizer, this); + CheckExceptionSafety check; + runChecks(check, tokenizer, this); } void destructors() { @@ -356,6 +356,21 @@ class TestExceptionSafety : public TestFixture { check("const char *func() noexcept { return 0; }\n" "const char *func1() noexcept { try { throw 1; } catch(...) {} return 0; }"); ASSERT_EQUALS("", errout_str()); + + check("struct A {\n" // #14526 + " void f(int = 0, int = 1) { throw 0; }\n" + "};\n" + "void g() noexcept {\n" + " A a;\n" + " a.f();\n" + "}\n" + "void h() noexcept {\n" + " A a;\n" + " a.f(1, 3);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:7]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" + "[test.cpp:10:7]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", + errout_str()); } void nothrowThrow() { @@ -518,6 +533,15 @@ class TestExceptionSafety : public TestFixture { " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(int i) {\n" // #9380 + " throw i;\n" + "}\n" + "int main() {\n" + " f(123);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n", + errout_str()); } }; diff --git a/test/testexecutor.cpp b/test/testexecutor.cpp index a0e5e02f1fb..30b2b834834 100644 --- a/test/testexecutor.cpp +++ b/test/testexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index 6aa4e6534a2..9ddb4c1f43c 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -86,6 +86,7 @@ class TestFunctions : public TestFixture { TEST_CASE(checkMissingReturn5); TEST_CASE(checkMissingReturn6); // #13180 TEST_CASE(checkMissingReturn7); // #14370 - FN try/catch + TEST_CASE(checkMissingReturnStdInt); // #14482 - FN std::int32_t // std::move for locar variable TEST_CASE(returnLocalStdMove1); @@ -131,7 +132,8 @@ class TestFunctions : public TestFixture { SimpleTokenizer tokenizer(s, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - runChecks(tokenizer, this); + CheckFunctions check; + runChecks(check, tokenizer, this); } void prohibitedFunctions_posix() { @@ -221,7 +223,7 @@ class TestFunctions : public TestFixture { "}"); ASSERT_EQUALS( "[test.cpp:2:22]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead. [indexCalled]\n" - "[test.cpp:2:37]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead. [indexCalled]\n", // duplicate + "[test.cpp:2:37]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead. [indexCalled]\n", errout_str()); } @@ -760,6 +762,13 @@ class TestFunctions : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); + check("char* f() {\n" // #14715 + " char a[3] = { 'a', 'b', 'c' };\n" + " *a = 0;\n" + " return strdup(a);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + check("size_t f() { wchar_t x = L'x'; return wcslen(&x); }"); ASSERT_EQUALS("[test.cpp:1:46]: (error) Invalid wcslen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); @@ -1918,6 +1927,11 @@ class TestFunctions : public TestFixture { ASSERT_EQUALS("[test.cpp:3:19]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); } + void checkMissingReturnStdInt() {// #14482 - FN + check("std::int32_t f() {}\n"); + ASSERT_EQUALS("[test.cpp:1:19]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); + } + // NRVO check void returnLocalStdMove1() { check("struct A{}; A f() { A var; return std::move(var); }"); @@ -2214,6 +2228,12 @@ class TestFunctions : public TestFixture { " return b;\n" "}\n", s); TODO_ASSERT_EQUALS("", "[test.cpp:6:5]: (debug) auto token with no type. [autoNoType]\n", errout_str()); + + check("template \n" // #13509 + "void f(const T& t) {\n" + " t.g();\n" + "}\n", s); + ASSERT_EQUALS("", errout_str()); } void checkUseStandardLibrary1() { diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index 2bfb1283587..289b22b284e 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ */ #include "check.h" +#include "checks.h" #include "errortypes.h" #include "fixture.h" #include "helpers.h" @@ -258,6 +259,8 @@ class TestGarbage : public TestFixture { TEST_CASE(garbageCode227); TEST_CASE(garbageCode228); TEST_CASE(garbageCode229); + TEST_CASE(garbageCode230); + TEST_CASE(garbageCode231); TEST_CASE(garbageCodeFuzzerClientMode1); // test cases created with the fuzzer client, mode 1 @@ -283,8 +286,8 @@ class TestGarbage : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // call all "runChecks" in all registered Check classes - for (auto it = Check::instances().cbegin(); it != Check::instances().cend(); ++it) { - (*it)->runChecks(tokenizer, this); + for (Check * const c : CheckInstances::get()) { + c->runChecks(tokenizer, this); } return tokenizer.tokens()->stringifyList(false, false, false, true, false, nullptr, nullptr); @@ -318,7 +321,6 @@ class TestGarbage : public TestFixture { void final_class_x() { - const char code[] = "class __declspec(dllexport) x final { };"; SimpleTokenizer tokenizer(settings, *this); ASSERT(tokenizer.tokenize(code)); @@ -847,7 +849,7 @@ class TestGarbage : public TestFixture { } void garbageCode95() { // #6804 - ASSERT_THROW_INTERNAL(checkCode("{ } x x ; { } h h [ ] ( ) ( ) { struct x ( x ) ; int __attribute__ ( ) f ( ) { h - > first = & x ; struct x * n = h - > first ; ( ) n > } }"), AST); // do not crash + ASSERT_THROW_INTERNAL(checkCode("{ } x x ; { } h h [ ] ( ) ( ) { struct x ( x ) ; int __attribute__ ( ) f ( ) { h - > first = & x ; struct x * n = h - > first ; ( ) n > } }"), SYNTAX); // do not crash } void garbageCode96() { // #6807 @@ -1342,6 +1344,8 @@ class TestGarbage : public TestFixture { "{ return return { | { - name3 1 enum != >= 1 >= ++ { name6 | ; ++}}}}}}}"), UNKNOWN_MACRO); ASSERT_THROW_INTERNAL(checkCode("else return % name5 name2 - =name1 return enum | { - name3 1 enum != >= 1 >= ++ { { || " "{ return return { | { - name3 1 enum != >= 1 >= ++ { { || ; ++}}}}}}}}"), UNKNOWN_MACRO); + + ASSERT_THROW_INTERNAL(checkCode("f(*p, requires(x));"), AST); // #14740 } void templateSimplifierCrashes() { @@ -1771,6 +1775,12 @@ class TestGarbage : public TestFixture { ASSERT_THROW_INTERNAL(checkCode("void f() {} [[maybe_unused]]"), SYNTAX); ASSERT_THROW_INTERNAL(checkCode("void f() {} [[unused]]"), SYNTAX); } + void garbageCode230() { // #14432 + ASSERT_THROW_INTERNAL(checkCode("e U U,i"), SYNTAX); + } + void garbageCode231() { + ASSERT_THROW_INTERNAL(checkCode("char char* [] = {\"a\" \"b\"}"), SYNTAX); + } void syntaxErrorFirstToken() { @@ -1889,6 +1899,12 @@ class TestGarbage : public TestFixture { // #13892 ASSERT_NO_THROW(checkCode("void foovm(int x[const *]);")); + + // #14676 + ASSERT_NO_THROW(checkCode("int main() {\n" + " auto value = m[1 + qRow<>];\n" + "}\n")); + ignore_errout(); } }; diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index 799f31d1bec..6f8633dbeea 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,17 +28,20 @@ #include #include #include +#include #include #include #include -class TestImporter : public ImportProject { +class TestImporter final : public ImportProject { public: using ImportProject::importCompileCommands; using ImportProject::importCppcheckGuiProject; using ImportProject::importVcxproj; using ImportProject::SharedItemsProject; using ImportProject::collectArgs; + using ImportProject::fsSetDefines; + using ImportProject::fsSetIncludePaths; }; @@ -83,21 +86,22 @@ class TestImportProject : public TestFixture { TEST_CASE(testCollectArgs5); TEST_CASE(testCollectArgs6); TEST_CASE(testCollectArgs7); + TEST_CASE(testVcxprojConditions); } void setDefines() const { FileSettings fs{"test.cpp", Standards::Language::CPP, 0}; - ImportProject::fsSetDefines(fs, "A"); + TestImporter::fsSetDefines(fs, "A"); ASSERT_EQUALS("A=1", fs.defines); - ImportProject::fsSetDefines(fs, "A;B;"); + TestImporter::fsSetDefines(fs, "A;B;"); ASSERT_EQUALS("A=1;B=1", fs.defines); - ImportProject::fsSetDefines(fs, "A;;B;"); + TestImporter::fsSetDefines(fs, "A;;B;"); ASSERT_EQUALS("A=1;B=1", fs.defines); - ImportProject::fsSetDefines(fs, "A;;B"); + TestImporter::fsSetDefines(fs, "A;;B"); ASSERT_EQUALS("A=1;B=1", fs.defines); } @@ -105,7 +109,7 @@ class TestImportProject : public TestFixture { FileSettings fs{"test.cpp", Standards::Language::CPP, 0}; std::list in(1, "../include"); std::map variables; - ImportProject::fsSetIncludePaths(fs, "abc/def/", in, variables); + TestImporter::fsSetIncludePaths(fs, "abc/def/", in, variables); ASSERT_EQUALS(1U, fs.includePaths.size()); ASSERT_EQUALS("abc/include/", fs.includePaths.front()); } @@ -115,7 +119,7 @@ class TestImportProject : public TestFixture { std::list in(1, "$(SolutionDir)other"); std::map variables; variables["SolutionDir"] = "c:/abc/"; - ImportProject::fsSetIncludePaths(fs, "/home/fred", in, variables); + TestImporter::fsSetIncludePaths(fs, "/home/fred", in, variables); ASSERT_EQUALS(1U, fs.includePaths.size()); ASSERT_EQUALS("c:/abc/other/", fs.includePaths.front()); } @@ -125,7 +129,7 @@ class TestImportProject : public TestFixture { std::list in(1, "$(SOLUTIONDIR)other"); std::map variables; variables["SolutionDir"] = "c:/abc/"; - ImportProject::fsSetIncludePaths(fs, "/home/fred", in, variables); + TestImporter::fsSetIncludePaths(fs, "/home/fred", in, variables); ASSERT_EQUALS(1U, fs.includePaths.size()); ASSERT_EQUALS("c:/abc/other/", fs.includePaths.front()); } @@ -371,8 +375,8 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS(2, importer.fileSettings.size()); const FileSettings &fs1 = importer.fileSettings.front(); const FileSettings &fs2 = importer.fileSettings.back(); - ASSERT_EQUALS(0, fs1.fileIndex); - ASSERT_EQUALS(1, fs2.fileIndex); + ASSERT_EQUALS(0, fs1.file.fsFileId()); + ASSERT_EQUALS(1, fs2.file.fsFileId()); } void importCompileCommands14() const { // #14156 @@ -478,6 +482,7 @@ class TestImportProject : public TestFixture { " \n" " \n" " \n" + " gcc-macros.h\n" " \n" " \n" " \n" @@ -493,6 +498,8 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS("cli/", project.guiProject.pathNames[0]); ASSERT_EQUALS(1, s.includePaths.size()); ASSERT_EQUALS("lib/", s.includePaths.front()); + ASSERT_EQUALS(1, s.userIncludes.size()); + ASSERT_EQUALS("gcc-macros.h", s.userIncludes.front()); ASSERT_EQUALS(true, s.inlineSuppressions); } @@ -680,28 +687,38 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS("Missing closing quote in command string", error); } + void testVcxprojConditions() const + { + ASSERT(cppcheck::testing::evaluateVcxprojCondition("'$(Configuration)'=='Debug'", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition("'$(Platform)'=='Win32'", "Debug", "Win32")); + ASSERT(!cppcheck::testing::evaluateVcxprojCondition("'$(Configuration)'=='Release'", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' == 'Debug' ", "Debug", "Win32")); + ASSERT(!cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' != 'Debug' ", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition("'$(Configuration)|$(Platform)' == 'Debug|Win32' ", "Debug", "Win32")); + ASSERT(!cppcheck::testing::evaluateVcxprojCondition("!('$(Configuration)|$(Platform)' == 'Debug|Win32' )", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' == 'Debug' And '$(Platform)' == 'Win32'", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' == 'Debug' Or '$(Platform)' == 'Win32'", "Release", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.StartsWith('Debug'))", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.EndsWith('AddressSanitizer'))", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.Contains('Address'))", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.Contains ( 'Address' ) )", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.Contains('Address')) And '$(Platform)' == 'Win32'", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" ($(Configuration.Contains('Address')) ) And ( '$(Platform)' == 'Win32')", "Debug-AddressSanitizer", "Win32")); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("And", "", ""), std::runtime_error, "Invalid condition: 'And'"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("Or", "", ""), std::runtime_error, "Invalid condition: 'Or'"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("!", "", ""), std::runtime_error, "Invalid condition: '!'"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '' And ", "", ""), std::runtime_error, "Missing operator"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("('' == ''", "", ""), std::runtime_error, "'(' without closing ')'!"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '')", "", ""), std::runtime_error, "unmatched ')' in condition '' == '')"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("''", "", ""), std::runtime_error, "Invalid condition: ''''"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '", "", ""), std::runtime_error, "Can not tokenize condition"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("$(Configuration.Lower())", "", ""), std::runtime_error, "Missing operator"); + // invalid expression in => no error. We are ok with that as long as we don't crash + ASSERT(!cppcheck::testing::evaluateVcxprojCondition("' ' && ' '", "", "")); + } + // TODO: test fsParseCommand() - // TODO: test vcxproj conditions - /* - - - - - Debug - x64 - - - - - CPPCHECKLIB_IMPORT - - - - - - - */ }; REGISTER_TEST(TestImportProject) diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp index 7a1fbdb2dab..3d8f5d4d713 100644 --- a/test/testincompletestatement.cpp +++ b/test/testincompletestatement.cpp @@ -750,6 +750,14 @@ class TestIncompleteStatement : public TestFixture { " g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct S;\n" // #14664 + "S* a[1];\n" + "void f() {\n" + " a[0];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:6]: (warning) Redundant code: Found unused array access. [constStatement]\n", + errout_str()); } void vardecl() { diff --git a/test/testinternal.cpp b/test/testinternal.cpp index 009129c5dc1..10431adcd38 100644 --- a/test/testinternal.cpp +++ b/test/testinternal.cpp @@ -56,8 +56,8 @@ class TestInternal : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckInternal check; + runChecks(check, tokenizer, this); } void simplePatternInTokenMatch() { diff --git a/test/testio.cpp b/test/testio.cpp index b402f5c0aa1..d3344f76b8d 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -113,7 +113,8 @@ class TestIO : public TestFixture { checkIO.checkWrongPrintfScanfArguments(); return; } - runChecks(tokenizer, this); + CheckIO check; + runChecks(check, tokenizer, this); } void coutCerrMisusage() { @@ -544,7 +545,29 @@ class TestIO : public TestFixture { " FILE *a = fopen(\"aa\", \"r\");\n" " while (fclose(a)) {}\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:3:5]: (error) Used file that is not opened. [useClosedFile]\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:3:12]: (warning) fclose() used as loop condition may skip loop body or double-close file handle. [fcloseInLoopCondition]\n", errout_str()); + + check("void foo() {\n" + " FILE *a = fopen(\"aa\", \"r\");\n" + " while (fclose(a)) {\n" + " break;\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo() {\n" + " FILE *a = fopen(\"aa\", \"r\");\n" + " while (fclose(a)) {\n" + " a = fopen(\"aa\", \"r\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo() {\n" + " FILE *a = fopen(\"aa\", \"r\");\n" + " do {} while (fclose(a));\n" + "}"); + ASSERT_EQUALS("[test.cpp:3:18]: (warning) fclose() used as loop condition may skip loop body or double-close file handle. [fcloseInLoopCondition]\n", errout_str()); // #6823 check("void foo() {\n" @@ -3371,6 +3394,20 @@ class TestIO : public TestFixture { "}"); ASSERT_EQUALS("", errout_str()); + check("enum E : uint8_t { E0 }; \n" // #7959 + "void f(E e) {\n" + " printf(\"%hhu\", e);\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("enum E : uint8_t { E0 }; \n" + "void f(E e) {\n" + " printf(\"%lu\", e);\n" + "}"); + TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) %lu in format string (no. 1) requires 'unsigned long' but the argument type is 'uint8_t'.\n", + "", + errout_str()); + check("void f() {\n" " printf(\"%lu\", sizeof(char));\n" "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); @@ -4800,6 +4837,13 @@ class TestIO : public TestFixture { " wscanf_s(L\"%4[^-]\", msStr1, _countof(msStr1));\n" "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("", errout_str()); + + check("void f(const char* c) {\n" + " const size_t N = 5;\n" + " char buf[N];\n" + " sscanf_s(c, \"%4[^.]\", buf, N);\n" + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win64)); + ASSERT_EQUALS("", errout_str()); } void testQStringFormatArguments() { diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 7aa64c1cd3c..265e31bf3c2 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -154,6 +154,7 @@ class TestLeakAutoVar : public TestFixture { TEST_CASE(ifelse27); TEST_CASE(ifelse28); // #11038 TEST_CASE(ifelse29); + TEST_CASE(ifelse30); // switch TEST_CASE(switch1); @@ -225,23 +226,17 @@ class TestLeakAutoVar : public TestFixture { template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { const Settings& settings1 = options.s ? *options.s : settings; - - // Tokenize.. - SimpleTokenizer tokenizer(settings1, *this, options.cpp); - ASSERT_LOC(tokenizer.tokenize(code), file, line); - - // Check for leaks.. - runChecks(tokenizer, this); + check_(file, line, code, settings1, options.cpp); } template - void check_(const char* file, int line, const char (&code)[size], const Settings & s) { + void check_(const char* file, int line, const char (&code)[size], const Settings & s, bool cpp = true) { // Tokenize.. - SimpleTokenizer tokenizer(s, *this); + SimpleTokenizer tokenizer(s, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for leaks.. - runChecks(tokenizer, this); + CheckLeakAutoVar check; + runChecks(check, tokenizer, this); } void assign1() { @@ -641,6 +636,14 @@ class TestLeakAutoVar : public TestFixture { " x = p != nullptr ? p : nullptr;\n" "}", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); + + check("void f(const char* n) {\n" // #12724 + " FILE* fp = fopen(n, \"r\");\n" + " bool b = (fp == NULL);\n" + " if (b)\n" + " return;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("[test.cpp:6:1]: (error) Resource leak: fp [resourceLeak]\n", errout_str()); } void memcpy1() { // #11542 @@ -2382,6 +2385,22 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("", errout_str()); // don't crash } + void ifelse30() { + check("void f(void** pp) {\n" // #14709 + " void* p = malloc(8);\n" + " if ((void*)p == 0)\n" + " return;\n" + " *pp = p;\n" + "}\n" + "void g(void** pp) {\n" + " void* p = malloc(8);\n" + " if (static_cast(p) == 0)\n" + " return;\n" + " *pp = p;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("", errout_str()); + } + void switch1() { check("void f() {\n" " char *p = 0;\n" @@ -3247,8 +3266,8 @@ class TestLeakAutoVarRecursiveCountLimit : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check for leaks.. - runChecks(tokenizer, this); + CheckLeakAutoVar check; + runChecks(check, tokenizer, this); } void run() override { @@ -3294,8 +3313,8 @@ class TestLeakAutoVarStrcpy : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for leaks.. - runChecks(tokenizer, this); + CheckLeakAutoVar check; + runChecks(check, tokenizer, this); } void run() override { @@ -3399,8 +3418,8 @@ class TestLeakAutoVarWindows : public TestFixture { SimpleTokenizer tokenizer(settings, *this, false); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for leaks.. - runChecks(tokenizer, this); + CheckLeakAutoVar check; + runChecks(check, tokenizer, this); } void run() override { @@ -3472,8 +3491,8 @@ class TestLeakAutoVarPosix : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for leaks.. - runChecks(tokenizer, this); + CheckLeakAutoVar check; + runChecks(check, tokenizer, this); } void run() override { diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index a2f9526162c..8cbe5b50019 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -167,7 +167,7 @@ class TestMathLib : public TestFixture { ASSERT_EQUALS("1", MathLib::calculate("0", "1", '^')); // Unknown action should throw exception - ASSERT_THROW_INTERNAL_EQUALS(MathLib::calculate("1","2",'j'),INTERNAL, "Unexpected action 'j' in MathLib::calculate(). Please report this to Cppcheck developers."); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::calculate("1","2",'j'),INTERNAL, "Unexpected action 'j' in MathLib::calculate()."); } void calculate1() const { diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 406f46de902..1ed88120886 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -150,6 +150,7 @@ class TestMemleakInFunction : public TestFixture { TEST_CASE(realloc22); TEST_CASE(realloc23); TEST_CASE(realloc24); // #9228 + TEST_CASE(realloc25); } void realloc1() { @@ -418,6 +419,60 @@ class TestMemleakInFunction : public TestFixture { "}"); ASSERT_EQUALS("", errout_str()); } + + void realloc25() { + check("struct T {\n" + " char* ptr;\n" + " size_t len;\n" + "};\n" + "struct S {\n" + " struct T t;\n" + "};\n" + "void f(struct S* s, size_t len) {\n" + " char* p = s->t.ptr;\n" + " p = realloc(p, len);\n" + " if (p) {\n" + " s->t.ptr = p;\n" + " s->t.len = len;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct T {\n" + " char* ptr;\n" + " size_t len;\n" + "};\n" + "struct S {\n" + " struct T t[1];\n" + "};\n" + "void f(struct S* s, size_t len) {\n" + " char* p = s->t[0].ptr;\n" + " p = realloc(p, len);\n" + " if (p) {\n" + " s->t[0].ptr = p;\n" + " s->t[0].len = len;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct T {\n" // #14718 + " char* ptr;\n" + " size_t len;\n" + "};\n" + "struct S {\n" + " struct T t;\n" + "};\n" + "char* get(struct T t) { return t.ptr; };\n" + "void f(struct S* s, size_t len) {\n" + " char* p = get(s->t);\n" + " p = realloc(p, len);\n" + " if (p) {\n" + " s->t.ptr = p;\n" + " s->t.len = len;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } }; REGISTER_TEST(TestMemleakInFunction) @@ -1674,6 +1729,7 @@ class TestMemleakStructMember : public TestFixture { TEST_CASE(assign3); TEST_CASE(assign4); // #11019 TEST_CASE(assign5); + TEST_CASE(assign6); // Failed allocation TEST_CASE(failedAllocation); @@ -1683,6 +1739,7 @@ class TestMemleakStructMember : public TestFixture { TEST_CASE(function3); // #3024: kernel list TEST_CASE(function4); // #3038: Deallocating in function TEST_CASE(function5); // #10381, #10382, #10158 + TEST_CASE(function6); // Handle if-else TEST_CASE(ifelse); @@ -1955,6 +2012,15 @@ class TestMemleakStructMember : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void assign6() { + check("struct S { S* p; };\n" // #14524 + "void f() {\n" + " S s;\n" + " s.p = static_cast(malloc(sizeof(S)));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:1]: (error) Memory leak: s.p [memleak]\n", errout_str()); + } + void failedAllocation() { check("static struct ABC * foo()\n" "{\n" @@ -2054,7 +2120,33 @@ class TestMemleakStructMember : public TestFixture { " }\n" " return g(&a);\n" "}\n"); - TODO_ASSERT_EQUALS("", "[test.cpp:9:9]: (error) Memory leak: a.str [memleak]\n", errout_str()); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int *p; };\n" + "S f(int i) {\n" + " S s;\n" + " switch(i) {\n" + " case 1:\n" + " s.p = new int;\n" + " break;\n" + " default: {\n" + " return {};\n" + " }\n" + " }\n" + " return s;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void function6() { + check("struct S { int* p; };\n" // #14706 + "void g(void*);\n" + "void f() {\n" + " S* s = new S();\n" + " s->p = new int();\n" + " g((void*)s);\n" + "}"); + ASSERT_EQUALS("", errout_str()); } void ifelse() { @@ -2752,6 +2844,18 @@ class TestMemleakNoVar : public TestFixture { " if (std::freopen(NULL, \"w+b\", fp2) == NULL) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" // #14172 + " if (malloc(4) == nullptr) {}\n" + " if (::malloc(4) == nullptr) {}\n" + " if (std::malloc(4) == nullptr) {}\n" + " if (::std::malloc(4) == nullptr) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n" + "[test.cpp:3:11]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n" + "[test.cpp:4:14]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n" + "[test.cpp:5:16]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n", + errout_str()); } void smartPointerFunctionParam() { diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 1eb01edfcce..a154bd0d9c2 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +37,7 @@ class TestNullPointer : public TestFixture { private: const Settings settings = settingsBuilder().library("std.cfg").severity(Severity::warning).build(); + const Settings settings_i = settingsBuilder(settings).certainty(Certainty::inconclusive).build(); void run() override { mNewTemplate = true; @@ -183,20 +184,23 @@ class TestNullPointer : public TestFixture { { bool inconclusive = false; bool cpp = true; - Standards::cstd_t cstd = Standards::CLatest; }; #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { - const Settings settings1 = settingsBuilder(settings).certainty(Certainty::inconclusive, options.inconclusive).c(options.cstd).build(); + const Settings& settings1 = options.inconclusive ? settings_i : settings; + check_(file, line, code, settings1, options.cpp); + } + template + void check_(const char* file, int line, const char (&code)[size], const Settings& s, bool cpp = true) { // Tokenize.. - SimpleTokenizer tokenizer(settings1, *this, options.cpp); + SimpleTokenizer tokenizer(s, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for null pointer dereferences.. - runChecks(tokenizer, this); + CheckNullPointer check; + runChecks(check, tokenizer, this); } #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) @@ -207,8 +211,8 @@ class TestNullPointer : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check for null pointer dereferences.. - runChecks(tokenizer, this); + CheckNullPointer check; + runChecks(check, tokenizer, this); } @@ -995,6 +999,14 @@ class TestNullPointer : public TestFixture { "char f(S* s) { return s->p ? 'a' : s->p->c; }\n"); ASSERT_EQUALS("[test.cpp:2:24] -> [test.cpp:2:37]: (warning) Either the condition 's->p' is redundant or there is possible null pointer dereference: s->p. [nullPointerRedundantCheck]\n", errout_str()); + + check("int f(const int a[]) {\n" // #14544 + " int i = 0;\n" + " if (!a)\n" + " a = &i;\n" + " return *a;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void nullpointer5() { @@ -1330,7 +1342,8 @@ class TestNullPointer : public TestFixture { check(code); // C++ file => nullptr means NULL ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: i [nullPointer]\n", errout_str()); - check(code, dinit(CheckOptions, $.cpp = false, $.cstd = Standards::C17)); // C17 file => nullptr does not mean NULL + const Settings s = settingsBuilder(settings).c(Standards::C17).build(); + check(code, s, false); // C17 file => nullptr does not mean NULL ASSERT_EQUALS("", errout_str()); check(code, dinit(CheckOptions, $.cpp = false)); @@ -2458,6 +2471,14 @@ class TestNullPointer : public TestFixture { " if (h(i) && *i == 1) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(int i) {\n" // #13797 + " int* p = nullptr;\n" + " if (!i) {\n" + " *p = 0;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); } void nullpointer78() // #7802 @@ -3473,8 +3494,7 @@ class TestNullPointer : public TestFixture { " printf(\"%s\", s);\n" "}"); ASSERT_EQUALS( - "[test.cpp:3:18]: (error) Null pointer dereference: s [nullPointer]\n" - "[test.cpp:3:18]: (error) Null pointer dereference [nullPointer]\n", + "[test.cpp:3:18]: (error) Null pointer dereference: s [nullPointer]\n", errout_str()); check("void f() {\n" @@ -3498,8 +3518,7 @@ class TestNullPointer : public TestFixture { " printf(\"%u%s\", 123, s);\n" "}"); ASSERT_EQUALS( - "[test.cpp:3:25]: (error) Null pointer dereference: s [nullPointer]\n" - "[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n", + "[test.cpp:3:25]: (error) Null pointer dereference: s [nullPointer]\n", errout_str()); @@ -3544,16 +3563,14 @@ class TestNullPointer : public TestFixture { " sscanf(s, \"%s\", 0);\n" "}"); ASSERT_EQUALS( - "[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f() {\n" " scanf(\"%d\", 0);\n" "}"); ASSERT_EQUALS( - "[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* foo) {\n" @@ -3574,9 +3591,7 @@ class TestNullPointer : public TestFixture { " sscanf(dummy, \"%d\", iVal);\n" "}"); ASSERT_EQUALS( - "[test.cpp:3:25]: (error) Null pointer dereference: iVal [nullPointer]\n" - "[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:3:25]: (error) Null pointer dereference: iVal [nullPointer]\n", errout_str()); check("void f(char *dummy) {\n" @@ -3595,8 +3610,7 @@ class TestNullPointer : public TestFixture { " sscanf(dummy, \"%*d%u\", 0);\n" "}"); ASSERT_EQUALS( - "[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n", errout_str()); } @@ -3701,6 +3715,26 @@ class TestNullPointer : public TestFixture { " i++;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(const int* p) {\n" // #6710 + " for (int i = *p; i < 5; ++i) {}\n" + " if (p) {}\n" + "}\n" + "struct S { int a; };\n" + "void g(const S* s) {\n" + " for (int i = s->a; i < 5; ++i) {}\n" + " if (s) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:19]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" + "[test.cpp:8:9] -> [test.cpp:7:18]: (warning) Either the condition 's' is redundant or there is possible null pointer dereference: s. [nullPointerRedundantCheck]\n", + errout_str()); + + check("struct S { int a; };\n" // #6492 + "void h(const S* s) {\n" + " for (int i = s->a; s; ++i) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:24] -> [test.cpp:3:18]: (warning) Either the condition 's' is redundant or there is possible null pointer dereference: s. [nullPointerRedundantCheck]\n", + errout_str()); } void nullpointerDeadCode() { @@ -3779,6 +3813,21 @@ class TestNullPointer : public TestFixture { " g(x);\n" "}"); ASSERT_EQUALS("", errout_str()); + + check("struct T {\n" // #14308 + " bool b{};\n" + " T* next{};\n" + "};\n" + "bool g(const T*& r) {\n" + " const T* t = r;\n" + " r = t->next;\n" + " return t->b;\n" + "}\n" + "void f(const T* tok) {\n" + " if (g(tok)) {}\n" + " if (tok) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void nullpointerExit() { @@ -3929,7 +3978,8 @@ class TestNullPointer : public TestFixture { " std::string s(p);\n" " return s;\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:6:17]: (warning, inconclusive) Possible null pointer dereference: p [nullPointer]\n", + errout_str()); check("void f() {\n" // #11078 " const char* p = nullptr;\n" @@ -4301,8 +4351,7 @@ class TestNullPointer : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - std::list null; - CheckNullPointer::parseFunctionCall(*xtok, null, library); + const std::list null = CheckNullPointer::parseFunctionCall(*xtok, library); ASSERT_EQUALS(0U, null.size()); } @@ -4320,8 +4369,7 @@ class TestNullPointer : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - std::list null; - CheckNullPointer::parseFunctionCall(*xtok, null, library); + const std::list null = CheckNullPointer::parseFunctionCall(*xtok, library); ASSERT_EQUALS(1U, null.size()); ASSERT_EQUALS("a", null.front()->str()); } @@ -4644,9 +4692,9 @@ class TestNullPointer : public TestFixture { CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); - // Check code.. + CheckNullPointer check; + Check& c = getCheck(check); std::list fileInfo; - Check& c = getCheck(); fileInfo.push_back(c.getFileInfo(tokenizer, settings, "")); c.analyseWholeProgram(*ctu, fileInfo, settings, *this); // TODO: check result while (!fileInfo.empty()) { @@ -4776,6 +4824,15 @@ class TestNullPointer : public TestFixture { "[test.cpp:5:20]: note: Assignment 'f=fopen(notexist,t)', assigned value is 0\n" "[test.cpp:6:8]: note: Calling function foo, 1st argument is null\n" "[test.cpp:2:13]: note: Dereferencing argument f that is null\n", errout_str()); + + ctu("void g(std::optional& o) {\n" // #14728 + " *o = 1;\n" + "}\n" + "void f() {\n" + " std::optional x = 0;\n" + " g(x);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } }; diff --git a/test/testoptions.cpp b/test/testoptions.cpp index 7c72b2de336..0dec04927e4 100644 --- a/test/testoptions.cpp +++ b/test/testoptions.cpp @@ -35,9 +35,8 @@ class TestOptions : public TestFixture { TEST_CASE(which_test); TEST_CASE(which_test_method); TEST_CASE(no_test_method); - TEST_CASE(not_quiet); + TEST_CASE(defaults); TEST_CASE(quiet); - TEST_CASE(not_help); TEST_CASE(help); TEST_CASE(help_long); TEST_CASE(multiple_testcases); @@ -45,54 +44,65 @@ class TestOptions : public TestFixture { TEST_CASE(invalid_switches); TEST_CASE(summary); TEST_CASE(dry_run); + TEST_CASE(exclude_tests); + TEST_CASE(timer_results); } void which_test() const { const char* argv[] = {"./test_runner", "TestClass"}; options args(getArrayLength(argv), argv); - ASSERT(std::set {"TestClass"} == args.which_test()); + const std::map> expected{ + { "TestClass", {} } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void which_test_method() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod"}; options args(getArrayLength(argv), argv); - ASSERT(std::set {"TestClass::TestMethod"} == args.which_test()); + const std::map> expected{ + { "TestClass", {"TestMethod"} } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void no_test_method() const { const char* argv[] = {"./test_runner"}; options args(getArrayLength(argv), argv); - ASSERT(std::set {""} == args.which_test()); + const std::map> expected{}; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } - void not_quiet() const { - const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-v"}; + void defaults() const { + const char* argv[] = {"./test_runner", "TestClass::TestMethod"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(false, args.quiet()); + ASSERT_EQUALS(false, args.help()); + ASSERT_EQUALS(true, args.summary()); + ASSERT_EQUALS(false, args.dry_run()); + ASSERT_EQUALS(false, args.exclude_tests()); + ASSERT(args.errors().empty()); } - void quiet() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-q"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.quiet()); + ASSERT(args.errors().empty()); } - void not_help() const { - const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-v"}; - options args(getArrayLength(argv), argv); - ASSERT_EQUALS(false, args.help()); - } - - void help() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-h"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.help()); + ASSERT(args.errors().empty()); } @@ -100,40 +110,69 @@ class TestOptions : public TestFixture { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "--help"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.help()); + ASSERT(args.errors().empty()); } void multiple_testcases() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass::AnotherTestMethod"}; options args(getArrayLength(argv), argv); - std::set expected {"TestClass::TestMethod", "TestClass::AnotherTestMethod"}; - ASSERT(expected == args.which_test()); + const std::map> expected{ + { "TestClass", { "TestMethod", "AnotherTestMethod" } } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void multiple_testcases_ignore_duplicates() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass"}; options args(getArrayLength(argv), argv); - std::set expected {"TestClass"}; - ASSERT(expected == args.which_test()); + const std::map> expected{ + { "TestClass", {} } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void invalid_switches() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-a", "-v", "-q"}; options args(getArrayLength(argv), argv); - std::set expected {"TestClass::TestMethod"}; - ASSERT(expected == args.which_test()); + const std::map> expected { + { "TestClass", { "TestMethod" } } + }; + ASSERT(expected == args.which_tests()); ASSERT_EQUALS(true, args.quiet()); + ASSERT_EQUALS(2, args.errors().size()); + auto it = args.errors().cbegin(); + ASSERT_EQUALS("unknown option '-a'", *it); + ++it; + ASSERT_EQUALS("unknown option '-v'", *it); } void summary() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-n"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(false, args.summary()); + ASSERT(args.errors().empty()); } void dry_run() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-d"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.dry_run()); + ASSERT(args.errors().empty()); + } + + void exclude_tests() const { + const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-x"}; + options args(getArrayLength(argv), argv); + ASSERT_EQUALS(true, args.exclude_tests()); + ASSERT(args.errors().empty()); + } + + void timer_results() const { + const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-t"}; + options args(getArrayLength(argv), argv); + ASSERT(!!args.timer_results()); } }; diff --git a/test/testother.cpp b/test/testother.cpp index 964abceca78..9a18a067231 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -121,6 +121,9 @@ class TestOther : public TestFixture { TEST_CASE(varScope41); // #11845 TEST_CASE(varScope42); TEST_CASE(varScope43); + TEST_CASE(varScope44); + TEST_CASE(varScope45); + TEST_CASE(varScope46); TEST_CASE(oldStylePointerCast); TEST_CASE(intToPointerCast); @@ -197,6 +200,7 @@ class TestOther : public TestFixture { TEST_CASE(duplicateExpression18); TEST_CASE(duplicateExpression19); TEST_CASE(duplicateExpression20); + TEST_CASE(duplicateExpression21); TEST_CASE(duplicateExpressionLoop); TEST_CASE(duplicateValueTernary); TEST_CASE(duplicateValueTernarySizeof); // #13773 @@ -261,6 +265,7 @@ class TestOther : public TestFixture { TEST_CASE(testUnusedLabel); TEST_CASE(testUnusedLabelConfiguration); TEST_CASE(testUnusedLabelSwitchConfiguration); + TEST_CASE(testUnusedLabelPremiumMisra); TEST_CASE(testEvaluationOrder); TEST_CASE(testEvaluationOrderSelfAssignment); @@ -300,6 +305,8 @@ class TestOther : public TestFixture { TEST_CASE(moveForRange); TEST_CASE(moveTernary); TEST_CASE(movePointerAlias); + TEST_CASE(moveOutparam); + TEST_CASE(moveTryEmplace); TEST_CASE(funcArgNamesDifferent); TEST_CASE(funcArgOrderDifferent); @@ -352,10 +359,6 @@ class TestOther : public TestFixture { } else { settings = opt.settings; - settings->severity.enable(Severity::style); - settings->severity.enable(Severity::warning); - settings->severity.enable(Severity::portability); - settings->severity.enable(Severity::performance); } settings->certainty.setEnabled(Certainty::inconclusive, opt.inconclusive); settings->verbose = opt.verbose; @@ -364,8 +367,8 @@ class TestOther : public TestFixture { SimpleTokenizer tokenizer(*settings, *this, opt.cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckOther check; + runChecks(check, tokenizer, this); } struct CheckPOptions @@ -381,8 +384,8 @@ class TestOther : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check.. - runChecks(tokenizer, this); + CheckOther check; + runChecks(check, tokenizer, this); } template @@ -1792,7 +1795,7 @@ class TestOther : public TestFixture { void varScope39() { check("struct S {\n" // #12405 - " void f(const std::string&) const;\n" + " void f(const std::string& s) const;\n" " const int* g(std::string&) const;\n" "};\n" "void h(int);\n" @@ -1948,6 +1951,100 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:3:12]: (style) The scope of the variable 'x' can be reduced. [variableScope]\n", errout_str()); } + void varScope44() { // #14496 + check("char* f() {\n" + " char* p = nullptr;\n" + " {\n" + " p = strdup(\"abc\");\n" + " if (p) {\n" + " return p;\n" + " }\n" + " }\n" + " return nullptr;\n" + "}\n" + "char* g() {\n" + " char* q = NULL;\n" + " {\n" + " q = strdup(\"abc\");\n" + " if (q) {\n" + " return q;\n" + " }\n" + " }\n" + " return nullptr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:11]: (style) The scope of the variable 'p' can be reduced. [variableScope]\n" + "[test.cpp:12:11]: (style) The scope of the variable 'q' can be reduced. [variableScope]\n", + errout_str()); + } + + void varScope45() { + check("void g(int x, int y) {\n" // #14497 + " int a = x, b = y;\n" + " if (a) {}\n" + " else {\n" + " if (b) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:16]: (style) The scope of the variable 'b' can be reduced. [variableScope]\n", errout_str()); + } + + void varScope46() { + check("void f() {\n" // #7091 + " int y1;\n" + " for (int i = 0; i < 3; ++i) {\n" + " for(int j = 0; j < 3; ++j) {\n" + " y1 = 2 * 1;\n" + " y1 += 1;\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'y1' can be reduced. [variableScope]\n", + errout_str()); + + check("bool f() {\n" + "bool b = false;\n" + "do {\n" + " switch (g()) {\n" + " case 0:\n" + " b = true;\n" + " break;\n" + " case 1:\n" + " return b;\n" + " break;\n" + " default:\n" + " break;\n" + " }\n" + "}\n" + "while (true);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " int y1 = 0;\n" + " for (int i = 0; i < 3; ++i) {\n" + " for(int j = 0; j < 3; ++j) {\n" + " y1 = y1 + 1;\n" + " dostuff(y1);\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int& r) {\n" // #14566 + " int i = 0;\n" + " while (g()) {\n" + " {\n" + " if (g()) {\n" + " i = 0;" + " std::swap(i, r);\n" + " }\n" + " }\n" + " }\n" + " use(i);" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + #define checkOldStylePointerCast(...) checkOldStylePointerCast_(__FILE__, __LINE__, __VA_ARGS__) template void checkOldStylePointerCast_(const char* file, int line, const char (&code)[size], Standards::cppstd_t std = Standards::CPPLatest) { @@ -2341,7 +2438,7 @@ class TestOther : public TestFixture { checkInvalidPointerCast("void test(float* data) {\n" " f.write((char*)data,sizeof(float));\n" "}", dinit(CheckInvalidPointerCastOptions, $.inconclusive = true)); // #3639 - ASSERT_EQUALS("[test.cpp:2:13]: (portability, inconclusive) Casting from float * to signed char * is not portable due to different binary data representations on different platforms. [invalidPointerCast]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:13]: (portability, inconclusive) Casting from float * to char * is not portable due to different binary data representations on different platforms. [invalidPointerCast]\n", errout_str()); checkInvalidPointerCast("long long* test(float* f) {\n" @@ -2666,7 +2763,9 @@ class TestOther : public TestFixture { check("void f(std::string str) {\n" " std::string s2 = str;\n" "}"); - ASSERT_EQUALS("[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:17]: (performance, inconclusive) Use const reference for 's2' to avoid unnecessary data copying. [redundantCopyLocalConst]\n" + "[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", + errout_str()); check("void f(std::string str) {\n" " std::string& s2 = str;\n" @@ -2784,11 +2883,11 @@ class TestOther : public TestFixture { "};\n" "void f(X x) {}"; - /*const*/ Settings s32 = settingsBuilder(settings0).platform(Platform::Type::Unix32).build(); + /*const*/ Settings s32 = settingsBuilder(settings1).platform(Platform::Type::Unix32).build(); check(code, dinit(CheckOptions, $.settings = &s32)); ASSERT_EQUALS("[test.cpp:5:10]: (performance) Function parameter 'x' should be passed by const reference. [passedByValue]\n", errout_str()); - /*const*/ Settings s64 = settingsBuilder(settings0).platform(Platform::Type::Unix64).build(); + /*const*/ Settings s64 = settingsBuilder(settings1).platform(Platform::Type::Unix64).build(); check(code, dinit(CheckOptions, $.settings = &s64)); ASSERT_EQUALS("", errout_str()); } @@ -2812,6 +2911,9 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); check("struct X { int a[5]; }; void f(const X v);"); + ASSERT_EQUALS("", errout_str()); + + check("struct X { int a[5]; }; void f(const X v) { (void) v; }"); ASSERT_EQUALS("[test.cpp:1:40]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); check("extern \"C\" { struct X { int a[5]; }; void f(const X v); }"); @@ -3525,7 +3627,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -3546,7 +3648,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&) noexcept;\n" + " explicit D(int& i) noexcept;\n" "\n" "private:\n" " C c;\n" @@ -3566,7 +3668,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -3587,7 +3689,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -3608,7 +3710,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -4010,6 +4112,35 @@ class TestOther : public TestFixture { " if (*pp) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("class C {\n" + "public:\n" + " explicit C(const std::string s);\n" + "private:\n" + " std::string _s;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int& r) {\n" // #9761 + " o1 = r;\n" + "}\n" + "boost::optional o2;\n" + "void g(int& r) {\n" + " o2 = r;\n" + "}\n" + "struct T {\n" + " int* p;\n" + " T& operator=(int& rhs) { p = &rhs; return *this; }\n" + "};\n" + "void h(T& t, int& r) {\n" + " t = r;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(std::optional& o) {\n" + " *o = 1;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void constParameterCallback() { @@ -4051,6 +4182,16 @@ class TestOther : public TestFixture { " S s2{ cb };\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:11] -> [test.cpp:2:21]: (performance) Function parameter 's' should be passed by const reference. However it seems that 'cb' is a callback function. [passedByValueCallback]\n", errout_str()); + + check("struct S {\n" // #14696 + " explicit S(std::string s = {}) {}\n" + "};\n" + "struct T {\n" + " explicit T(std::string* s = {}) {}\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:28]: (performance) Function parameter 's' should be passed by const reference. [passedByValue]\n" + "[test.cpp:5:29]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constPointer() { @@ -4640,6 +4781,89 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:1:18]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:18]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("using fp_t = int (*)(int*);\n" // #14510 + "fp_t g_fp;\n" + "struct S { fp_t m_fp; };\n" + "void g(fp_t);\n" + "S f(S* s) {\n" + " g_fp = [](int* p) { return *p; };\n" + " s->m_fp = [](int* p) { return *p; };\n" + " g([](int* p) { return *p; });\n" + " auto x = [](int* p) { return *p; };\n" + " g(x);\n" + " return { [](int* p) { return *p; } };\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " int i = 0;\n" + " auto x = [&]() { int* p = &i; if (*p) {} };\n" + " x();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:27]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n", errout_str()); + + check("int f() {\n" + " int i = 0;\n" + " return [](int* p) { return *p; }(&i);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:20]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S {\n" // #14571 + " char* c;\n" + "};\n" + "struct T {\n" + " S s;\n" + "};\n" + "void f(std::string* p, T& t) {\n" + " S& r = t.s;\n" + " strcpy(r.c, p->c_str());\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7:21]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S {\n" // #14559 + " int gc() const;\n" + " int gnc();\n" + "};\n" + "int f1(S* s) {\n" + " return h(s ? s->gc() : 1);\n" + "}\n" + "int f2(S* s) {\n" + " return h(s ? s->gnc() : 1);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:11]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("using IntPtr = int *;\n" + "int* foo(IntPtr bar) {\n" + " return bar = 0;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int x; };\n" // #14700 + "int f(S* s) {\n" + " return s->x ? 1 : 0;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S { int a[1][1]; };\n" // #14714 + "int f(S* s) {\n" + " return s->a[0][0] ? 1 : 0;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("int f(int *p, int *q) {\n" // #14748 + " return p ? *p : *q;\n" + "}\n" + "void g(int *p, int *q) {\n" + " int& r = p ? *p : *q;\n" + " r = 0;\n" + "}\n" + "void h(int *p, int *q) {\n" + " i(p ? *p : *q);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:1:12]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" + "[test.cpp:1:20]: (style) Parameter 'q' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constArray() { @@ -5562,7 +5786,7 @@ class TestOther : public TestFixture { " \n" " \n" ""; - /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).build(); + /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).severity(Severity::style).build(); check("void foo() {\n" " exit(0);\n" @@ -6370,9 +6594,9 @@ class TestOther : public TestFixture { check("class Foo {\n" " int var;\n" - " void func(int var);\n" + " Foo(int var);\n" "};\n" - "void Foo::func(int var) {\n" + "Foo::Foo(int var) {\n" " this->var = var;\n" "}"); ASSERT_EQUALS("", errout_str()); @@ -6629,7 +6853,7 @@ class TestOther : public TestFixture { " AMethodObject(double, double, double);\n" "};\n" "struct S {\n" - " static void A(double, double, double);\n" + " static void A(double a1, double a2, double a3);\n" "};\n" "void S::A(double const a1, double const a2, double const a3) {\n" " AMethodObject(a1, a2, a3);\n" @@ -7149,6 +7373,15 @@ class TestOther : public TestFixture { " }\n" "}"); ASSERT_EQUALS("", errout_str()); + + check("void f(int i) {\n" + " if (1 == i) {\n" + " ;\n" + " } else {\n" + " ;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void duplicateBranch6() { @@ -7456,7 +7689,7 @@ class TestOther : public TestFixture { " \n" " \n" ""; - /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).build(); + /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).severity(Severity::style).build(); check("void foo() {\n" " if (x() || x()) {}\n" @@ -7560,7 +7793,7 @@ class TestOther : public TestFixture { "}"); ASSERT_EQUALS( "[test.cpp:2:22]: (style) Same expression on both sides of '&'. [duplicateExpression]\n" - "[test.cpp:2:29]: (style) Same expression on both sides of '&'. [duplicateExpression]\n", // duplicate + "[test.cpp:2:29]: (style) Same expression on both sides of '&'. [duplicateExpression]\n", errout_str()); } @@ -7866,7 +8099,7 @@ class TestOther : public TestFixture { "public:\n" " double getScale() const { return m_range * m_zoom; }\n" " void setZoom(double z) { m_zoom = z; }\n" - " void dostuff(int);\n" + " void dostuff(int x);\n" "private:\n" " double m_zoom;\n" " double m_range;\n" @@ -8031,6 +8264,35 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void duplicateExpression21() { + check("struct S { int i; };\n" // #12795 + "struct T {\n" + " std::map m;\n" + " S* get(const std::string& s) { return m[s]; }\n" + " void modify() { for (const auto& e : m) e.second->i = 0; }\n" + "};\n" + "void f(T& t) {\n" + " const S* p = t.get(\"abc\");\n" + " const int o = p->i;\n" + " t.modify();\n" + " if (p->i == o) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int i; };\n" + " struct T {\n" + " std::vector m;\n" + " void modify() { for (auto e : m) e->i = 0; }\n" + "};\n" + "void f(T& t) {\n" + " const S* p = t.m[0];\n" + " const int o = p->i;\n" + " t.modify();\n" + " if (p->i == o) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void duplicateExpressionLoop() { check("void f() {\n" " int a = 1;\n" @@ -8164,7 +8426,7 @@ class TestOther : public TestFixture { const char code[] = "void foo(bool flag) {\n" " bar( (flag) ? ~0u : ~0ul);\n" "}"; - /*const*/ Settings settings = settings0; + /*const*/ Settings settings = settings1; settings.platform.sizeof_int = 4; settings.platform.int_bit = 32; @@ -8742,8 +9004,7 @@ class TestOther : public TestFixture { " if (i == j) {}\n" "}"); ASSERT_EQUALS( - "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n" - "[test.cpp:3:14] -> [test.cpp:4:14] -> [test.cpp:6:11]: (style) The comparison 'i == j' is always true because 'i' and 'j' represent the same value. [knownConditionTrueFalse]\n", + "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct A { int x; int y; };" @@ -8755,8 +9016,7 @@ class TestOther : public TestFixture { " if (i == a.x) {}\n" "}"); ASSERT_EQUALS( - "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n" - "[test.cpp:3:14] -> [test.cpp:6:11]: (style) The comparison 'i == a.x' is always true because 'i' and 'a.x' represent the same value. [knownConditionTrueFalse]\n", + "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct A { int x; int y; };" @@ -8768,8 +9028,7 @@ class TestOther : public TestFixture { " if (j == a.x) {}\n" "}"); ASSERT_EQUALS( - "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n" - "[test.cpp:4:14] -> [test.cpp:6:11]: (style) The comparison 'j == a.x' is always true because 'j' and 'a.x' represent the same value. [knownConditionTrueFalse]\n", + "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); // Issue #8612 @@ -9178,6 +9437,24 @@ class TestOther : public TestFixture { " for (unsigned p = 0; p < (sizeof(a) / sizeof((a)[0])); ++p) {}\n" "}"); ASSERT_EQUALS("", errout_str()); + + check("void f(const unsigned char u) {\n" + " if (u > 0) {}\n" + " if (u < 0) {}\n" + " if (u >= 0) {}\n" + " if (u <= 0) {}\n" + " if (0 < u) {}\n" + " if (0 > u) {}\n" + " if (0 <= u) {}\n" + " if (0 >= u) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:3:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n" + "[test.cpp:4:11]: (style) Unsigned expression 'u' can't be negative so it is unnecessary to test it. [unsignedPositive]\n" + "[test.cpp:5:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n" + "[test.cpp:7:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n" + "[test.cpp:8:11]: (style) Unsigned expression 'u' can't be negative so it is unnecessary to test it. [unsignedPositive]\n" + "[test.cpp:9:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n", + errout_str()); } void checkSignOfPointer() { @@ -9819,9 +10096,7 @@ class TestOther : public TestFixture { " u.g();\n" " if (c == m->get()) {}\n" "}\n"); - TODO_ASSERT_EQUALS("", - "[test.cpp:16:33] -> [test.cpp:18:11]: (style) The comparison 'c == m->get()' is always true because 'c' and 'm->get()' represent the same value. [knownConditionTrueFalse]\n", - errout_str()); + ASSERT_EQUALS("", errout_str()); check("struct S {\n" // #12925 " const std::string & f() const { return str; }\n" @@ -9848,6 +10123,58 @@ class TestOther : public TestFixture { " if (s.empty()) {}\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:16]: (performance, inconclusive) Use const reference for 's' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", errout_str()); + + check("void f1(const std::string& s) {\n" + " std::string s1 = s;\n" + " (void)s1;\n" + "}\n" + "void f2() {\n" + " const std::string s;\n" + " std::string s1 = s;\n" + " (void)s1;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:17]: (performance, inconclusive) Use const reference for 's1' to avoid unnecessary data copying. [redundantCopyLocalConst]\n" + "[test.cpp:7:17]: (performance, inconclusive) Use const reference for 's1' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", + errout_str()); + + check("struct S {\n" + " std::string m;\n" + " int f(const std::string& s);\n" + "};\n" + "int S::f(const std::string& s) {\n" + " std::string c = s;\n" + " m.clear();\n" + " return c.size();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" + " std::string m;\n" + " int f(std::string s);\n" + "};\n" + "int S::f(std::string s) {\n" + " s += m;\n" + " std::string c = s;\n" + " m.clear();\n" + " return c.size();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7:17]: (performance, inconclusive) Use const reference for 'c' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", + errout_str()); + + check("int f(const char* c) {\n" // #14530 + " std::string s = c;\n" + " return s.rfind('.');\n" + "}\n" + "struct M {\n" + " M(const std::array& a);\n" + " double m[3][3];\n" + " double trace() const;\n" + "};\n" + "double g(const std::array& a) {\n" + " M m = a;\n" + " return m.trace();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void checkNegativeShift() { @@ -10432,7 +10759,7 @@ class TestOther : public TestFixture { // Member variable pointers check("void podMemPtrs() {\n" - " int POD::*memptr;\n" + " const int POD::*memptr;\n" " memptr = &POD::a;\n" " memptr = &POD::b;\n" " if (memptr)\n" @@ -10517,6 +10844,21 @@ class TestOther : public TestFixture { ASSERT_EQUALS( "[test.cpp:2:10]: (style) Variable 'a' can be declared as pointer to const [constVariablePointer]\n", errout_str()); + + check("std::string f() {\n" // #14534 + " std::string s = \"abc\";\n" + " s = \"def\";\n" + " return s;\n" + "}\n" + "const char* g() {\n" + " const char* p = \"abc\";\n" + " p = \"def\";\n" + " return p;\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:2:19] -> [test.cpp:3:7]: (style) Redundant initialization for 's'. The initialized value is overwritten before it is read. [redundantInitialization]\n" + "[test.cpp:7:19] -> [test.cpp:8:7]: (style) Redundant initialization for 'p'. The initialized value is overwritten before it is read. [redundantInitialization]\n", + errout_str()); } void redundantVarAssignment_struct() { @@ -11119,6 +11461,12 @@ class TestOther : public TestFixture { check("void a(char *p, ...);\n" "void b() { a(NULL, 2); }"); ASSERT_EQUALS("", errout_str()); + + checkP("extern const int sentinel;\n" + "void a(int, ...);\n" + "#define b(x, ...) a((x), __VA_ARGS__, &sentinel)\n" + "void c() { b(1, NULL); }"); + ASSERT_EQUALS("", errout_str()); } void checkCastIntToCharAndBack() { // #160 @@ -11444,6 +11792,19 @@ class TestOther : public TestFixture { "void f(S s) {}\n"); ASSERT_EQUALS("", errout_str()); + check("struct T {\n" // #14667 + " U u1, u2;\n" + " union {\n" + " enum { E0, E1 } e;\n" + " U u3;\n" + " T i;\n" + " } x;\n" + "};\n" + "T f(T t) {\n" + " return t;\n" + "}"); + ASSERT_EQUALS("", errout_str()); // don't crash + Settings settingsUnix32 = settingsBuilder().platform(Platform::Type::Unix32).build(); check("struct S {\n" // #13850 " int i0 : 32;\n" @@ -11932,16 +12293,29 @@ class TestOther : public TestFixture { errout_str()); } + void testUnusedLabelPremiumMisra() { // #14467 - enable unusedLabel with --premium=misra-c-20xx flag + Settings s; + check("void f() {\n" + " label:\n" + "}", dinit(CheckOptions, $.settings = &s)); + ASSERT_EQUALS("", errout_str()); + s.premiumArgs = "--premium=misra-c-2012"; // <- activates unusedLabel checking + check("void f() {\n" + " label:\n" + "}", dinit(CheckOptions, $.settings = &s)); + ASSERT_EQUALS("[test.cpp:2:5]: (style) Label 'label' is not used. [unusedLabel]\n", errout_str()); + } + // TODO: only used in a single place #define checkCustomSettings(...) checkCustomSettings_(__FILE__, __LINE__, __VA_ARGS__) template - void checkCustomSettings_(const char* file, int line, const char (&code)[size], const Settings& settings) { + void checkCustomSettings_(const char* file, int line, const char (&code)[size], const Settings& settings, bool cpp = true) { // Tokenize.. - SimpleTokenizer tokenizer(settings, *this); + SimpleTokenizer tokenizer(settings, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckOther check; + runChecks(check, tokenizer, this); } void testEvaluationOrder() { @@ -12010,6 +12384,12 @@ class TestOther : public TestFixture { " i = i++ + 2;\n" "}", settings11); ASSERT_EQUALS("[test.cpp:2:11]: (error) Expression 'i+++2' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); + + // #14431 + checkCustomSettings("int f(void) {\n" + " struct baz baz = {.bar = {.foo = {.foo = 1}}};\n" + "}\n", settings0, false); + ASSERT_EQUALS("", errout_str()); } void testEvaluationOrderSelfAssignment() { @@ -12373,6 +12753,24 @@ class TestOther : public TestFixture { " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:36]: (warning) Access of moved variable 'l'. [accessMoved]\n", errout_str()); + + check("struct S {\n" // #13179 + " operator bool() const { return !m.empty(); }\n" + " std::string m;\n" + "};\n" + "S get();\n" + "void set(S);\n" + "void f() {\n" + " while (S s = get()) {\n" + " set(std::move(s));\n" + " }\n" + "}\n" + "void g() {\n" + " while (S s{ get() }) {\n" + " set(std::move(s));\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void moveCallback() @@ -12473,6 +12871,38 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:5:8]: (warning) Access of moved variable '.'. [accessMoved]\n", errout_str()); } + void moveOutparam() + { + check("void f(std::vector& v) {\n" // #11300 + " std::string l;\n" + " while (std::getline(std::cin, l)) {\n" + " if (!l.empty()) {\n" + " v.emplace_back(std::move(l));\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(std::ifstream& fin, std::set& s) {\n" + " std::string line;\n" + " while (std::getline(fin, line)) {\n" + " s.emplace(std::move(line));\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void moveTryEmplace() + { + check("void f(std::map& m, std::string& s) {\n" // #12773 + " bool b = m.try_emplace(\"a\", std::move(s)).second;\n" + " if (!b) {\n" + " std::cout << s;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void funcArgNamesDifferent() { check("void func1(int a, int b, int c);\n" "void func1(int a, int b, int c) { }\n" @@ -12497,6 +12927,31 @@ class TestOther : public TestFixture { "[test.cpp:9:20] -> [test.cpp:14:22]: (style, inconclusive) Function 'func4' argument 1 names different: declaration 'a' definition 'A'. [funcArgNamesDifferent]\n" "[test.cpp:9:31] -> [test.cpp:14:29]: (style, inconclusive) Function 'func4' argument 2 names different: declaration 'b' definition 'B'. [funcArgNamesDifferent]\n" "[test.cpp:9:42] -> [test.cpp:14:36]: (style, inconclusive) Function 'func4' argument 3 names different: declaration 'c' definition 'C'. [funcArgNamesDifferent]\n", errout_str()); + + check("using F1 = void (*)();\n" // #14633 + "void f(F1 a);\n" + "void f(F1 b) {}\n" + "typedef void (*F2)();\n" + "void g(F2 a);\n" + "void g(F2 b) {}\n" + "void h(void (*a)());\n" + "void h(void (*b)()) {}\n"); + ASSERT_EQUALS( + "[test.cpp:2:11] -> [test.cpp:3:11]: (style, inconclusive) Function 'f' argument 1 names different: declaration 'a' definition 'b'. [funcArgNamesDifferent]\n" + "[test.cpp:5:11] -> [test.cpp:6:11]: (style, inconclusive) Function 'g' argument 1 names different: declaration 'a' definition 'b'. [funcArgNamesDifferent]\n" + "[test.cpp:7:15] -> [test.cpp:8:15]: (style, inconclusive) Function 'h' argument 1 names different: declaration 'a' definition 'b'. [funcArgNamesDifferent]\n", + errout_str()); + + check("void f(int a);\n" // #14632 + "void f(int) {}\n" + "void g(int);\n" + "void g(int b) {}\n" + "void h(int);\n" + "void h(int) {}\n"); + ASSERT_EQUALS( + "[test.cpp:1:12]: (style, inconclusive) Function 'f' argument 1 names different: declaration 'a' definition ''. [funcArgNamesDifferentUnnamed]\n" + "[test.cpp:4:12]: (style, inconclusive) Function 'g' argument 1 names different: declaration '' definition 'b'. [funcArgNamesDifferentUnnamed]\n", + errout_str()); } void funcArgOrderDifferent() { @@ -12522,6 +12977,10 @@ class TestOther : public TestFixture { "[test.cpp:9:20] -> [test.cpp:14:22]: (warning) Function 'func2' argument order different: declaration 'a, b, c' definition 'c, b, a' [funcArgOrderDifferent]\n" "[test.cpp:10:20] -> [test.cpp:15:22]: (warning) Function 'func3' argument order different: declaration 'a, b, c' definition 'c, b, a' [funcArgOrderDifferent]\n" "[test.cpp:11:16] -> [test.cpp:16:22]: (warning) Function 'func4' argument order different: declaration ', b, c' definition 'c, b, a' [funcArgOrderDifferent]\n", errout_str()); + + check("void f(int N, const int a[N], const int b[N]);\n" // #14710 + "void f(int N, const int a[N], const int b[N]) {}\n"); + ASSERT_EQUALS("", errout_str()); } // #7846 - Syntax error when using C++11 braced-initializer in default argument @@ -12596,14 +13055,14 @@ class TestOther : public TestFixture { " int i{};\n" " void f() { int i; }\n" "};\n"); - ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:20]: (style) Local variable 'i' shadows outer variable [shadowVariable]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:20]: (style) Local variable 'i' shadows outer member [shadowMember]\n", errout_str()); check("struct S {\n" " int i{};\n" " std::vector v;\n" " void f() const { for (const int& i : v) {} }\n" "};\n"); - ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:38]: (style) Local variable 'i' shadows outer variable [shadowVariable]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:38]: (style) Local variable 'i' shadows outer member [shadowMember]\n", errout_str()); check("struct S {\n" // #10405 " F* f{};\n" @@ -12613,7 +13072,7 @@ class TestOther : public TestFixture { "void S::f() const {\n" " for (const F& f : fl) {}\n" "};\n"); - ASSERT_EQUALS("[test.cpp:2:8] -> [test.cpp:7:19]: (style) Local variable 'f' shadows outer variable [shadowVariable]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:8] -> [test.cpp:7:19]: (style) Local variable 'f' shadows outer member [shadowMember]\n", errout_str()); check("extern int a;\n" "int a;\n" @@ -12635,6 +13094,30 @@ class TestOther : public TestFixture { " friend int f() { int i = 5; return i; }\n" "};\n"); ASSERT_EQUALS("", errout_str()); + + check("int x;\n" + "void f(int x) {}\n"); + ASSERT_EQUALS("[test.cpp:1:5] -> [test.cpp:2:12]: (style) Argument 'x' shadows outer variable [shadowVariable]\n", errout_str()); + + check("void x() {}\n" + "void f(int x) {}\n"); + ASSERT_EQUALS("[test.cpp:1:6] -> [test.cpp:2:12]: (style) Argument 'x' shadows outer function [shadowFunction]\n", errout_str()); + + check("struct S { int v; void func(int v); };\n" + "void S::func(int v) { this->v = v; }\n"); + ASSERT_EQUALS("[test.cpp:1:16] -> [test.cpp:2:18]: (style) Argument 'v' shadows outer member [shadowMember]\n", errout_str()); + + check("struct S { int v; void func(void); };\n" + "void S::func() { int v = 0; }\n"); + ASSERT_EQUALS("[test.cpp:1:16] -> [test.cpp:2:22]: (style) Local variable 'v' shadows outer member [shadowMember]\n", errout_str()); + + check("struct S { int v; explicit S(int v); };\n" + "S::S(int v) : v(v) {}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int v(); explicit S(int v); };\n" + "S::S(int v) : v(v) {}\n"); + ASSERT_EQUALS("", errout_str()); } void knownArgument() { @@ -13057,6 +13540,13 @@ class TestOther : public TestFixture { " if (j % c) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " int i = 0;\n" + " i %= 1;\n" + " (void)i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:7]: (style) Modulo of one is always equal to zero [moduloofone]\n", errout_str()); } void sameExpressionPointers() { @@ -13198,14 +13688,14 @@ class TestOther : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); - check("struct A { bool x; };\n" + check("struct A { bool x; };\n" // #14481 "bool f(A* a) {\n" " if (a) {\n" " return a->x;\n" " }\n" " return false;\n" "}\n"); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'a' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("struct A { int* x; };\n" "bool f(A a) {\n" diff --git a/test/testpath.cpp b/test/testpath.cpp index 7c181e28afb..69ee91fa391 100644 --- a/test/testpath.cpp +++ b/test/testpath.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,6 +57,7 @@ class TestPath : public TestFixture { TEST_CASE(getAbsolutePath); TEST_CASE(exists); TEST_CASE(fromNativeSeparators); + TEST_CASE(isRelative); } void removeQuotationMarks() const { @@ -202,6 +203,8 @@ class TestPath : public TestFixture { //ASSERT_EQUALS("", Path::join("S:/a", "S:/b")); //ASSERT_EQUALS("", Path::join("S:/a", "S:\\b")); //ASSERT_EQUALS("", Path::join("S:/a", "/b")); + + ASSERT_EQUALS("a/b/c", Path::join("a", "b", "c")); } void isDirectory() const { @@ -315,7 +318,7 @@ class TestPath : public TestFixture { ASSERT_EQUALS(Standards::Language::CPP, Path::identify("/mnt/c/foo/index.cpp", false)); ASSERT_EQUALS(Standards::Language::CPP, Path::identify("/mnt/c/foo/index.Cpp", false)); - // TODO: check for case-insenstive filesystem instead + // TODO: check for case-insensitive filesystem instead // In unix .C is considered C++ #if !defined(_WIN32) && !(defined(__APPLE__) && defined(__MACH__)) ASSERT_EQUALS(Standards::Language::CPP, Path::identify("index.C", false)); @@ -533,7 +536,7 @@ class TestPath : public TestFixture { #ifndef _WIN32 // the underlying realpath() call only returns something if the path actually exists - ASSERT_THROW_EQUALS_2(Path::getAbsoluteFilePath("testabspath2.txt"), std::runtime_error, "path 'testabspath2.txt' does not exist"); + ASSERT_THROW_EQUALS(Path::getAbsoluteFilePath("testabspath2.txt"), std::runtime_error, "path 'testabspath2.txt' does not exist"); #else ASSERT_EQUALS(Path::toNativeSeparators(Path::join(cwd, "testabspath2.txt")), Path::getAbsoluteFilePath("testabspath2.txt")); #endif @@ -572,7 +575,7 @@ class TestPath : public TestFixture { #endif #ifndef _WIN32 - ASSERT_THROW_EQUALS_2(Path::getAbsoluteFilePath("C:\\path\\files.txt"), std::runtime_error, "path 'C:\\path\\files.txt' does not exist"); + ASSERT_THROW_EQUALS(Path::getAbsoluteFilePath("C:\\path\\files.txt"), std::runtime_error, "path 'C:\\path\\files.txt' does not exist"); #endif // TODO: test UNC paths @@ -618,6 +621,33 @@ class TestPath : public TestFixture { ASSERT_EQUALS("//lib/file.c", Path::fromNativeSeparators("\\\\lib\\file.c")); ASSERT_EQUALS("./lib/file.c", Path::fromNativeSeparators(".\\lib\\file.c")); } + + void isRelative() const { + ASSERT_EQUALS(true, Path::isRelative("dir/file")); + ASSERT_EQUALS(true, Path::isRelative("dir\\file")); + + // TODO: is this expected? + ASSERT_EQUALS(true, Path::isRelative("file/")); + ASSERT_EQUALS(true, Path::isRelative("file\\")); + + ASSERT_EQUALS(false, Path::isRelative("file")); + +#ifdef _WIN32 + // this is a relative path on Windows + ASSERT_EQUALS(true, Path::isRelative("/dir/file")); +#else + ASSERT_EQUALS(false, Path::isRelative("/dir/file")); +#endif + +#ifdef _WIN32 + // TODO: this is not detected as absolute path in _WIN32 builds + ASSERT_EQUALS(false, Path::isRelative("c:\\dir\\file")); + ASSERT_EQUALS(false, Path::isRelative("c:/dir/file")); +#else + ASSERT_EQUALS(true, Path::isRelative("c:\\dir\\file")); + ASSERT_EQUALS(true, Path::isRelative("c:/dir/file")); +#endif + } }; REGISTER_TEST(TestPath) diff --git a/test/testpathmatch.cpp b/test/testpathmatch.cpp index 2be6a943845..7e721502a11 100644 --- a/test/testpathmatch.cpp +++ b/test/testpathmatch.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +28,11 @@ class TestPathMatch : public TestFixture { TestPathMatch() : TestFixture("TestPathMatch") {} private: + class PathMatchTest final : public PathMatch + { + friend class TestPathMatch; + }; + static constexpr auto unix = PathMatch::Syntax::unix; static constexpr auto windows = PathMatch::Syntax::windows; static constexpr auto ifreg = PathMatch::Filemode::regular; @@ -277,7 +282,7 @@ class TestPathMatch : public TestFixture { void pathiterator() const { /* See https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats * for information on Windows path syntax. */ - using PathIterator = PathMatch::PathIterator; + using PathIterator = PathMatchTest::PathIterator; ASSERT_EQUALS("/", PathIterator("/", nullptr, unix).read()); ASSERT_EQUALS("/", PathIterator("//", nullptr, unix).read()); ASSERT_EQUALS("/", PathIterator("/", "/", unix).read()); @@ -291,7 +296,7 @@ class TestPathMatch : public TestFixture { ASSERT_EQUALS("", PathIterator(nullptr, "", unix).read()); ASSERT_EQUALS("", PathIterator(nullptr, nullptr, unix).read()); ASSERT_EQUALS("c:", PathIterator("C:", nullptr, windows).read()); - /* C: without slash is a bit ambigous. It should probably not be considered a root because it's + /* C: without slash is a bit ambiguous. It should probably not be considered a root because it's * not fully qualified (it designates the current directory on the C drive), * so this test could be considered to be unspecified behavior. */ ASSERT_EQUALS("c:", PathIterator("C:", "../..", windows).read()); diff --git a/test/testplatform.cpp b/test/testplatform.cpp index 2df02cb43af..ccb7d9b41a8 100644 --- a/test/testplatform.cpp +++ b/test/testplatform.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,11 +37,12 @@ class TestPlatform : public TestFixture { TEST_CASE(valid_config_win32w); TEST_CASE(valid_config_unix32); TEST_CASE(valid_config_win64); + // TODO: test native and unspecified TEST_CASE(valid_config_file_1); TEST_CASE(valid_config_file_2); - TEST_CASE(valid_config_file_3); TEST_CASE(valid_config_file_4); TEST_CASE(invalid_config_file_1); + TEST_CASE(invalid_config_file_2); TEST_CASE(empty_elements); TEST_CASE(default_platform); TEST_CASE(limitsDefines); @@ -210,6 +211,7 @@ class TestPlatform : public TestFixture { // Similar to the avr8 platform file. constexpr char xmldata[] = "\n" "\n" + " false\n" " 8\n" " unsigned\n" " \n" @@ -254,6 +256,7 @@ class TestPlatform : public TestFixture { // char_bit > 8. constexpr char xmldata[] = "\n" "\n" + " true\n" " 20\n" " signed\n" " \n" @@ -273,7 +276,7 @@ class TestPlatform : public TestFixture { PlatformTest platform; ASSERT(readPlatform(platform, xmldata)); ASSERT_EQUALS(Platform::Type::File, platform.type); - ASSERT(!platform.isWindows()); + ASSERT(platform.isWindows()); ASSERT_EQUALS(20, platform.char_bit); ASSERT_EQUALS('s', platform.defaultSign); ASSERT_EQUALS(1, platform.sizeof_bool); @@ -293,11 +296,12 @@ class TestPlatform : public TestFixture { ASSERT_EQUALS(100, platform.long_long_bit); } - void valid_config_file_3() const { - // Valid platform configuration without any usable information. + void invalid_config_file_2() const { + // Invalid platform configuration without any usable information. // Similar like an empty file. constexpr char xmldata[] = "\n" "\n" + " true\n" " 8\n" " unsigned\n" " \n" @@ -324,6 +328,7 @@ class TestPlatform : public TestFixture { // set to 0. constexpr char xmldata[] = "\n" "\n" + " true\n" " 0\n" " z\n" " \n" @@ -343,7 +348,7 @@ class TestPlatform : public TestFixture { PlatformTest platform; ASSERT(readPlatform(platform, xmldata)); ASSERT_EQUALS(Platform::Type::File, platform.type); - ASSERT(!platform.isWindows()); + ASSERT(platform.isWindows()); ASSERT_EQUALS(0, platform.char_bit); ASSERT_EQUALS('z', platform.defaultSign); ASSERT_EQUALS(0, platform.sizeof_bool); @@ -367,6 +372,7 @@ class TestPlatform : public TestFixture { // Invalid XML file: mismatching elements "boolt" vs "bool". constexpr char xmldata[] = "\n" "\n" + " false\n" " 8\n" " unsigned\n" " \n" @@ -392,6 +398,7 @@ class TestPlatform : public TestFixture { // Similar like an empty file. constexpr char xmldata[] = "\n" "\n" + " \n" " \n" " \n" " \n" diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 66b3e24062f..6846d49ff30 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -281,6 +281,7 @@ class TestPreprocessor : public TestFixture { // inline suppression, missingInclude/missingIncludeSystem TEST_CASE(inline_suppressions); + TEST_CASE(inline_suppressions_not_next_line); // remark comment TEST_CASE(remarkComment1); @@ -318,10 +319,15 @@ class TestPreprocessor : public TestFixture { TEST_CASE(getConfigs11); // #9832 - include guards TEST_CASE(getConfigs12); // #14222 TEST_CASE(getConfigs13); // #14222 - TEST_CASE(getConfigs14); // #1059 - TEST_CASE(getConfigs15); // #1059 - TEST_CASE(getConfigs16); // #1059 - TEST_CASE(getConfigs17); // #1059 + TEST_CASE(getConfigs_gte); // #1059 + TEST_CASE(getConfigs_lte); // #1059 + TEST_CASE(getConfigs_gt); // #1059 + TEST_CASE(getConfigs_lt); // #1059 + TEST_CASE(getConfigs_eq_compound); // #1059 + TEST_CASE(getConfigs_gte_compound); // #1059 + TEST_CASE(getConfigs_lte_compound); // #1059 + TEST_CASE(getConfigs_gt_compound); // #1059 + TEST_CASE(getConfigs_lt_compound); // #1059 TEST_CASE(getConfigsError); TEST_CASE(getConfigsD1); @@ -334,6 +340,11 @@ class TestPreprocessor : public TestFixture { TEST_CASE(getConfigsU6); TEST_CASE(getConfigsU7); + TEST_CASE(getConfigsAndCodeIssue14317); + TEST_CASE(getConfigsMostGeneralConfigIssue14317); + + TEST_CASE(getConfigsInvalid); // #14732 + TEST_CASE(if_sizeof); TEST_CASE(invalid_ifs); // #5909 @@ -435,7 +446,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "#error abcd\n" "#endif\n"; - ASSERT_EQUALS("\nA\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A\n", getConfigsStr(filedata)); } void error2() { @@ -495,7 +506,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "#error 2\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\nB\n", getConfigsStr(filedata1)); + ASSERT_EQUALS("\nA=A\nA=A;B=B\nB=B\n", getConfigsStr(filedata1)); const char filedata2[] = "#ifndef A\n" "#error 1\n" @@ -527,7 +538,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "#error \"2\"\n" "#endif\n"; - ASSERT_EQUALS("\nB\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nB=B\n", getConfigsStr(filedata)); } void error8() { @@ -540,7 +551,7 @@ class TestPreprocessor : public TestFixture { "#ifndef C\n" "#error aa\n" "#endif"; - ASSERT_EQUALS("A;B;C\nA;C\nC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("A=A;B=B;C\nA=A;C\nC\n", getConfigsStr(filedata)); } void setPlatformInfo() { @@ -581,7 +592,7 @@ class TestPreprocessor : public TestFixture { "#endfile\n" "#ifdef ABC\n" "#endif"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void includeguard2() { @@ -592,7 +603,7 @@ class TestPreprocessor : public TestFixture { "\n" "#endif\n" "#endfile\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } @@ -611,7 +622,7 @@ class TestPreprocessor : public TestFixture { // Expected configurations: "" and "ABC" ASSERT_EQUALS(2, actual.size()); ASSERT_EQUALS("\n\n\nint main ( ) { }", actual.at("")); - ASSERT_EQUALS("\n#line 1 \"abc.h\"\nclass A { } ;\n#line 4 \"file.c\"\n int main ( ) { }", actual.at("ABC")); + ASSERT_EQUALS("\n#line 1 \"abc.h\"\nclass A { } ;\n#line 4 \"file.c\"\n int main ( ) { }", actual.at("ABC=ABC")); } void if0() { @@ -648,7 +659,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "GHI\n" "#endif\n"; - ASSERT_EQUALS("\nDEF1\nDEF2\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nDEF1=DEF1\nDEF2=DEF2\n", getConfigsStr(filedata)); } } @@ -668,7 +679,7 @@ class TestPreprocessor : public TestFixture { "#if defined(A) && defined(B)\n" "ab\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A\nA=A;B=B\n", getConfigsStr(filedata)); if_cond2b(); if_cond2c(); @@ -685,7 +696,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "a\n" "#endif\n"; - TODO_ASSERT_EQUALS("\nA;B\n", "\nA\nB\n", getConfigsStr(filedata)); + TODO_ASSERT_EQUALS("\nA;B=B\n", "\nA\nB=B\n", getConfigsStr(filedata)); } void if_cond2c() { @@ -699,7 +710,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "a\n" "#endif\n"; - TODO_ASSERT_EQUALS("\nA\nA;B\n", "\nA\nB\n", getConfigsStr(filedata)); + TODO_ASSERT_EQUALS("\nA\nA;B=B\n", "\nA\nB=B\n", getConfigsStr(filedata)); } void if_cond2d() { @@ -718,7 +729,7 @@ class TestPreprocessor : public TestFixture { "!b\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\nB\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA\nA;B=B\nB=B\n", getConfigsStr(filedata)); } void if_cond2e() { @@ -737,7 +748,7 @@ class TestPreprocessor : public TestFixture { "abc\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B;C\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A\nA=A;B=B;C=C\n", getConfigsStr(filedata)); } void if_cond4() { @@ -758,7 +769,7 @@ class TestPreprocessor : public TestFixture { "#endif\n" "}\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA\nA;B=B\n", getConfigsStr(filedata)); } { @@ -793,20 +804,20 @@ class TestPreprocessor : public TestFixture { "#if defined(B) && defined(A)\n" "ef\n" "#endif\n"; - ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A;B=B\n", getConfigsStr(filedata)); } void if_cond6() { const char filedata[] = "\n" "#if defined(A) && defined(B))\n" "#endif\n"; - ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A;B=B\n", getConfigsStr(filedata)); } void if_cond8() { const char filedata[] = "#if defined(A) + defined(B) + defined(C) != 1\n" "#endif\n"; - TODO_ASSERT_EQUALS("\nA\n", "\nA;B;C\n", getConfigsStr(filedata)); + TODO_ASSERT_EQUALS("\nA=A\n", "\nA=A;B=B;C=C\n", getConfigsStr(filedata)); } @@ -865,7 +876,7 @@ class TestPreprocessor : public TestFixture { const char filedata[] = "#if defined(DEF_10) || defined(DEF_11)\n" "a1;\n" "#endif\n"; - ASSERT_EQUALS("\nDEF_10;DEF_11\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nDEF_10=DEF_10;DEF_11=DEF_11\n", getConfigsStr(filedata)); } void if_or_2() { @@ -1529,7 +1540,7 @@ class TestPreprocessor : public TestFixture { ASSERT_EQUALS(2, actual.size()); const std::string expected("void f ( ) {\n\n\n}"); ASSERT_EQUALS(expected, actual.at("")); - ASSERT_EQUALS(expected, actual.at("A")); + ASSERT_EQUALS(expected, actual.at("A=A")); } void handle_error() { @@ -1649,7 +1660,7 @@ class TestPreprocessor : public TestFixture { // Compare results.. ASSERT_EQUALS(2, actual.size()); ASSERT_EQUALS("\n\n\n\n\n$20", actual.at("")); - ASSERT_EQUALS("\n\n\n\n\n$10", actual.at("A")); + ASSERT_EQUALS("\n\n\n\n\n$10", actual.at("A=A")); ASSERT_EQUALS("", errout_str()); } @@ -1701,7 +1712,7 @@ class TestPreprocessor : public TestFixture { // Compare results.. ASSERT_EQUALS(2, actual.size()); ASSERT_EQUALS("", actual.at("")); - ASSERT_EQUALS("\nA\n\n\nA", actual.at("ABC")); + ASSERT_EQUALS("\nA\n\n\nA", actual.at("ABC=ABC")); } void define_if1() { @@ -1942,9 +1953,9 @@ class TestPreprocessor : public TestFixture { // Compare results.. ASSERT_EQUALS(4, actual.size()); ASSERT(actual.find("") != actual.end()); - ASSERT(actual.find("BAR") != actual.end()); - ASSERT(actual.find("FOO") != actual.end()); - ASSERT(actual.find("BAR;FOO") != actual.end()); + ASSERT(actual.find("BAR=BAR") != actual.end()); + ASSERT(actual.find("FOO=FOO") != actual.end()); + ASSERT(actual.find("BAR=BAR;FOO=FOO") != actual.end()); } @@ -1978,9 +1989,9 @@ class TestPreprocessor : public TestFixture { // cases should be fixed whenever this other bug is fixed ASSERT_EQUALS(2U, actual.size()); - ASSERT_EQUALS_MSG(true, (actual.find("A") != actual.end()), "A is expected to be checked but it was not checked"); + ASSERT_EQUALS_MSG(true, (actual.find("A=A") != actual.end()), "A is expected to be checked but it was not checked"); - ASSERT_EQUALS_MSG(true, (actual.find("A;A;B") == actual.end()), "A;A;B is expected to NOT be checked but it was checked"); + ASSERT_EQUALS_MSG(true, (actual.find("A=A;A=A;B=B") == actual.end()), "A;A;B is expected to NOT be checked but it was checked"); } void invalid_define_1() { @@ -2027,6 +2038,38 @@ class TestPreprocessor : public TestFixture { ignore_errout(); // we are not interested in the output } + void inline_suppressions_not_next_line() { + const auto settings = dinit(Settings, + $.inlineSuppressions = true, + $.checks.enable (Checks::missingInclude)); + + const char code[] = "// cppcheck-suppress missingInclude\n" + "// some other comment\n" + "#include \"missing.h\"\n" + "// cppcheck-suppress missingIncludeSystem\n" + "\n" // Empty line + "#include \n"; + SuppressionList inlineSuppr; + (void)getcodeforcfg(settings, *this, code, "", "test.c", &inlineSuppr); + + auto suppressions = inlineSuppr.getSuppressions(); + ASSERT_EQUALS(2, suppressions.size()); + + auto suppr = suppressions.front(); + suppressions.pop_front(); + ASSERT_EQUALS("missingInclude", suppr.errorId); + ASSERT_EQUALS("test.c", suppr.fileName); + ASSERT_EQUALS(3, suppr.lineNumber); + + suppr = suppressions.front(); + suppressions.pop_front(); + ASSERT_EQUALS("missingIncludeSystem", suppr.errorId); + ASSERT_EQUALS("test.c", suppr.fileName); + ASSERT_EQUALS(6, suppr.lineNumber); + + ignore_errout(); + } + void remarkComment1() { const char code[] = "// REMARK: assignment with 1\n" "x=1;\n"; @@ -2146,7 +2189,7 @@ class TestPreprocessor : public TestFixture { " qwerty\n" "#endif \n"; - ASSERT_EQUALS("\nWIN32\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nWIN32=WIN32\n", getConfigsStr(filedata)); } void getConfigs2() { @@ -2167,7 +2210,7 @@ class TestPreprocessor : public TestFixture { "c\n" "#endif\n"; - ASSERT_EQUALS("\nABC\nABC;DEF\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\nABC=ABC;DEF=DEF\n", getConfigsStr(filedata)); } void getConfigs4() { @@ -2177,7 +2220,7 @@ class TestPreprocessor : public TestFixture { "#ifdef ABC\n" "A\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs5() { @@ -2189,7 +2232,7 @@ class TestPreprocessor : public TestFixture { "C\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\nDEF\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\nDEF=DEF\n", getConfigsStr(filedata)); } void getConfigs7() { @@ -2199,7 +2242,7 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7a() { @@ -2219,7 +2262,7 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7c() { @@ -2229,7 +2272,7 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7d() { @@ -2239,7 +2282,7 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7e() { @@ -2252,7 +2295,7 @@ class TestPreprocessor : public TestFixture { "#endif\n" "#endfile\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs8() { @@ -2295,32 +2338,259 @@ class TestPreprocessor : public TestFixture { ASSERT_EQUALS("\n", getConfigsStr(filedata, nullptr, "gnu.cfg")); } - void getConfigs14() { // #1059 - const char filedata[] = "#if A >= 1\n" - "1\n" - "#endif\n"; - ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata)); + void getConfigs_gte() { // #1059 + { + const char filedata[] = "#if A >= 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A >= 201112L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A >= 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483647\n", getConfigsStr(filedata)); + } } - void getConfigs15() { // #1059 - const char filedata[] = "#if A <= 1\n" - "1\n" - "#endif\n"; - ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata)); + void getConfigs_lte() { // #1059 + { + const char filedata[] = "#if A <= 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A <= 201112L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A <= 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483647\n", getConfigsStr(filedata)); + } } - void getConfigs16() { // #1059 - const char filedata[] = "#if A > 1\n" - "1\n" - "#endif\n"; - ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + void getConfigs_gt() { // #1059 + { + const char filedata[] = "#if A > 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1U\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1UL\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1Z\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 0x1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 01\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 0b1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1t\n" + "1\n" + "#endif\n"; + ASSERT_THROW_INTERNAL_EQUALS(getConfigsStr(filedata), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1t"); + } + { + const char filedata[] = "#if A > 1.0\n" + "1\n" + "#endif\n"; + TODO_ASSERT_THROW(getConfigsStr(filedata), InternalError); // floating point literals are not allowed + } + { + const char filedata[] = "#if A > 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483648\n", getConfigsStr(filedata)); + } } - void getConfigs17() { // #1059 - const char filedata[] = "#if A < 1\n" - "1\n" - "#endif\n"; - ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + void getConfigs_lt() { // #1059 + { + const char filedata[] = "#if A < 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1U\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1UL\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1Z\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 0x1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 01\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 0b1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1t\n" + "1\n" + "#endif\n"; + ASSERT_THROW_INTERNAL_EQUALS(getConfigsStr(filedata), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1t"); + } + { + const char filedata[] = "#if A < 1.0\n" + "1\n" + "#endif\n"; + TODO_ASSERT_THROW(getConfigsStr(filedata), InternalError); // floating point literals are not allowed + } + { + const char filedata[] = "#if A < 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483646\n", getConfigsStr(filedata)); + } + } + + void getConfigs_eq_compound() { // #1059 + { + const char filedata[] = "#if A == 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A == 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_gte_compound() { // #1059 + { + const char filedata[] = "#if A >= 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A >= 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_lte_compound() { // #1059 + { + const char filedata[] = "#if A <= 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A <= 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_gt_compound() { // #1059 + { + const char filedata[] = "#if A > 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201113;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_lt_compound() { // #1059 + { + const char filedata[] = "#if A < 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201111;B=B\n", getConfigsStr(filedata)); + } } void getConfigsError() { @@ -2334,7 +2604,7 @@ class TestPreprocessor : public TestFixture { "#error \"!Y\"\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nX;Y\nY\n", getConfigsStr(filedata2)); + ASSERT_EQUALS("\nX=X;Y\nY\n", getConfigsStr(filedata2)); } void getConfigsD1() { @@ -2344,14 +2614,14 @@ class TestPreprocessor : public TestFixture { "#endif\n" "#endif\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata, "-DX")); - ASSERT_EQUALS("\nX\nY\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nX=X\nY=Y\n", getConfigsStr(filedata)); } void getConfigsU1() { const char filedata[] = "#ifdef X\n" "#endif\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata, "-UX")); - ASSERT_EQUALS("\nX\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nX=X\n", getConfigsStr(filedata)); } void getConfigsU2() { @@ -2375,8 +2645,8 @@ class TestPreprocessor : public TestFixture { const char filedata[] = "#if defined(X) || defined(Y) || defined(Z)\n" "#else\n" "#endif\n"; - ASSERT_EQUALS("\nY;Z\n", getConfigsStr(filedata, "-UX")); - ASSERT_EQUALS("\nX;Y;Z\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nY=Y;Z=Z\n", getConfigsStr(filedata, "-UX")); + ASSERT_EQUALS("\nX=X;Y=Y;Z=Z\n", getConfigsStr(filedata)); } void getConfigsU5() { @@ -2400,6 +2670,80 @@ class TestPreprocessor : public TestFixture { ASSERT_EQUALS("\nY\n", getConfigsStr(code, "-DX")); } + void getConfigsAndCodeIssue14317() { + const char filedata[] = "bool test() {\n" + "return\n" + "#if defined(isless)\n" + "0 != isless(1.0, 2.0)\n" + "#else\n" + "0\n" + "#endif\n" + ";\n" + "}\n"; + // Test getConfigsStr() + ASSERT_EQUALS("\nisless=isless\n", getConfigsStr(filedata)); + + // Test getcode() + // Preprocess => actual result.. + const std::map actual = getcode(settings0, *this, filedata); + + // Expected configurations: "" and "ABC" + ASSERT_EQUALS(2, actual.size()); + ASSERT_EQUALS("bool test ( ) {\nreturn\n\n\n\n0\n\n;\n}", actual.at("")); + ASSERT_EQUALS("bool test ( ) {\nreturn\n\n0 != $isless ( 1.0 , 2.0 )\n\n\n\n;\n}", actual.at("isless=isless")); + } + + void getConfigsMostGeneralConfigIssue14317() { + // Verifies that the most general X (out of X=X and X) and Y=Y is returned + // For Z: First Z=Z is added to ret, then the ifndef else branch replaces Z=Z with the more general Z + const char filedata[] = "#ifdef X\n" + "print(X);\n" + "#endif\n" + "#if X\n" + "print(X+1);\n" + "#endif\n" + "#if defined(Y)\n" + "print(Y);\n" + "#endif\n" + "#ifdef Z\n" + "print(Z);\n" + "#endif\n" + "#ifndef Z\n" + "print(Z+1);\n" + "#else\n" + "print(Z+2);\n" + "#endif\n"; + // Test getConfigsStr() + ASSERT_EQUALS("\nX\nY=Y\nZ\n", getConfigsStr(filedata)); + } + + void getConfigsInvalid() { // #14732 + { + const char filedata[] = "#if<"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if>"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if=="; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if<="; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if>="; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if!"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + } + void if_sizeof() { // #4071 const char code[] = "#if sizeof(unsigned short) == 2\n" "Fred & Wilma\n" @@ -2563,7 +2907,7 @@ class TestPreprocessor : public TestFixture { const char code[] = "#include "; (void)getcodeforcfg(settings, *this, code, "", "test.c"); - ASSERT_EQUALS("test.c:1:2: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } // test for missing system include @@ -2578,7 +2922,7 @@ class TestPreprocessor : public TestFixture { const char code[] = "#include "; (void)getcodeforcfg(settings, *this, code, "", "test.c"); - ASSERT_EQUALS("test.c:1:2: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } // test for existing system include in system include path @@ -2631,7 +2975,7 @@ class TestPreprocessor : public TestFixture { std::string code("#include <" + header + ">"); (void)getcodeforcfg(settings, *this, code.data(), code.size(), "", "test.c"); - ASSERT_EQUALS("test.c:1:2: information: Include file: <" + header + "> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: <" + header + "> not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } // test for missing local and system include @@ -2654,8 +2998,8 @@ class TestPreprocessor : public TestFixture { (void)getcodeforcfg(settings, *this, code, "", "test.c"); ASSERT_EQUALS("test.c:1:2: information: Include file: \"missing.h\" not found. [missingInclude]\n" - "test.c:2:2: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n" - "test.c:3:2: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + "test.c:2:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n" + "test.c:3:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } void testMissingIncludeCheckConfig() { @@ -2691,11 +3035,11 @@ class TestPreprocessor : public TestFixture { (void)getcodeforcfg(settings, *this, code.data(), code.size(), "", "test.c"); ASSERT_EQUALS("test.c:1:2: information: Include file: \"missing.h\" not found. [missingInclude]\n" - "test.c:2:2: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n" - "test.c:3:2: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n" + "test.c:2:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n" + "test.c:3:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n" "test.c:6:2: information: Include file: \"header4.h\" not found. [missingInclude]\n" "test.c:9:2: information: Include file: \"" + missing3 + "\" not found. [missingInclude]\n" - "test.c:11:2: information: Include file: <" + missing4 + "> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + "test.c:11:2: information: Include file: <" + missing4 + "> not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } void hasInclude() { @@ -2783,7 +3127,7 @@ class TestPreprocessor : public TestFixture { std::vector files; TokenList tokenlist{settingsDefault, Standards::Language::CPP}; // TODO: can this happen from application code? if yes we need to turn it into a proper error - ASSERT_THROW_EQUALS_2(preprocess(code, files, "test.cpp", tokenlist, dui), std::runtime_error, "unexpected simplecpp::Output type 9"); + ASSERT_THROW_EQUALS(preprocess(code, files, "test.cpp", tokenlist, dui), std::runtime_error, "unexpected simplecpp::Output type 9"); ASSERT(!tokenlist.front()); // nothing is tokenized when an unknown standard is provided } } diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index c430116110e..87b03d915f8 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,7 +51,7 @@ class TestProcessExecutorBase : public TestFixture { private: #ifdef HAS_THREADING_MODEL_FORK - /*const*/ Settings settings = settingsBuilder().library("std.cfg").build(); + /*const*/ Settings settings; bool useFS; std::string fprefix() const @@ -64,7 +64,7 @@ class TestProcessExecutorBase : public TestFixture { struct CheckOptions { bool quiet = true; - ShowTime showtime = ShowTime::NONE; + Settings::ShowTime showtime = Settings::ShowTime::NONE; const char* plistOutput = nullptr; std::vector filesList; }; @@ -104,7 +104,9 @@ class TestProcessExecutorBase : public TestFixture { s.plistOutput = opt.plistOutput; s.templateFormat = "{callstack}: ({severity}) {inconclusive:inconclusive: }{message}"; Suppressions supprs; - TimerResults timerResults; + std::unique_ptr timerResults; + if (s.showtime != Settings::ShowTime::NONE) + timerResults.reset(new TimerResults); // NOLINTNEXTLINE(performance-unnecessary-value-param) auto executeFn = [](std::string,std::vector,std::string,std::string&){ @@ -120,7 +122,7 @@ class TestProcessExecutorBase : public TestFixture { if (useFS) filelist.clear(); - ProcessExecutor executor(filelist, fileSettings, s, supprs, *this, &timerResults, executeFn); + ProcessExecutor executor(filelist, fileSettings, s, supprs, *this, timerResults.get(), executeFn); ASSERT_EQUALS(result, executor.check()); } #endif // HAS_THREADING_MODEL_FORK @@ -138,9 +140,7 @@ class TestProcessExecutorBase : public TestFixture { TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); TEST_CASE(showtime_top5_file); - TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); - TEST_CASE(showtime_summary); TEST_CASE(showtime_file_total); TEST_CASE(suppress_error_library); TEST_CASE(unique_errors); @@ -179,7 +179,7 @@ class TestProcessExecutorBase : public TestFixture { "void f()\n" "{\n" " (void)(*((int*)0));\n" - "}", dinit(CheckOptions, $.showtime = ShowTime::SUMMARY)); + "}", dinit(CheckOptions, $.showtime = Settings::ShowTime::SUMMARY)); // we are not interested in the results - so just consume them ignore_errout(); } @@ -248,25 +248,10 @@ class TestProcessExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::TOP5_FILE)); - // for each file: top5 results + overall + empty line + $.showtime = Settings::ShowTime::TOP5_FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; - // for each file: top5 results + overall + empty line - TODO_ASSERT_EQUALS(static_cast(5 + 1 + 1) * 2, 0, cppcheck::count_all_of(output_s, '\n')); - } - - void showtime_top5_summary() { - REDIRECT; - check(2, 2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = ShowTime::TOP5_SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // once: top5 results + overall + empty line - TODO_ASSERT_EQUALS(5 + 1 + 1, 1, cppcheck::count_all_of(output_s, '\n')); - // should only report the top5 once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - TODO_ASSERT(output_s.find("2 result(s)") != std::string::npos); + // for each file: top5 results + check time + TODO_ASSERT_EQUALS(static_cast(5 + 1) * 2, 0, cppcheck::count_all_of(output_s, '\n')); } void showtime_file() { @@ -274,29 +259,17 @@ class TestProcessExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE)); + $.showtime = Settings::ShowTime::FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; TODO_ASSERT_EQUALS(2, 0, cppcheck::count_all_of(output_s, "Overall time:")); } - void showtime_summary() { - REDIRECT; // should not cause TSAN failures as the showtime logging is synchronized - check(2, 2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = ShowTime::SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // should only report the actual summary once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - TODO_ASSERT(output_s.find("2 result(s)") != std::string::npos); - } - void showtime_file_total() { REDIRECT; // should not cause TSAN failures as the showtime logging is synchronized check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE_TOTAL)); + $.showtime = Settings::ShowTime::FILE_TOTAL)); const std::string output_s = GET_REDIRECT_OUTPUT; TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_1.c: ") != std::string::npos); TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_2.c: ") != std::string::npos); diff --git a/test/testprogrammemory.cpp b/test/testprogrammemory.cpp index a6cf933d843..688efa0075b 100644 --- a/test/testprogrammemory.cpp +++ b/test/testprogrammemory.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -98,8 +98,8 @@ class TestProgramMemory : public TestFixture { void at() const { ProgramMemory pm; - ASSERT_THROW_EQUALS_2(pm.at(123), std::out_of_range, "ProgramMemory::at"); - ASSERT_THROW_EQUALS_2(utils::as_const(pm).at(123), std::out_of_range, "ProgramMemory::at"); + ASSERT_THROW_EQUALS(pm.at(123), std::out_of_range, "ProgramMemory::at"); + ASSERT_THROW_EQUALS(utils::as_const(pm).at(123), std::out_of_range, "ProgramMemory::at"); } }; diff --git a/test/testregex.cpp b/test/testregex.cpp index 628ec3e6f5d..4b6b2781cc8 100644 --- a/test/testregex.cpp +++ b/test/testregex.cpp @@ -26,11 +26,13 @@ #include #include -class TestRegEx : public TestFixture { +class TestRegExBase : public TestFixture { public: - TestRegEx() : TestFixture("TestRegEx") {} + TestRegExBase(const char * const name, Regex::Engine engine) : TestFixture(name), mEngine(engine) {} private: + Regex::Engine mEngine; + void run() override { TEST_CASE(match); TEST_CASE(nomatch); @@ -44,7 +46,7 @@ class TestRegEx : public TestFixture { #define assertRegex(...) assertRegex_(__FILE__, __LINE__, __VA_ARGS__) std::shared_ptr assertRegex_(const char* file, int line, std::string pattern, const std::string& exp_err = "") const { std::string regex_err; - auto r = Regex::create(std::move(pattern), regex_err); + auto r = Regex::create(std::move(pattern), mEngine, regex_err); if (exp_err.empty()) ASSERT_LOC(!!r.get(), file, line); else @@ -80,7 +82,11 @@ class TestRegEx : public TestFixture { } void compileError() const { - (void)assertRegex("[", "pcre_compile failed: missing terminating ] for character class"); + std::string exp; + if (mEngine == Regex::Engine::Pcre) + exp = "missing terminating ] for character class"; + + (void)assertRegex("[", exp); } void copy() const { @@ -190,6 +196,11 @@ class TestRegEx : public TestFixture { #undef assertRegex }; -REGISTER_TEST(TestRegEx) +class TestRegExPcre : public TestRegExBase { +public: + TestRegExPcre() : TestRegExBase("TestRegExPcre", Regex::Engine::Pcre) {} +}; + +REGISTER_TEST(TestRegExPcre) #endif // HAVE_RULES diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj index cd7a039c418..1c5230c5535 100755 --- a/test/testrunner.vcxproj +++ b/test/testrunner.vcxproj @@ -53,6 +53,7 @@ + diff --git a/test/testsarifreport.cpp b/test/testsarifreport.cpp index b4d3056a762..e9fc56d736d 100644 --- a/test/testsarifreport.cpp +++ b/test/testsarifreport.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/test/testsettings.cpp b/test/testsettings.cpp index 7bc6aeb0352..ddd11de3273 100644 --- a/test/testsettings.cpp +++ b/test/testsettings.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 52df0597f92..b28bc503869 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -224,6 +224,8 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(template180); TEST_CASE(template181); TEST_CASE(template182); // #13770 + TEST_CASE(template183); + TEST_CASE(template184); TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_3); @@ -4678,6 +4680,51 @@ class TestSimplifyTemplate : public TestFixture { ASSERT_EQUALS(exp, tok(code)); } + void template183() { // #11498 + const char code[] = "template \n" + "struct S {\n" + " void f();\n" + " using X = decltype(&S::f);\n" + "private:\n" + " X x;\n" + "};\n" + "S s;\n"; + const char exp[] = "struct S ; " + "S s ; " + "struct S { " + "void f ( ) ; " + "private: " + "decltype ( & S :: f ) x ; " + "} ;"; + ASSERT_EQUALS(exp, tok(code)); + } + + void template184() { + const char code[] = "template \n" + "T g(T x) {\n" + " return x;\n" + "}\n" + "template <>\n" + "float g(float x) {\n" + " return x + 1.0f;\n" + "}\n" + "void f(int i) {\n" + " g(i);\n" + " g(1.0f);\n" + "}\n"; + const char exp[] = "float g ( float x ) ; " + "template < typename T > " + "T g ( T x ) { return x ; } " + "float g ( float x ) {" + " return x + 1.0f ; " + "} " + "void f ( int i ) {" + " g ( i ) ;" + " g ( 1.0f ) ; " + "}"; + ASSERT_EQUALS(exp, tok(code)); // TODO: instantiate g(int) + } + void template_specialization_1() { // #7868 - template specialization template struct S> {..}; const char code[] = "template struct C {};\n" "template struct S {a};\n" @@ -6372,7 +6419,7 @@ class TestSimplifyTemplate : public TestFixture { "class E<1,3> { " "template < int ... I > " "int f ( int n , std :: integer_sequence < int , I ... > ) { " - "return ( ( ( I == n ) ? : 0 ) + ... ) ; " + "return ( ( ( I == n ) ? ( 1 , 3 ) : 0 ) + ... ) ; " // TODO the simplification is not quite correct "} " "} ;"; ASSERT_EQUALS(expected, tok(code)); @@ -6390,6 +6437,18 @@ class TestSimplifyTemplate : public TestFixture { "A a ; " "struct A { } ;"; ASSERT_EQUALS(expected2, tok(code2)); + + const char code3[] = "template \n" // #14477 + " int f() {\n" + " return (0 | ... | (1, 2, 4));\n" + "}\n" + "int main() {\n" + " return f<1, 2, 4>();\n" + "}\n"; + const char expected3[] = "int f<1,2,4> ( ) ; " + "int main ( ) { return f<1,2,4> ( ) ; } " + "int f<1,2,4> ( ) { return ( 0 | ... | ( 1 , 2 , 4 ) ) ; }"; + ASSERT_EQUALS(expected3, tok(code3)); } void template_variable_1() { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index f55b1e83fc7..88d1a4b2725 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -208,7 +208,7 @@ class TestSimplifyTokens : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // result.. - return tokenizer.tokens()->stringifyList(true); + return tokenizer.tokens()->stringifyList(true, false, true, true, true); } @@ -2207,6 +2207,7 @@ class TestSimplifyTokens : public TestFixture { "for ( i = 0 ; ( i < sz ) && ( sz > 3 ) ; ++ i ) { }\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, dinit(TokenizeAndStringifyOptions, $.cpp = false))); + ignore_errout(); } void simplifyKnownVariables49() { // #3691 diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 866ee85a5d7..342cda59dc8 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -230,6 +230,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef157); TEST_CASE(simplifyTypedef158); TEST_CASE(simplifyTypedef159); + TEST_CASE(simplifyTypedef160); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3812,6 +3813,35 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS(exp, tok(code)); } + void simplifyTypedef160() { + const char code[] = "struct S1 {};\n" + "typedef struct S1 S2;\n" + "namespace N {\n" + " struct B {\n" + " explicit B(int& i);\n" + " };\n" + " struct S2 : B {\n" + " explicit S2(int& i) : B(i) {}\n" + " };\n" + "}\n"; + const char exp[] = "struct S1 { } ; " // #12623 + "namespace N { " + "struct B { " + "explicit B ( int & i ) ; } ; " + "struct S2 : B { " + "explicit S2 ( int & i ) : B ( i ) { } " + "} ; " + "}"; + ASSERT_EQUALS(exp, tok(code)); + + const char code2[] = "typedef stuct T* T;\n" // #14669 + "struct T {\n" + " T p;\n" + "};\n"; + const char exp2[] = "struct T { stuct T * p ; } ;"; + ASSERT_EQUALS(exp2, simplifyTypedefC(code2)); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n" @@ -4507,7 +4537,7 @@ class TestSimplifyTypedef : public TestFixture { // Search for the simplified short token and check its original Name, start from front to get the variable in the struct token = Token::findsimplematch(tokenizer.list.front(), "short", tokenizer.list.back()); ASSERT_EQUALS("int16_t", token->originalName()); - // Search for the simplified * token -> function pointer gets "(*" tokens infront of it + // Search for the simplified * token -> function pointer gets "(*" tokens in front of it token = Token::findsimplematch(endOfTypeDef, "*", tokenizer.list.back()); ASSERT_EQUALS("rFunctionPointer_fp", token->originalName()); } @@ -4585,7 +4615,7 @@ class TestSimplifyTypedef : public TestFixture { void typedefInfo1() { const std::string xml = dumpTypedefInfo("typedef int A;\nA x;"); ASSERT_EQUALS(" \n" - " \n" + " \n" " \n", xml); } @@ -4597,7 +4627,7 @@ class TestSimplifyTypedef : public TestFixture { " typedef fp16 ( *pfp16 ) ( void );\n" "}\n"); ASSERT_EQUALS(" \n" - " \n" + " \n" " \n" " \n" " \n" @@ -4609,7 +4639,7 @@ class TestSimplifyTypedef : public TestFixture { " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -4647,7 +4677,7 @@ class TestSimplifyTypedef : public TestFixture { "} coord;\n" "coord c;"); ASSERT_EQUALS(" \n" - " \n" + " \n" " \n", xml); } }; diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 647668a93b2..7359613510f 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include "helpers.h" #include "platform.h" #include "settings.h" +#include "standards.h" #include "token.h" #include "utils.h" @@ -74,6 +75,8 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing35); TEST_CASE(simplifyUsing36); TEST_CASE(simplifyUsing37); + TEST_CASE(simplifyUsing38); + TEST_CASE(simplifyUsing39); TEST_CASE(simplifyUsing8970); TEST_CASE(simplifyUsing8971); @@ -105,12 +108,14 @@ class TestSimplifyUsing : public TestFixture { Platform::Type type = Platform::Type::Native; bool debugwarnings = true; bool preprocess = false; + Standards::cppstd_t cppstd = Standards::CPPLatest; }; #define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__) template std::string tok_(const char* file, int line, const char (&code)[size], const TokOptions& options = make_default_obj()) { - const Settings settings = settingsBuilder(settings0).certainty(Certainty::inconclusive).debugwarnings(options.debugwarnings).platform(options.type).build(); + const Settings settings = settingsBuilder(settings0).certainty(Certainty::inconclusive).debugwarnings(options.debugwarnings) + .platform(options.type).cpp(options.cppstd).build(); if (options.preprocess) { SimpleTokenizer2 tokenizer(settings, *this, code, "test.cpp"); @@ -914,6 +919,26 @@ class TestSimplifyUsing : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void simplifyUsing38() { + const char code[] = "using std::begin;\n" // #14424 + "using std::end;\n" + "Unknown begin;\n" + "int end;\n"; + const char expected[] = "Unknown begin ; int end ;"; + ASSERT_EQUALS(expected, tok(code)); + ASSERT_EQUALS("", errout_str()); + } + + void simplifyUsing39() { + const char code[] = "using std::wstring;\n" // #14578 + "wstring ws;"; + const char expected[] = "std :: wstring ws ;"; + ASSERT_EQUALS(expected, tok(code)); + ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS(expected, tok(code, dinit(TokOptions, $.cppstd = Standards::CPP03))); + ASSERT_EQUALS("", errout_str()); + } + void simplifyUsing8970() { const char code[] = "using V = std::vector;\n" "struct A {\n" diff --git a/test/testsingleexecutor.cpp b/test/testsingleexecutor.cpp index 4e1a258d19b..d3f42868a4d 100644 --- a/test/testsingleexecutor.cpp +++ b/test/testsingleexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ class TestSingleExecutorBase : public TestFixture { TestSingleExecutorBase(const char * const name, bool useFS) : TestFixture(name), useFS(useFS) {} private: - /*const*/ Settings settings = settingsBuilder().library("std.cfg").build(); + /*const*/ Settings settings; bool useFS; std::string fprefix() const @@ -61,7 +61,7 @@ class TestSingleExecutorBase : public TestFixture { struct CheckOptions { bool quiet = true; - ShowTime showtime = ShowTime::NONE; + Settings::ShowTime showtime = Settings::ShowTime::NONE; const char* plistOutput = nullptr; std::vector filesList; }; @@ -97,10 +97,12 @@ class TestSingleExecutorBase : public TestFixture { s.templateFormat = "{callstack}: ({severity}) {inconclusive:inconclusive: }{message}"; // TODO: remove when we only longer rely on toString() in unique message handling? Suppressions supprs; - TimerResults timerResults; + std::unique_ptr timerResults; + if (s.showtime != Settings::ShowTime::NONE) + timerResults.reset(new TimerResults); // NOLINTNEXTLINE(performance-unnecessary-value-param) - CppCheck cppcheck(s, supprs, *this, &timerResults, true, [](std::string,std::vector,std::string,std::string&){ + CppCheck cppcheck(s, supprs, *this, timerResults.get(), true, [](std::string,std::vector,std::string,std::string&){ return EXIT_SUCCESS; }); @@ -113,7 +115,7 @@ class TestSingleExecutorBase : public TestFixture { if (useFS) filelist.clear(); - SingleExecutor executor(cppcheck, filelist, fileSettings, s, supprs, *this, &timerResults); + SingleExecutor executor(cppcheck, filelist, fileSettings, s, supprs, *this, timerResults.get()); ASSERT_EQUALS(result, executor.check()); } @@ -128,9 +130,7 @@ class TestSingleExecutorBase : public TestFixture { TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); TEST_CASE(showtime_top5_file); - TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); - TEST_CASE(showtime_summary); TEST_CASE(showtime_file_total); TEST_CASE(suppress_error_library); TEST_CASE(unique_errors); @@ -167,7 +167,7 @@ class TestSingleExecutorBase : public TestFixture { "void f()\n" "{\n" " (void)(*((int*)0));\n" - "}", dinit(CheckOptions, $.showtime = ShowTime::SUMMARY)); + "}", dinit(CheckOptions, $.showtime = Settings::ShowTime::SUMMARY)); // we are not interested in the results - so just consume them ignore_errout(); } @@ -241,24 +241,10 @@ class TestSingleExecutorBase : public TestFixture { check(2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::TOP5_FILE)); + $.showtime = Settings::ShowTime::TOP5_FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; - // for each file: top5 results + overall + total - ASSERT_EQUALS((5 + 1 + 1) * 2LL, cppcheck::count_all_of(output_s, '\n')); - } - - void showtime_top5_summary() { - REDIRECT; - check(2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = ShowTime::TOP5_SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // once: top5 results + newline - ASSERT_EQUALS(5 + 1, cppcheck::count_all_of(output_s, '\n')); - // should only report the top5 once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - ASSERT(output_s.find("2 result(s)") != std::string::npos); + // for each file: top5 results + check time + ASSERT_EQUALS((5 + 1) * 2LL, cppcheck::count_all_of(output_s, '\n')); } void showtime_file() { @@ -266,29 +252,17 @@ class TestSingleExecutorBase : public TestFixture { check(2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE)); + $.showtime = Settings::ShowTime::FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT_EQUALS(0, cppcheck::count_all_of(output_s, "Overall time:")); } - void showtime_summary() { - REDIRECT; - check(2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = ShowTime::SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // should only report the actual summary once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - ASSERT(output_s.find("2 result(s)") != std::string::npos); - } - void showtime_file_total() { REDIRECT; check(2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE_TOTAL)); + $.showtime = Settings::ShowTime::FILE_TOTAL)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT(output_s.find("Check time: " + fprefix() + "_" + zpad3(1) + ".c: ") != std::string::npos); ASSERT(output_s.find("Check time: " + fprefix() + "_" + zpad3(2) + ".c: ") != std::string::npos); diff --git a/test/testsizeof.cpp b/test/testsizeof.cpp index ad8aa3192af..b25afe8d153 100644 --- a/test/testsizeof.cpp +++ b/test/testsizeof.cpp @@ -54,8 +54,8 @@ class TestSizeof : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check... - runChecks(tokenizer, this); + CheckSizeof check; + runChecks(check, tokenizer, this); } #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) @@ -66,8 +66,8 @@ class TestSizeof : public TestFixture { // Tokenize.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check... - runChecks(tokenizer, this); + CheckSizeof check; + runChecks(check, tokenizer, this); } void sizeofsizeof() { diff --git a/test/teststl.cpp b/test/teststl.cpp index 2c4669dbeca..18549e08f9f 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -199,7 +199,8 @@ class TestStl : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); - runChecks(tokenizer, this); + CheckStl check; + runChecks(check, tokenizer, this); } // TODO: get rid of this @@ -209,7 +210,8 @@ class TestStl : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); - runChecks(tokenizer, this); + CheckStl check; + runChecks(check, tokenizer, this); } #define checkNormal(...) checkNormal_(__FILE__, __LINE__, __VA_ARGS__) @@ -219,8 +221,8 @@ class TestStl : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckStl check; + runChecks(check, tokenizer, this); } void outOfBounds() { @@ -972,6 +974,32 @@ class TestStl : public TestFixture { "bool g() { return f(\" \"); }\n"); ASSERT_EQUALS("[test.cpp:1:44]: error: Out of bounds access in 's[500]', if 's' size is 1 and '500' is 500 [containerOutOfBounds]\n", errout_str()); + + checkNormal("int main() {\n" // #14342 + " const int a[] = { 1, 2, 3 };\n" + " std::span x{ a };\n" + " return x[3];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:13]: error: Out of bounds access in 'x[3]', if 'x' size is 1 and '3' is 3 [containerOutOfBounds]\n", + errout_str()); + + checkNormal("int main() {\n" + " const char a[] = \"abc\";\n" + " std::string_view x{ a };\n" + " return x[5];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:13]: error: Out of bounds access in 'x[5]', if 'x' size is 4 and '5' is 5 [containerOutOfBounds]\n", + errout_str()); + + checkNormal("int f(const std::string& v) {\n" + " return v[2];\n" + "}\n" + "int main() {\n" + " std::string_view x{ \"a\" };\n" + " return f(std::string(x));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:13]: error: Out of bounds access in 'v[2]', if 'v' size is 1 and '2' is 2 [containerOutOfBounds]\n", + errout_str()); } void outOfBoundsSymbolic() @@ -984,6 +1012,12 @@ class TestStl : public TestFixture { ASSERT_EQUALS( "[test.cpp:2:12] -> [test.cpp:4:21]: (warning) Either the condition 'col>textline.size()' is redundant or 'col' can have the value textline.size(). Expression 'textline[col]' causes access out of bounds. [containerOutOfBounds]\n", errout_str()); + + check("void f(const std::vector& v) {\n" // #12742 + " for (unsigned i = 0; i < v.size();)\n" + " (void)v[i++];\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void outOfBoundsIndexExpression() { @@ -4648,6 +4682,52 @@ class TestStl : public TestFixture { " return s->x.c_str();\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("std::string f(const std::string& s) {\n" // #14533 + " auto x = std::string(\"abc\") + s.c_str();\n" + " auto y = s.c_str() + std::string(\"def\");\n" + " return x + y;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:33]: (performance) Concatenating the result of c_str() and a std::string is slow and redundant. [stlcstrConcat]\n" + "[test.cpp:3:24]: (performance) Concatenating the result of c_str() and a std::string is slow and redundant. [stlcstrConcat]\n", + errout_str()); + + check("std::string get();\n" + "std::string f(const std::string& s) {\n" + " return get() + s.c_str();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:18]: (performance) Concatenating the result of c_str() and a std::string is slow and redundant. [stlcstrConcat]\n", + errout_str()); + + check("std::string get();\n" // #14536 + " std::string f(const std::string& s) {\n" + " return s + get().c_str();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:14]: (performance) Concatenating the result of c_str() and a std::string is slow and redundant. [stlcstrConcat]\n", + errout_str()); + + check("std::string get();\n" + "std::string f(std::string & s) {\n" + " s = get().c_str();\n" + " std::string s2{ get().c_str() };\n" + " return s2;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:5]: (performance) Assigning the result of c_str() to a std::string is slow and redundant. [stlcstrAssignment]\n" + "[test.cpp:4:17]: (performance) Constructing a std::string from the result of c_str() is slow and redundant. [stlcstrConstructor]\n", + errout_str()); + + check("void f() {\n" + " std::string s;\n" + " auto a = + s.c_str();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("std::string f(const std::string& a) {\n" // #14600 + " std::string b(a.c_str() + 1 + 2);\n" + " return b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:17]: (performance) Constructing a std::string from the result of c_str() is slow and redundant. [stlcstrConstructor]\n", + errout_str()); } void uselessCalls() { @@ -4755,6 +4835,12 @@ class TestStl : public TestFixture { "[test.cpp:3:5]: (warning) Return value of std::remove_if() ignored. Elements remain in container. [uselessCallsRemove]\n" "[test.cpp:4:5]: (warning) Return value of std::unique() ignored. Elements remain in container. [uselessCallsRemove]\n", errout_str()); + check("void f(std::string& s) {\n" // #14764 + " auto it{ std::remove(s.begin(), s.end(), 'a') };\n" + " s.erase(it, s.end());\n" + "}"); + ASSERT_EQUALS("", errout_str()); + // #4431 - fp check("bool f() {\n" " return x ? true : (y.empty());\n" @@ -5261,6 +5347,13 @@ class TestStl : public TestFixture { " return it;\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:18:5]: (error, inconclusive) Invalid iterator 'it' used. [eraseDereference]\n", errout_str()); + + check("int f(const std::vector& v) {\n" // #11895 + " auto it = v.end();\n" + " std::advance(it, -2);\n" + " return *it;\n" + "}\n", dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS("", errout_str()); } void loopAlgoElementAssign() { diff --git a/test/teststring.cpp b/test/teststring.cpp index 051aa870788..e0e401256e2 100644 --- a/test/teststring.cpp +++ b/test/teststring.cpp @@ -74,8 +74,8 @@ class TestString : public TestFixture { // Tokenize.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check char variable usage.. - runChecks(tokenizer, this); + CheckString check; + runChecks(check, tokenizer, this); } void stringLiteralWrite() { diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index 61bb0f9cc1a..49d46149c90 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include "addoninfo.h" #include "config.h" #include "cppcheck.h" #include "cppcheckexecutor.h" @@ -32,6 +33,7 @@ #include "threadexecutor.h" #include +#include #include #include #include @@ -55,6 +57,8 @@ class TestSuppressions : public TestFixture { void run() override { mNewTemplate = true; + TEST_CASE(parseLine); + TEST_CASE(parseLineInvalid); TEST_CASE(suppressionsBadId1); TEST_CASE(suppressionsDosFormat); // Ticket #1836 TEST_CASE(suppressionsFileNameWithColon); // Ticket #1919 - filename includes colon @@ -120,6 +124,85 @@ class TestSuppressions : public TestFixture { TEST_CASE(suppressionFromErrorMessage); TEST_CASE(suppressionWildcard); + + TEST_CASE(polyspaceParseRange); + TEST_CASE(polyspaceParseIds); + + TEST_CASE(polyspaceMisraC2012); + TEST_CASE(polyspacePremiumMisraC2012); + TEST_CASE(polyspaceMisraC2023); + TEST_CASE(polyspaceMisraCpp2008); + TEST_CASE(polyspaceMisraCpp2023); + TEST_CASE(polyspaceCertC); + TEST_CASE(polyspaceCertCpp); + TEST_CASE(polyspaceAutosar); + TEST_CASE(polyspaceIgnored); + TEST_CASE(polyspaceMultiple1); + TEST_CASE(polyspaceMultiple2); + TEST_CASE(polyspaceMultiple3); + TEST_CASE(polyspaceRange); + TEST_CASE(polyspaceBlock); + TEST_CASE(polyspaceExtraComments); + } + + + void parseLine() const { + ASSERT_EQUALS("bad", SuppressionList::parseLine("bad").toString()); + ASSERT_EQUALS("bad:test.c", SuppressionList::parseLine("bad:test.c").toString()); + ASSERT_EQUALS("bad:test.c:1", SuppressionList::parseLine("bad:test.c:1").toString()); + + // symbol + ASSERT_EQUALS("bad\nsymbol=x", SuppressionList::parseLine("bad\nsymbol=x").toString()); + ASSERT_EQUALS("bad:test.c\nsymbol=x", SuppressionList::parseLine("bad:test.c\nsymbol=x").toString()); + ASSERT_EQUALS("bad:test.c:1\nsymbol=x", SuppressionList::parseLine("bad:test.c:1\nsymbol=x").toString()); + + // empty symbol + ASSERT_EQUALS("bad", SuppressionList::parseLine("bad\nsymbol=").toString()); + ASSERT_EQUALS("bad:test.c", SuppressionList::parseLine("bad:test.c\nsymbol=").toString()); + ASSERT_EQUALS("bad:test.c:1", SuppressionList::parseLine("bad:test.c:1\nsymbol=").toString()); + + // polyspace + ASSERT_EQUALS("bad\npolyspace=1", SuppressionList::parseLine("bad\npolyspace=1").toString()); + ASSERT_EQUALS("bad:test.c\npolyspace=1", SuppressionList::parseLine("bad:test.c\npolyspace=1").toString()); + ASSERT_EQUALS("bad:test.c:1\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\npolyspace=1").toString()); + + // symbol + polyspace + ASSERT_EQUALS("bad\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad\nsymbol=x\npolyspace=1").toString()); + ASSERT_EQUALS("bad:test.c\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c\nsymbol=x\npolyspace=1").toString()); + ASSERT_EQUALS("bad:test.c:1\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\nsymbol=x\npolyspace=1").toString()); + + // polyspace + symbol + ASSERT_EQUALS("bad\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad\npolyspace=1\nsymbol=x").toString()); + ASSERT_EQUALS("bad:test.c\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c\npolyspace=1\nsymbol=x").toString()); + ASSERT_EQUALS("bad:test.c:1\nsymbol=x\npolyspace=1", SuppressionList::parseLine("bad:test.c:1\npolyspace=1\nsymbol=x").toString()); + } + + void parseLineInvalid() const { + // missing filename + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:"), std::runtime_error, "filename is missing"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:\n"), std::runtime_error, "filename is missing"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:\n1.c"), std::runtime_error, "filename is missing"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:#1.c"), std::runtime_error, "filename is missing"); // TODO: looks like a valid filename + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id://1.c"), std::runtime_error, "filename is missing"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id::"), std::runtime_error, "filename is missing"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id::1"), std::runtime_error, "filename is missing"); + + // missing/invalid line + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:#1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); // TODO: looks like a valid filename + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c://1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:zero"), std::runtime_error, "invalid line number (converting 'zero' to integer failed - not an integer (invalid_argument))"); + + // invalid extras + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\n"), std::runtime_error, "unexpected extra ''"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\nsym=x"), std::runtime_error, "unexpected extra 'sym=x'"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\nsymbol:x"), std::runtime_error, "unexpected extra 'symbol:x'"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\npolyspace=0"), std::runtime_error, "unexpected extra 'polyspace=0'"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\npolyspace:1"), std::runtime_error, "unexpected extra 'polyspace:1'"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id\n:"), std::runtime_error, "unexpected extra ':'"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c\n:"), std::runtime_error, "unexpected extra ':'"); } void suppressionsBadId1() const { @@ -434,7 +517,7 @@ class TestSuppressions : public TestFixture { " a++;\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:2:0]: (error) File suppression should be at the top of the file [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:2:5]: (error) File suppression should be at the top of the file [invalidSuppression]\n" "[test.cpp:4:5]: (error) Uninitialized variable: a [uninitvar]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("void f() {\n" @@ -443,7 +526,7 @@ class TestSuppressions : public TestFixture { "}\n" "// cppcheck-suppress-file uninitvar\n", "")); - ASSERT_EQUALS("[test.cpp:5:0]: (error) File suppression should be at the top of the file [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:5:1]: (error) File suppression should be at the top of the file [invalidSuppression]\n" "[test.cpp:3:5]: (error) Uninitialized variable: a [uninitvar]\n", errout_str()); ASSERT_EQUALS(0, (this->*check)("// cppcheck-suppress-file uninitvar\n" @@ -495,7 +578,7 @@ class TestSuppressions : public TestFixture { " b++;\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:1:0]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); // suppress uninitvar for this file only ASSERT_EQUALS(0, (this->*check)("void f() {\n" @@ -511,7 +594,7 @@ class TestSuppressions : public TestFixture { " b++;\n" "}\n", "uninitvar:test.cpp")); - ASSERT_EQUALS("[test.cpp]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:0:0]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); // suppress all for this file only ASSERT_EQUALS(0, (this->*check)("void f() {\n" @@ -527,7 +610,7 @@ class TestSuppressions : public TestFixture { " b++;\n" "}\n", "*:test.cpp")); - ASSERT_EQUALS("[test.cpp]: (information) Unmatched suppression: * [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:0:0]: (information) Unmatched suppression: * [unmatchedSuppression]\n", errout_str()); // suppress uninitvar for this file and line ASSERT_EQUALS(0, (this->*check)("void f() {\n" @@ -673,7 +756,7 @@ class TestSuppressions : public TestFixture { " b++;\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:4:0]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:4:5]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); // suppress block inline checks ASSERT_EQUALS(0, (this->*check)("void f() {\n" @@ -695,7 +778,7 @@ class TestSuppressions : public TestFixture { " b++;\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:2:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:2:5]: (error) Suppress Begin: No matching end [invalidSuppression]\n" "[test.cpp:4:5]: (error) Uninitialized variable: a [uninitvar]\n" "[test.cpp:6:5]: (error) Uninitialized variable: b [uninitvar]\n", errout_str()); @@ -707,7 +790,7 @@ class TestSuppressions : public TestFixture { " // cppcheck-suppress-end uninitvar\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:6:0]: (error) Suppress End: No matching begin [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:6:5]: (error) Suppress End: No matching begin [invalidSuppression]\n" "[test.cpp:3:5]: (error) Uninitialized variable: a [uninitvar]\n" "[test.cpp:5:5]: (error) Uninitialized variable: b [uninitvar]\n", errout_str()); @@ -718,11 +801,11 @@ class TestSuppressions : public TestFixture { "void f() {}\n" "// cppcheck-suppress-end-unknown id4\n", "")); - ASSERT_EQUALS("[test.cpp:1:0]: (error) unknown suppression type 'cppcheck-suppress:' [invalidSuppression]\n" - "[test.cpp:2:0]: (error) unknown suppression type 'cppcheck-suppress-unknown' [invalidSuppression]\n" - "[test.cpp:3:0]: (error) unknown suppression type 'cppcheck-suppress-begin-unknown' [invalidSuppression]\n" - "[test.cpp:6:0]: (error) unknown suppression type 'cppcheck-suppress-end-unknown' [invalidSuppression]\n" - "[test.cpp:4:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (error) unknown suppression type 'cppcheck-suppress:' [invalidSuppression]\n" + "[test.cpp:2:1]: (error) unknown suppression type 'cppcheck-suppress-unknown' [invalidSuppression]\n" + "[test.cpp:3:1]: (error) unknown suppression type 'cppcheck-suppress-begin-unknown' [invalidSuppression]\n" + "[test.cpp:6:1]: (error) unknown suppression type 'cppcheck-suppress-end-unknown' [invalidSuppression]\n" + "[test.cpp:4:1]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress-file\n" "// cppcheck-suppress\n" @@ -735,14 +818,14 @@ class TestSuppressions : public TestFixture { "void f() {}\n" "// cppcheck-suppress-end\n", "")); - ASSERT_EQUALS("[test.cpp:1:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:2:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:3:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:4:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:6:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:7:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:10:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:8:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:2:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:3:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:4:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:6:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:7:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:10:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:8:1]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress:\n" "// cppcheck-suppress-unknown\n" @@ -752,11 +835,11 @@ class TestSuppressions : public TestFixture { "// cppcheck-suppress-end-unknown\n", "")); // TODO: actually these are all invalid types - ASSERT_EQUALS("[test.cpp:1:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:2:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:3:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:4:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:6:0]: (error) suppression without error ID [invalidSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:2:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:3:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:4:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:6:1]: (error) suppression without error ID [invalidSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("void f() {\n" " int a;\n" @@ -856,7 +939,7 @@ class TestSuppressions : public TestFixture { " // cppcheck-suppress-end [uninitvar, syntaxError]\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:2:0]: (information) Unmatched suppression: syntaxError [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:5]: (information) Unmatched suppression: syntaxError [unmatchedSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress-begin [uninitvar, syntaxError]\n" "void f() {\n" @@ -871,7 +954,7 @@ class TestSuppressions : public TestFixture { "}\n" "// cppcheck-suppress-end [uninitvar, syntaxError]\n", "")); - ASSERT_EQUALS("[test.cpp:1:0]: (information) Unmatched suppression: syntaxError [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (information) Unmatched suppression: syntaxError [unmatchedSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress-begin [uninitvar, syntaxError]\n" "void f() {\n" @@ -886,7 +969,7 @@ class TestSuppressions : public TestFixture { "}\n" "// cppcheck-suppress-end [uninitvar, syntaxError]", "")); - ASSERT_EQUALS("[test.cpp:1:0]: (information) Unmatched suppression: syntaxError [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (information) Unmatched suppression: syntaxError [unmatchedSuppression]\n", errout_str()); // test of multiple suppression types ASSERT_EQUALS(0, (this->*check)("// cppcheck-suppress-file uninitvar\n" @@ -936,7 +1019,7 @@ class TestSuppressions : public TestFixture { " a++;\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:4:0]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:4:5]: (information) Unmatched suppression: uninitvar [unmatchedSuppression]\n", errout_str()); // #5746 - exitcode ASSERT_EQUALS(1U, @@ -965,7 +1048,7 @@ class TestSuppressions : public TestFixture { "#define DIV(A,B) A/B\n" "a = DIV(10,1);\n", ""); - ASSERT_EQUALS("[test.cpp:2:0]: (information) Unmatched suppression: abc [unmatchedSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:1]: (information) Unmatched suppression: abc [unmatchedSuppression]\n", errout_str()); } void suppressionsSettingsFiles() { @@ -1791,7 +1874,7 @@ class TestSuppressions : public TestFixture { SuppressionList::Suppression s; s.errorId = "unitvar"; s.symbolName = "sym"; - ASSERT_EQUALS("unitvar:sym", s.toString()); + ASSERT_EQUALS("unitvar\nsymbol=sym", s.toString()); } } @@ -1900,6 +1983,261 @@ class TestSuppressions : public TestFixture { ASSERT(!suppressions.getUnmatchedGlobalSuppressions().empty()); } } + + static std::string polyspaceParseIdsResults(const std::string& comment, std::string::size_type pos) { + std::string ret; + for (const auto& fr: polyspace::Parser::parseFamilyRules(comment,pos)) { + if (!fr.second.empty()) + ret += ',' + fr.first + ':' + fr.second; + } + return ret.empty() ? ret : ret.substr(1); + } + + void polyspaceParseRange() const { + std::string::size_type pos; + + // Happy case + pos = 0; + ASSERT_EQUALS(12, polyspace::Parser::parseRange(" +12 ",pos)); + ASSERT_EQUALS(4U, pos); + + // Invalid range => pos will point at the token + pos = 0; + ASSERT_EQUALS(0, polyspace::Parser::parseRange(" ",pos)); + ASSERT_EQUALS(std::string::npos, pos); + + pos = 0; + ASSERT_EQUALS(0, polyspace::Parser::parseRange(" test ",pos)); + ASSERT_EQUALS(1U, pos); + + pos = 0; + ASSERT_EQUALS(0, polyspace::Parser::parseRange(" +",pos)); + ASSERT_EQUALS(1U, pos); + + pos = 0; + ASSERT_EQUALS(0, polyspace::Parser::parseRange(" +12",pos)); + ASSERT_EQUALS(1U, pos); + + pos = 0; + ASSERT_EQUALS(0, polyspace::Parser::parseRange(" +A ",pos)); + ASSERT_EQUALS(1U, pos); + } + + void polyspaceParseIds() const { + ASSERT_EQUALS("test:12", polyspaceParseIdsResults("abc test:12",3)); + ASSERT_EQUALS("test:12", polyspaceParseIdsResults("abc test:12 [12]",3)); + ASSERT_EQUALS("test:12", polyspaceParseIdsResults("abc test:12 */",3)); + ASSERT_EQUALS("test:1*", polyspaceParseIdsResults("abc test:1* */",3)); + ASSERT_EQUALS("test:*", polyspaceParseIdsResults("// abc test:*",6)); + // -_. + ASSERT_EQUALS("test:1-2.3", polyspaceParseIdsResults("abc test:1-2.3",3)); + ASSERT_EQUALS("t-e_s.t:12", polyspaceParseIdsResults("abc t-e_s.t : 12",3)); + // multiple ids + ASSERT_EQUALS("d:1,d:2", polyspaceParseIdsResults("abc d:1,2",3)); + ASSERT_EQUALS("d:1,d:2,e:3,e:4,f:6", polyspaceParseIdsResults("abc d:1,2 e: 3 , 4 f : 6 ",3)); + } + + struct PolyspaceComment { + std::string text; + int line; + + PolyspaceComment(const std::string &&text, int line) + : text(text) + , line(line) + {} + }; + + struct PolyspaceParseResult { + std::string errorId; + int lineNumber; + std::string extraComment; + SuppressionList::Type type = SuppressionList::Type::unique; + int lineBegin = SuppressionList::Suppression::NO_LINE; + int lineEnd = SuppressionList::Suppression::NO_LINE; + + PolyspaceParseResult(const std::string &&errorId, + int lineNumber, + const std::string &&extraComment = "", + SuppressionList::Type type = SuppressionList::Type::unique, + int lineBegin = SuppressionList::Suppression::NO_LINE, + int lineEnd = SuppressionList::Suppression::NO_LINE) + : errorId(errorId) + , lineNumber(lineNumber) + , extraComment(extraComment) + , type(type) + , lineBegin(lineBegin) + , lineEnd(lineEnd) + {} + }; + + void testPolyspaceSuppression(const std::string& addon, + const std::string& premiumArgs, + const PolyspaceComment& comment, + std::initializer_list results) const + { + SuppressionList list; + Settings settings; + if (!addon.empty()) { + AddonInfo info; + info.name = addon; + settings.addonInfos.push_back(info); + } + settings.premiumArgs = premiumArgs; + polyspace::Parser parser(settings); + + const std::string fileName = "file.c"; + const auto supprs = parser.parse(comment.text, comment.line, fileName); + + ASSERT_EQUALS(results.size(), supprs.size()); + + auto supprIt = supprs.cbegin(); + const auto *resultIt = results.begin(); + + for (; supprIt != supprs.cend(); supprIt++, resultIt++) { + ASSERT(supprIt->isPolyspace); + ASSERT(supprIt->isInline); + ASSERT_EQUALS(fileName, supprIt->fileName); + ASSERT_EQUALS(resultIt->errorId, supprIt->errorId); + ASSERT_EQUALS(resultIt->extraComment, supprIt->extraComment); + ASSERT_EQUALS_ENUM(resultIt->type, supprIt->type); + ASSERT_EQUALS(resultIt->lineNumber, supprIt->lineNumber); + ASSERT_EQUALS(resultIt->lineBegin, supprIt->lineBegin); + ASSERT_EQUALS(resultIt->lineEnd, supprIt->lineEnd); + } + } + + void polyspaceMisraC2012() const { + testPolyspaceSuppression( + "misra", "", + { "/* polyspace MISRA2012 : 2.7 */", 1 }, + { { "misra-c2012-2.7", 1 } } + ); + } + + void polyspacePremiumMisraC2012() const { + testPolyspaceSuppression( + "", "--misra-c-2012", + { "/* polyspace MISRA2012 : 2.7 */", 1 }, + { { "premium-misra-c-2012-2.7", 1 } } + ); + } + + void polyspaceMisraC2023() const { + testPolyspaceSuppression( + "", "--misra-c-2023", + { "// polyspace MISRA-C-2023 : *", 2 }, + { { "premium-misra-c-2023-*", 2 } } + ); + } + + void polyspaceMisraCpp2008() const { + testPolyspaceSuppression( + "", "--misra-cpp-2008", + { "// polyspace MISRA-CPP : 7-1-1", 1 }, + { { "premium-misra-cpp-2008-7-1-1", 1 } } + ); + } + + void polyspaceMisraCpp2023() const { + testPolyspaceSuppression( + "", "--misra-cpp-2023", + { "// polyspace MISRA-CPP-2023 : 4.6.1", 1 }, + { { "premium-misra-cpp-2023-4.6.1", 1 } } + ); + } + + void polyspaceCertC() const { + testPolyspaceSuppression( + "", "--cert-c", + { "// polyspace CERT-C : PRE30", 1 }, + { { "premium-cert-c-PRE30", 1 } } + ); + } + + void polyspaceCertCpp() const { + testPolyspaceSuppression( + "", "--cert-cpp", + { "// polyspace CERT-CPP : CTR51", 1 }, + { { "premium-cert-cpp-CTR51", 1 } } + ); + } + + void polyspaceAutosar() const { + testPolyspaceSuppression( + "", "--autosar", + { "// polyspace AUTOSAR-CPP14 : a2-10-1", 1 }, + { { "premium-autosar-a2-10-1", 1 } } + ); + } + + void polyspaceIgnored() const { + testPolyspaceSuppression( + "", "", + { "// polyspace DEFECT : INT_OVFL AUTOSAR-CPP14 : a2-10-1", 1 }, + {} + ); + } + + void polyspaceMultiple1() const { + testPolyspaceSuppression( + "", "--misra-c-2012", + { "/* polyspace MISRA2012 : 2.7, 9.1 */", 1 }, + { { "premium-misra-c-2012-2.7", 1 }, + { "premium-misra-c-2012-9.1", 1 } } + ); + } + + void polyspaceMultiple2() const { + testPolyspaceSuppression( + "", "--misra-c-2012 --misra-cpp-2008", + { "/* polyspace MISRA2012 : 2.7 MISRA-CPP : 7-1-1 */", 1 }, + { { "premium-misra-c-2012-2.7", 1 }, + { "premium-misra-cpp-2008-7-1-1", 1 } } + ); + } + + void polyspaceMultiple3() const { + testPolyspaceSuppression( + "", "--misra-c-2012 --misra-cpp-2008", + { "/* polyspace MISRA2012 : 2.7 [Justified:Low] \"comment 1\" polyspace MISRA-CPP : 7-1-1 \"comment 2\"*/", 1 }, + { { "premium-misra-c-2012-2.7", 1, "comment 1" }, + { "premium-misra-cpp-2008-7-1-1", 1, "comment 2" }, } + ); + } + + void polyspaceRange() const { + testPolyspaceSuppression( + "", "--misra-c-2012", + { "/* polyspace +3 MISRA2012 : 2.7 */", 1 }, + { { "premium-misra-c-2012-2.7", 1, "", SuppressionList::Type::block, 1, 4 } } + ); + } + + void polyspaceBlock() const { + testPolyspaceSuppression( + "", "--misra-c-2012", + { "/* polyspace-begin MISRA2012 : 2.7 */", 1 }, + { { "premium-misra-c-2012-2.7", 1, "", SuppressionList::Type::blockBegin } } + ); + + testPolyspaceSuppression( + "", "--misra-c-2012", + { "/* polyspace-end MISRA2012 : 2.7 */", 1 }, + { { "premium-misra-c-2012-2.7", 1, "", SuppressionList::Type::blockEnd } } + ); + + } + + void polyspaceExtraComments() const { + testPolyspaceSuppression( + "", "--misra-c-2012 --misra-cpp-2008", + { "/* polyspace MISRA2012 : 2.7 MISRA-CPP : 7-1-1 \"comment 1\" polyspace MISRA2012 : 8.1, 8.3 \"comment 2\" */", 1 }, + { { "premium-misra-c-2012-2.7", 1, "comment 1" }, + { "premium-misra-cpp-2008-7-1-1", 1, "comment 1" }, + { "premium-misra-c-2012-8.1", 1, "comment 2" }, + { "premium-misra-c-2012-8.3", 1, "comment 2" }, } + ); + } }; REGISTER_TEST(TestSuppressions) diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index b33dcdbc30a..e981c8ea546 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -442,6 +441,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(createSymbolDatabaseFindAllScopes8); // #12761 TEST_CASE(createSymbolDatabaseFindAllScopes9); TEST_CASE(createSymbolDatabaseFindAllScopes10); + TEST_CASE(createSymbolDatabaseFindAllScopes11); TEST_CASE(createSymbolDatabaseIncompleteVars); @@ -464,6 +464,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(enum17); TEST_CASE(enum18); TEST_CASE(enum19); + TEST_CASE(enum20); // #14419 TEST_CASE(struct1); @@ -585,6 +586,8 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(valueType2); TEST_CASE(valueType3); TEST_CASE(valueTypeThis); + TEST_CASE(valueTypeChar); + TEST_CASE(valueTypeRValueReference); TEST_CASE(variadic1); // #7453 TEST_CASE(variadic2); // #7649 @@ -629,6 +632,8 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(stdintFunction); TEST_CASE(userDefinedLiteral); + + TEST_CASE(dumpValueNegative); // #14735 - dumping negative impossible value for unsigned expression } void array() { @@ -1871,11 +1876,11 @@ class TestSymbolDatabase : public TestFixture { // TODO: we should provide our own error message #ifdef _MSC_VER - ASSERT_THROW_EQUALS_2(db->getVariableFromVarId(3), std::out_of_range, "invalid vector subscript"); + ASSERT_THROW_EQUALS(db->getVariableFromVarId(3), std::out_of_range, "invalid vector subscript"); #elif !defined(_LIBCPP_VERSION) - ASSERT_THROW_EQUALS_2(db->getVariableFromVarId(3), std::out_of_range, "vector::_M_range_check: __n (which is 3) >= this->size() (which is 3)"); + ASSERT_THROW_EQUALS(db->getVariableFromVarId(3), std::out_of_range, "vector::_M_range_check: __n (which is 3) >= this->size() (which is 3)"); #else - ASSERT_THROW_EQUALS_2(db->getVariableFromVarId(3), std::out_of_range, "vector"); + ASSERT_THROW_EQUALS(db->getVariableFromVarId(3), std::out_of_range, "vector"); #endif } @@ -6109,6 +6114,24 @@ class TestSymbolDatabase : public TestFixture { } } + void createSymbolDatabaseFindAllScopes11() // #13685 + { + GET_SYMBOL_DB("int f() {\n" + " int x;\n" + " if (!({ int *p = &x; *p = 1; 1; }))\n" + " return 0;\n" + " return x;\n" + "}\n"); + ASSERT(db && db->scopeList.size() == 4); + + auto it = db->scopeList.begin(); + std::advance(it, 3); + const Scope& compoundScope = *it; + ASSERT_EQUALS_ENUM(ScopeType::eUnconditional, compoundScope.type); + ASSERT_EQUALS_ENUM(ScopeType::eFunction, compoundScope.nestedIn->type); + ASSERT_EQUALS("f", compoundScope.nestedIn->className); + } + void createSymbolDatabaseIncompleteVars() { { @@ -6860,6 +6883,23 @@ class TestSymbolDatabase : public TestFixture { } } + void enum20() { // #14419 + { + GET_SYMBOL_DB("enum class myclass : uint8_t { A = 0U };\n"); + const Token *A = Token::findsimplematch(tokenizer.tokens(), "A"); + ASSERT(A && A->valueType() && A->valueType()->isEnum()); + ASSERT_EQUALS_ENUM(ValueType::CHAR, A->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::UNSIGNED, A->valueType()->sign); + } + { + GET_SYMBOL_DB("enum myclass : uint8_t { A = 0U };\n"); + const Token *A = Token::findsimplematch(tokenizer.tokens(), "A"); + ASSERT(A && A->valueType() && A->valueType()->isEnum()); + ASSERT_EQUALS_ENUM(ValueType::CHAR, A->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::UNSIGNED, A->valueType()->sign); + } + } + void struct1() { GET_SYMBOL_DB_C("struct deer {\n" " uint16_t a;\n" @@ -7778,20 +7818,12 @@ class TestSymbolDatabase : public TestFixture { f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v7 ) ) ;"); ASSERT(f); ASSERT(f->function()); - if (std::numeric_limits::is_signed) { - ASSERT_EQUALS(10, f->function()->tokenDef->linenr()); - } else { - ASSERT_EQUALS(5, f->function()->tokenDef->linenr()); - } + ASSERT_EQUALS(10, f->function()->tokenDef->linenr()); f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v8 ) ) ;"); ASSERT(f); ASSERT(f->function()); - if (std::numeric_limits::is_signed) { - ASSERT_EQUALS(5, f->function()->tokenDef->linenr()); - } else { - ASSERT_EQUALS(11, f->function()->tokenDef->linenr()); - } + ASSERT_EQUALS(11, f->function()->tokenDef->linenr()); f = Token::findsimplematch(tokenizer.tokens(), "get ( get ( v9 ) ) ;"); ASSERT(f); @@ -9940,6 +9972,18 @@ class TestSymbolDatabase : public TestFixture { ASSERT(tok && tok->valueType()); ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str()); } + { + GET_SYMBOL_DB("struct S { std::vector v[1][1]; };\n" + "void f(S& s) {\n" + " auto it = std::begin(s.v[0][0]);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + const Token* tok = tokenizer.tokens(); + tok = Token::findsimplematch(tok, "auto"); + ASSERT(tok && tok->valueType()); + ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str()); + } { GET_SYMBOL_DB("void f(std::vector::iterator beg, std::vector::iterator end) {\n" " auto it = std::find(beg, end, 0);\n" @@ -10127,6 +10171,17 @@ class TestSymbolDatabase : public TestFixture { ASSERT_EQUALS("const C *", typeOf("class C { void foo() const; }; void C::foo() const { *this = 0; }", "this")); } + void valueTypeChar() { + Settings s = settings2; + s.platform.defaultSign = 's'; + ASSERT_EQUALS("char", typeOf("char c; c = 'x';", "c =", true, &s)); + ASSERT_EQUALS("char", typeOf("char buf[10]; buf[0] = 'x';", "[ 0 ]", true, &s)); + } + + void valueTypeRValueReference() { + TODO_ASSERT_EQUALS("", "bool", typeOf("void f(std::string&& s = {})", "&&")); + } + void variadic1() { // #7453 { GET_SYMBOL_DB("CBase* create(const char *c1, ...);\n" @@ -11391,6 +11446,18 @@ class TestSymbolDatabase : public TestFixture { ASSERT(!x->varId()); ASSERT(!x->variable()); } + + void dumpValueNegative() { // #14735 + GET_SYMBOL_DB("void f(unsigned int x) { a = x; }"); + const Token* x = Token::findsimplematch(tokenizer.tokens(), "x ;"); + ASSERT(x != nullptr); + std::ostringstream out; + x->printValueFlow({"test.cpp"}, true, out); + const std::string dump = out.str(); + const std::string expected = ""; + // dump should contain expected string, otherwise print the dump string + ASSERT_EQUALS(expected, dump.find(expected) == std::string::npos ? dump : expected); + } }; REGISTER_TEST(TestSymbolDatabase) diff --git a/test/testthreadexecutor.cpp b/test/testthreadexecutor.cpp index 27d88e1d699..ddd65c316b2 100644 --- a/test/testthreadexecutor.cpp +++ b/test/testthreadexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,7 +51,7 @@ class TestThreadExecutorBase : public TestFixture { private: #ifdef HAS_THREADING_MODEL_THREAD - /*const*/ Settings settings = settingsBuilder().library("std.cfg").build(); + /*const*/ Settings settings; bool useFS; std::string fprefix() const @@ -64,7 +64,7 @@ class TestThreadExecutorBase : public TestFixture { struct CheckOptions { bool quiet = true; - ShowTime showtime = ShowTime::NONE; + Settings::ShowTime showtime = Settings::ShowTime::NONE; const char* plistOutput = nullptr; std::vector filesList; }; @@ -105,7 +105,9 @@ class TestThreadExecutorBase : public TestFixture { s.templateFormat = "{callstack}: ({severity}) {inconclusive:inconclusive: }{message}"; // TODO: remove when we only longer rely on toString() in unique message handling? Suppressions supprs; - TimerResults timerResults; + std::unique_ptr timerResults; + if (s.showtime != Settings::ShowTime::NONE) + timerResults.reset(new TimerResults); // NOLINTNEXTLINE(performance-unnecessary-value-param) auto executeFn = [](std::string,std::vector,std::string,std::string&){ @@ -121,7 +123,7 @@ class TestThreadExecutorBase : public TestFixture { if (useFS) filelist.clear(); - ThreadExecutor executor(filelist, fileSettings, s, supprs, *this, &timerResults, executeFn); + ThreadExecutor executor(filelist, fileSettings, s, supprs, *this, timerResults.get(), executeFn); ASSERT_EQUALS(result, executor.check()); } #endif // HAS_THREADING_MODEL_THREAD @@ -139,9 +141,7 @@ class TestThreadExecutorBase : public TestFixture { TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); TEST_CASE(showtime_top5_file); - TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); - TEST_CASE(showtime_summary); TEST_CASE(showtime_file_total); TEST_CASE(suppress_error_library); TEST_CASE(unique_errors); @@ -180,7 +180,7 @@ class TestThreadExecutorBase : public TestFixture { "void f()\n" "{\n" " (void)(*((int*)0));\n" - "}", dinit(CheckOptions, $.showtime = ShowTime::SUMMARY)); + "}", dinit(CheckOptions, $.showtime = Settings::ShowTime::SUMMARY)); // we are not interested in the results - so just consume them ignore_errout(); } @@ -249,24 +249,10 @@ class TestThreadExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::TOP5_FILE)); + $.showtime = Settings::ShowTime::TOP5_FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; - // for each file: top5 results + newline + overall - ASSERT_EQUALS((5 + 1 + 1) * 2LL, cppcheck::count_all_of(output_s, '\n')); - } - - void showtime_top5_summary() { - REDIRECT; - check(2, 2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = ShowTime::TOP5_SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // once: top5 results + newline - ASSERT_EQUALS(5 + 1, cppcheck::count_all_of(output_s, '\n')); - // should only report the top5 once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - ASSERT(output_s.find("2 result(s)") != std::string::npos); + // for each file: top5 results + check time + ASSERT_EQUALS((5 + 1) * 2LL, cppcheck::count_all_of(output_s, '\n')); } void showtime_file() { @@ -274,29 +260,17 @@ class TestThreadExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE)); + $.showtime = Settings::ShowTime::FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT_EQUALS(0, cppcheck::count_all_of(output_s, "Overall time:")); } - void showtime_summary() { - REDIRECT; // should not cause TSAN failures as the showtime logging is synchronized - check(2, 2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = ShowTime::SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // should only report the actual summary once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - ASSERT(output_s.find("2 result(s)") != std::string::npos); - } - void showtime_file_total() { REDIRECT; // should not cause TSAN failures as the showtime logging is synchronized check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE_TOTAL)); + $.showtime = Settings::ShowTime::FILE_TOTAL)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT(output_s.find("Check time: " + fprefix() + "_1.c: ") != std::string::npos); ASSERT(output_s.find("Check time: " + fprefix() + "_2.c: ") != std::string::npos); diff --git a/test/testtimer.cpp b/test/testtimer.cpp index 75fead13d2d..4d5c1c2700c 100644 --- a/test/testtimer.cpp +++ b/test/testtimer.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ */ #include "fixture.h" +#include "redirect.h" #include "timer.h" #include @@ -26,17 +27,43 @@ class TestTimer : public TestFixture { TestTimer() : TestFixture("TestTimer") {} private: - void run() override { TEST_CASE(result); } - void result() const { - TimerResultsData t1; - t1.mDuration = std::chrono::milliseconds{1234}; - ASSERT(t1.getSeconds().count() > 1.233 && t1.getSeconds().count() < 1.235); + void result() { + REDIRECT; + + TimerResults t1; + t1.addResults("call1", std::chrono::milliseconds{1230}); + t1.addResults("call2", std::chrono::milliseconds{1234}); + t1.addResults("call1", std::chrono::milliseconds{1235}); + t1.addResults("call1", std::chrono::milliseconds{1239}); + + const auto results = t1.getResults(); + ASSERT_EQUALS(2, results.size()); + + auto it = results.find("call1"); + ASSERT(it != results.cend()); + ASSERT_EQUALS(3, it->second.size()); + ASSERT_EQUALS(1230, it->second[0].count()); + ASSERT_EQUALS(1235, it->second[1].count()); + ASSERT_EQUALS(1239, it->second[2].count()); + + it = results.find("call2"); + ASSERT(it != results.cend()); + ASSERT_EQUALS(1, it->second.size()); + ASSERT_EQUALS(1234, it->second[0].count()); + + t1.showResults(); + ASSERT_EQUALS("call1: 3.704s (avg. 1.23467s / min 1.23s / max 1.239s - 3 result(s))\n" + "call2: 1.234s (avg. 1.234s / min 1.234s / max 1.234s - 1 result(s))\n", GET_REDIRECT_OUTPUT); + + t1.showResults(1); + ASSERT_EQUALS("call1: 3.704s (avg. 1.23467s / min 1.23s / max 1.239s - 3 result(s))\n", GET_REDIRECT_OUTPUT); - // TODO : more tests + t1.showResults(1, false); + ASSERT_EQUALS("call1: 3.704s\n", GET_REDIRECT_OUTPUT); } }; diff --git a/test/testtoken.cpp b/test/testtoken.cpp index 1a94e092ac9..83a514eb963 100644 --- a/test/testtoken.cpp +++ b/test/testtoken.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,11 @@ class TestToken : public TestFixture { TestToken() : TestFixture("TestToken") {} private: + class TokenTest final : public Token + { + friend class TestToken; + }; + const TokenList list{settingsDefault, Standards::Language::C}; std::vector arithmeticalOps; @@ -59,6 +64,7 @@ class TestToken : public TestFixture { TEST_CASE(multiCompare3); // false positive for %or% on code using "|=" TEST_CASE(multiCompare4); TEST_CASE(multiCompare5); + TEST_CASE(multiCompare6); TEST_CASE(charTypes); TEST_CASE(stringTypes); TEST_CASE(getStrLength); @@ -165,15 +171,15 @@ class TestToken : public TestFixture { auto tokensFrontBack = std::make_shared(); Token one(list, std::move(tokensFrontBack)); one.str("one"); - ASSERT_EQUALS(1, Token::multiCompare(&one, "one|two", 0)); + ASSERT_EQUALS(1, TokenTest::multiCompare(&one, "one|two", 0)); } { auto tokensFrontBack = std::make_shared(); Token two(list, std::move(tokensFrontBack)); two.str("two"); - ASSERT_EQUALS(1, Token::multiCompare(&two, "one|two", 0)); - ASSERT_EQUALS(1, Token::multiCompare(&two, "verybig|two|", 0)); + ASSERT_EQUALS(1, TokenTest::multiCompare(&two, "one|two", 0)); + ASSERT_EQUALS(1, TokenTest::multiCompare(&two, "verybig|two|", 0)); } // Test for empty string found @@ -181,45 +187,45 @@ class TestToken : public TestFixture { auto tokensFrontBack = std::make_shared(); Token notfound(list, std::move(tokensFrontBack)); notfound.str("notfound"); - ASSERT_EQUALS(0, Token::multiCompare(¬found, "one|two|", 0)); + ASSERT_EQUALS(0, TokenTest::multiCompare(¬found, "one|two|", 0)); // Test for not found - ASSERT_EQUALS(-1, Token::multiCompare(¬found, "one|two", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(¬found, "one|two", 0)); } { auto tokensFrontBack = std::make_shared(); Token s(list, std::move(tokensFrontBack)); s.str("s"); - ASSERT_EQUALS(-1, Token::multiCompare(&s, "verybig|two", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(&s, "verybig|two", 0)); } { auto tokensFrontBack = std::make_shared(); Token ne(list, std::move(tokensFrontBack)); ne.str("ne"); - ASSERT_EQUALS(-1, Token::multiCompare(&ne, "one|two", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(&ne, "one|two", 0)); } { auto tokensFrontBack = std::make_shared(); Token a(list, std::move(tokensFrontBack)); a.str("a"); - ASSERT_EQUALS(-1, Token::multiCompare(&a, "abc|def", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(&a, "abc|def", 0)); } { auto tokensFrontBack = std::make_shared(); Token abcd(list, std::move(tokensFrontBack)); abcd.str("abcd"); - ASSERT_EQUALS(-1, Token::multiCompare(&abcd, "abc|def", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(&abcd, "abc|def", 0)); } { auto tokensFrontBack = std::make_shared(); Token def(list, std::move(tokensFrontBack)); def.str("default"); - ASSERT_EQUALS(-1, Token::multiCompare(&def, "abc|def", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(&def, "abc|def", 0)); } // %op% @@ -227,15 +233,15 @@ class TestToken : public TestFixture { auto tokensFrontBack = std::make_shared(); Token plus(list, std::move(tokensFrontBack)); plus.str("+"); - ASSERT_EQUALS(1, Token::multiCompare(&plus, "one|%op%", 0)); - ASSERT_EQUALS(1, Token::multiCompare(&plus, "%op%|two", 0)); + ASSERT_EQUALS(1, TokenTest::multiCompare(&plus, "one|%op%", 0)); + ASSERT_EQUALS(1, TokenTest::multiCompare(&plus, "%op%|two", 0)); } { auto tokensFrontBack = std::make_shared(); Token x(list, std::move(tokensFrontBack)); x.str("x"); - ASSERT_EQUALS(-1, Token::multiCompare(&x, "one|%op%", 0)); - ASSERT_EQUALS(-1, Token::multiCompare(&x, "%op%|two", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(&x, "one|%op%", 0)); + ASSERT_EQUALS(-1, TokenTest::multiCompare(&x, "%op%|two", 0)); } } @@ -314,7 +320,18 @@ class TestToken : public TestFixture { auto tokensFrontBack = std::make_shared(); Token tok(list, std::move(tokensFrontBack)); tok.str("||"); - ASSERT_EQUALS(true, Token::multiCompare(&tok, "+|%or%|%oror%", 0) >= 0); + ASSERT_EQUALS(true, TokenTest::multiCompare(&tok, "+|%or%|%oror%", 0) >= 0); + } + + void multiCompare6() const { + { + const SimpleTokenList stl("x %= y;"); + ASSERT_EQUALS(true, Token::Match(stl.front(), "%name% %= %name%")); + } + { + const SimpleTokenList stl("x += y;"); + ASSERT_EQUALS(false, Token::Match(stl.front(), "%name% %= %name%")); + } } void charTypes() const { @@ -705,7 +722,7 @@ class TestToken : public TestFixture { ASSERT(var.tokenize("int a ; int b ;")); // Varid == 0 should throw exception - ASSERT_THROW_INTERNAL_EQUALS((void)Token::Match(var.tokens(), "%type% %varid% ; %type% %name%", 0),INTERNAL,"Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers"); + ASSERT_THROW_INTERNAL_EQUALS((void)Token::Match(var.tokens(), "%type% %varid% ; %type% %name%", 0),INTERNAL,"Internal error. Token::Match called with varid 0."); ASSERT_EQUALS(true, Token::Match(var.tokens(), "%type% %varid% ; %type% %name%", 1)); ASSERT_EQUALS(true, Token::Match(var.tokens(), "%type% %name% ; %type% %varid%", 2)); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index b9978261914..a81130c3114 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,11 +46,17 @@ class TestTokenizer : public TestFixture { TestTokenizer() : TestFixture("TestTokenizer") {} private: - const Settings settings0 = settingsBuilder().library("qt.cfg").build(); - const Settings settings1 = settingsBuilder().library("qt.cfg").library("std.cfg").debugwarnings().build(); + const Settings settings1 = settingsBuilder().library("std.cfg").debugwarnings().build(); const Settings settings2 = settingsBuilder(settings1).cpp(Standards::CPP11).c(Standards::C11).build(); - const Settings settings3 = settingsBuilder(settings0).c(Standards::C89).cpp(Standards::CPP03).build(); + const Settings settings2_win32a = settingsBuilder(settings2).platform(Platform::Type::Win32A).build(); + const Settings settings2_win32w = settingsBuilder(settings2).platform(Platform::Type::Win32W).build(); + const Settings settings2_win64 = settingsBuilder(settings2).platform(Platform::Type::Win64).build(); + const Settings settings2_unix32 = settingsBuilder(settings2).platform(Platform::Type::Unix32).build(); + const Settings settings2_unix64 = settingsBuilder(settings2).platform(Platform::Type::Unix64).build(); + const Settings settings3 = settingsBuilder().c(Standards::C89).cpp(Standards::CPP03).build(); const Settings settings_windows = settingsBuilder().library("windows.cfg").debugwarnings().cpp(Standards::CPP11).build(); + const Settings settings_win32a = settingsBuilder(settings_windows).platform(Platform::Type::Win32A).build(); + const Settings settings_win32w = settingsBuilder(settings_windows).platform(Platform::Type::Win32W).build(); void run() override { mNewTemplate = true; @@ -184,6 +190,8 @@ class TestTokenizer : public TestFixture { TEST_CASE(removeParentheses26); // Ticket #8875 a[0](0) TEST_CASE(removeParentheses27); TEST_CASE(removeParentheses28); // #12164 - don't remove parentheses in '(expr1) ? (expr2) : (expr3);' + TEST_CASE(removeParantheses29); // #13735 + TEST_CASE(removeParentheses30); TEST_CASE(tokenize_double); TEST_CASE(tokenize_strings); @@ -282,6 +290,10 @@ class TestTokenizer : public TestFixture { TEST_CASE(cppMaybeUnusedAfter2); TEST_CASE(cppMaybeUnusedStructuredBinding); + TEST_CASE(attributeAlignasBefore); + TEST_CASE(attributeAlignasAfter); + TEST_CASE(simplifyAlignedStorage); + TEST_CASE(splitTemplateRightAngleBrackets); TEST_CASE(cpp03template1); @@ -423,6 +435,11 @@ class TestTokenizer : public TestFixture { TEST_CASE(astdesignatedinit); TEST_CASE(astrvaluedecl); TEST_CASE(astorkeyword); + TEST_CASE(astenumdecl); + TEST_CASE(astcompound); + TEST_CASE(astfuncdecl); + TEST_CASE(astarrayinit); + TEST_CASE(astbracedinit); TEST_CASE(startOfExecutableScope); @@ -462,6 +479,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(cppKeywordInCSource); TEST_CASE(cppcast); + TEST_CASE(ccast); TEST_CASE(checkHeader1); @@ -527,19 +545,14 @@ class TestTokenizer : public TestFixture { struct TokenizeOptions { bool expand = true; - Platform::Type platform = Platform::Type::Native; bool cpp = true; - Standards::cppstd_t cppstd = Standards::CPP11; - Standards::cstd_t cstd = Standards::C11; }; #define tokenizeAndStringify(...) tokenizeAndStringify_(__FILE__, __LINE__, __VA_ARGS__) template std::string tokenizeAndStringify_(const char* file, int linenr, const char (&code)[size], const TokenizeOptions& opt = make_default_obj{}) { - const Settings settings = settingsBuilder(settings1).cpp(opt.cppstd).c(opt.cstd).platform(opt.platform).build(); - // tokenize.. - SimpleTokenizer tokenizer(settings, *this, opt.cpp); + SimpleTokenizer tokenizer(settings2, *this, opt.cpp); ASSERT_LOC(tokenizer.tokenize(code), file, linenr); if (tokenizer.tokens()) @@ -558,27 +571,13 @@ class TestTokenizer : public TestFixture { } template - std::string tokenizeAndStringify_(const char* file, int line, const char (&code)[size], const Settings &settings, bool cpp = true) { + std::string tokenizeAndStringify_(const char* file, int line, const char (&code)[size], const Settings &settings, bool cpp = true, bool expand = true) { // tokenize.. SimpleTokenizer tokenizer(settings, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); if (!tokenizer.tokens()) return ""; - return tokenizer.tokens()->stringifyList(false, true, false, true, false, nullptr, nullptr); - } - -#define tokenizeAndStringifyWindows(...) tokenizeAndStringifyWindows_(__FILE__, __LINE__, __VA_ARGS__) - template - std::string tokenizeAndStringifyWindows_(const char* file, int linenr, const char (&code)[size], Platform::Type platform = Platform::Type::Native) { - const Settings settings = settingsBuilder(settings_windows).platform(platform).build(); - - // tokenize.. - SimpleTokenizer tokenizer(settings, *this); - ASSERT_LOC(tokenizer.tokenize(code), file, linenr); - - if (tokenizer.tokens()) - return tokenizer.tokens()->stringifyList(false, true, false, true, false, nullptr, nullptr); - return ""; + return tokenizer.tokens()->stringifyList(false, expand, false, true, false, nullptr, nullptr); } #define tokenizeDebugListing(...) tokenizeDebugListing_(__FILE__, __LINE__, __VA_ARGS__) @@ -1738,7 +1737,7 @@ class TestTokenizer : public TestFixture { { const char code[] = "extern \"C\" int foo();"; // tokenize.. - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); // Expected result.. ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); @@ -1747,7 +1746,7 @@ class TestTokenizer : public TestFixture { { const char code[] = "extern \"C\" { int foo(); }"; // tokenize.. - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); // Expected result.. ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); @@ -1756,7 +1755,7 @@ class TestTokenizer : public TestFixture { { const char code[] = "extern \"C++\" int foo();"; // tokenize.. - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); // Expected result.. ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); @@ -1765,7 +1764,7 @@ class TestTokenizer : public TestFixture { { const char code[] = "extern \"C++\" { int foo(); }"; // tokenize.. - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); // Expected result.. ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); @@ -2024,7 +2023,7 @@ class TestTokenizer : public TestFixture { const char code[] = "struct foo {\n" " void operator delete(void *obj, size_t sz);\n" "}\n"; - const std::string actual(tokenizeAndStringify(code, dinit(TokenizeOptions, $.platform = Platform::Type::Win32A))); + const std::string actual(tokenizeAndStringify(code, settings2_win32a)); const char expected[] = "struct foo {\n" "void operatordelete ( void * obj , unsigned long sz ) ;\n" @@ -2178,6 +2177,31 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS(exp, tokenizeAndStringify(code)); } + void removeParantheses29() { // Ticket #13735 + static char code[] = "double foo(void)\n" + "{\n" + "return (modf)(12.3, NULL);\n" + "}"; + static const char exp[] = "double foo ( )\n" + "{\n" + "return modf ( 12.3 , NULL ) ;\n" + "}"; + ASSERT_EQUALS(exp, tokenizeAndStringify(code)); + } + + void removeParentheses30() { + static char code[] = "void f (Node *node) {\n" + " if (node->data && (node->provider)->free)\n" + " (node->provider)->free (node);\n" + "}\n"; + static const char exp[] = "void f ( Node * node ) {\n" + "if ( node . data && ( node . provider ) . free ) {\n" + "node . provider . free ( node ) ; }\n" + "}"; + ASSERT_EQUALS(exp, tokenizeAndStringify(code)); + (void) errout_str(); + } + void tokenize_double() { const char code[] = "void f() {\n" " double a = 4.2;\n" @@ -2535,8 +2559,9 @@ class TestTokenizer : public TestFixture { } void vardecl14() { + const Settings s = settingsBuilder(settings1).cpp(Standards::CPP03).build(); const char code[] = "::std::tr1::shared_ptr pNum1, pNum2;\n"; - ASSERT_EQUALS(":: std :: tr1 :: shared_ptr < int > pNum1 ; :: std :: tr1 :: shared_ptr < int > pNum2 ;", tokenizeAndStringify(code, dinit(TokenizeOptions, $.expand = false, $.cppstd = Standards::CPP03))); + ASSERT_EQUALS(":: std :: tr1 :: shared_ptr < int > pNum1 ; :: std :: tr1 :: shared_ptr < int > pNum2 ;", tokenizeAndStringify(code, s, true, false)); } void vardecl15() { @@ -3166,7 +3191,7 @@ class TestTokenizer : public TestFixture { const char code[] = "class A{\n" " void f() {}\n" "};"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); // A body {} @@ -3189,7 +3214,7 @@ class TestTokenizer : public TestFixture { " char a[10];\n" " char *b ; b = new char[a[0]];\n" "};"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); // a[10] @@ -3211,7 +3236,7 @@ class TestTokenizer : public TestFixture { const char code[] = "void f(){\n" " foo(g());\n" "};"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); // foo( @@ -3229,7 +3254,7 @@ class TestTokenizer : public TestFixture { const char code[] = "bool foo(C a, bar>& f, int b) {\n" " return(af);\n" "}"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); // template< @@ -3255,7 +3280,7 @@ class TestTokenizer : public TestFixture { const char code[] = "void foo() {\n" " return static_cast(a);\n" "}"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3270,7 +3295,7 @@ class TestTokenizer : public TestFixture { const char code[] = "void foo() {\n" " nvwa<(x > y)> ERROR_nnn;\n" "}"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3284,7 +3309,7 @@ class TestTokenizer : public TestFixture { { // #4860 const char code[] = "class A : public B {};"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3298,7 +3323,7 @@ class TestTokenizer : public TestFixture { { // #4860 const char code[] = "Bar>>>::set(1, 2, 3);"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3313,7 +3338,7 @@ class TestTokenizer : public TestFixture { { // #5627 const char code[] = "new Foo[10];"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3327,7 +3352,7 @@ class TestTokenizer : public TestFixture { { // #6242 const char code[] = "func = integral_;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3340,7 +3365,7 @@ class TestTokenizer : public TestFixture { { // if (a < b || c > d) { } const char code[] = "{ if (a < b || c > d); }"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3350,7 +3375,7 @@ class TestTokenizer : public TestFixture { { // bool f = a < b || c > d const char code[] = "bool f = a < b || c > d;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3360,7 +3385,7 @@ class TestTokenizer : public TestFixture { { // template const char code[] = "a < b || c > d;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3370,7 +3395,7 @@ class TestTokenizer : public TestFixture { { // if (a < ... > d) { } const char code[] = "{ if (a < b || c == 3 || d > e); }"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3380,7 +3405,7 @@ class TestTokenizer : public TestFixture { { // template const char code[] = "a d;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); ASSERT_EQUALS(true, tok->linkAt(1) == tok->tokAt(7)); @@ -3389,7 +3414,7 @@ class TestTokenizer : public TestFixture { { // template const char code[] = "a d;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); ASSERT_EQUALS(true, tok->linkAt(1) == tok->tokAt(7)); @@ -3397,7 +3422,7 @@ class TestTokenizer : public TestFixture { { const char code[] = "template < f = b || c > struct S;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); ASSERT_EQUALS(true, tok->linkAt(1) == tok->tokAt(7)); @@ -3406,7 +3431,7 @@ class TestTokenizer : public TestFixture { { const char code[] = "struct A : B {};"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); ASSERT_EQUALS(true, tok->linkAt(4) == tok->tokAt(8)); @@ -3415,7 +3440,7 @@ class TestTokenizer : public TestFixture { { const char code[] = "Data;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); ASSERT_EQUALS(true, tok->linkAt(1) == tok->tokAt(4)); @@ -3425,7 +3450,7 @@ class TestTokenizer : public TestFixture { { // #6601 const char code[] = "template struct FuncType : FuncType { };"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = tokenizer.tokens(); @@ -3443,7 +3468,7 @@ class TestTokenizer : public TestFixture { { // #7158 const char code[] = "enum { value = boost::mpl::at_c };"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok = Token::findsimplematch(tokenizer.tokens(), "<"); ASSERT_EQUALS(true, tok->link() == tok->tokAt(4)); @@ -3455,7 +3480,7 @@ class TestTokenizer : public TestFixture { const char code[] = "template \n" "struct CheckedDivOp< T, U, typename std::enable_if::value || std::is_floating_point::value>::type> {\n" "};\n"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok1 = Token::findsimplematch(tokenizer.tokens(), "struct")->tokAt(2); const Token *tok2 = Token::findsimplematch(tokenizer.tokens(), "{")->previous(); @@ -3466,7 +3491,7 @@ class TestTokenizer : public TestFixture { { // #7975 const char code[] = "template X copy() {};\n"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok1 = Token::findsimplematch(tokenizer.tokens(), "< Y"); const Token *tok2 = Token::findsimplematch(tok1, "> copy"); @@ -3477,7 +3502,7 @@ class TestTokenizer : public TestFixture { { // #8006 const char code[] = "C && a = b;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok1 = tokenizer.tokens()->next(); const Token *tok2 = tok1->tokAt(2); @@ -3488,7 +3513,7 @@ class TestTokenizer : public TestFixture { { // #8115 const char code[] = "void Test(C && c);"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok1 = Token::findsimplematch(tokenizer.tokens(), "<"); const Token *tok2 = tok1->tokAt(2); @@ -3499,7 +3524,7 @@ class TestTokenizer : public TestFixture { // #8654 const char code[] = "template struct A {}; " "template struct foo : A... {};"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *A = Token::findsimplematch(tokenizer.tokens(), "A <"); ASSERT_EQUALS(true, A->linkAt(1) == A->tokAt(3)); @@ -3508,7 +3533,7 @@ class TestTokenizer : public TestFixture { // #8851 const char code[] = "template::type>" "void basic_json() {}"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT_EQUALS(true, Token::simpleMatch(tokenizer.tokens()->linkAt(1), "> void")); } @@ -3516,7 +3541,7 @@ class TestTokenizer : public TestFixture { { // #9094 - template usage or comparison? const char code[] = "a = f(x%x<--a==x>x);"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr == Token::findsimplematch(tokenizer.tokens(), "<")->link()); } @@ -3526,7 +3551,7 @@ class TestTokenizer : public TestFixture { const char code[] = "using std::same_as;\n" "template T>\n" "void f();"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); const Token *tok1 = Token::findsimplematch(tokenizer.tokens(), "template <"); const Token *tok2 = Token ::findsimplematch(tokenizer.tokens(), "same_as <"); @@ -3537,7 +3562,7 @@ class TestTokenizer : public TestFixture { { // #9131 - template usage or comparison? const char code[] = "using std::list; list l;"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "<")->link()); } @@ -3548,7 +3573,7 @@ class TestTokenizer : public TestFixture { "{\n" " for (set::iterator i = sources.begin(); i != sources.end(); ++i) {}\n" "}"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "<")->link()); } @@ -3559,7 +3584,7 @@ class TestTokenizer : public TestFixture { " a<> b;\n" " b.a<>::c();\n" "}\n"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> ::")->link()); } @@ -3570,7 +3595,7 @@ class TestTokenizer : public TestFixture { "template struct c {\n" " void d() { a[0]; }\n" "};\n"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> [")->link()); } @@ -3582,7 +3607,7 @@ class TestTokenizer : public TestFixture { "template using f = c;\n" "template > struct g {};\n" "template using baz = g;\n"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> ;")->link()); } @@ -3596,7 +3621,7 @@ class TestTokenizer : public TestFixture { "template using c = a;\n" "template c e;\n" "auto f = -e<1> == 0;\n"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> ==")->link()); } @@ -3614,7 +3639,7 @@ class TestTokenizer : public TestFixture { "constexpr void b::operator()(c &&) const {\n" " i<3>.f([] {});\n" "}\n"; - SimpleTokenizer tokenizer(settings0, *this); + SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT(tokenizer.tokenize(code)); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> . f (")->link()); } @@ -3622,7 +3647,7 @@ class TestTokenizer : public TestFixture { { // #10491 const char code[] = "template